C/S架構的滲透測試-請求加解密及測試
概述
目標站點是http://www.example.com,官網提供了api使用文件,但是對其測試後沒有發現漏洞,目錄、埠掃描等都未發現可利用的點。後發現官網提供了客戶端下載,遂對其進行一番測試。
資訊收集
先抓了下客戶端的包,使用Fiddler和BurpSuite都抓不到,懷疑走的不是HTTP協議,用WireShark檢視其確實用的是HTTP協議,但是資料包不好重放,這裡最後使用了WSExplorer抓指定程序的包,成功抓取到通訊的資料,抓到的資料如下,綠色的是請求包,紅色的是響應包。
資料包又分為兩部分,一個是請求行和請求頭。
一個是請求正文。
拼接起來即可放到BurpSuite中進行資料包的重放
測試過程
可看到請求包經過了加密再傳輸,返回的響應包也經過了加密。但是加解密總歸是在客戶端進行的,所以可從分析客戶端入手。
使用Exeinfo PE查殼,可得知使用的是.NET框架 C#開發的程式。
可以使用dnspy,針對.NET程式的逆向工程工具,對客戶端的加解密進行分析。開啟後發現類及方法的命名都是無規律的數字字母,程式碼做了混淆。
混淆了的程式碼不利用閱讀分析,可使用De4Dot嘗試反混淆,支援很多種混淆加密工具混淆過的原始碼。
de4dot-x64.exe origin.exe
- 1
即可得到反混淆後的程式 origin-cleaned.exe
將反混淆後的程式拖入dnspy檢視,可看到基本已還原,提高了可讀性。
因為其通訊採用的是HTTP協議,又發現有個類名為HttpHelper,跟進分析,程式碼不多看到一個Post函式,疑似為對資料加密併發起Post請求的方法,如圖。
呼叫了MM.Encrypt()對請求的引數進行加密,跟進方法,發現其中關鍵的加密函式應該就是MM類下的test05函式。
下斷點,驗證程式是否呼叫此函式進行加密並傳輸,我在明文及密文處下了斷點。
F5啟動程式,輸入賬號密碼test123456,登入。
程式在斷點處停了下來,明文中包含我輸入的賬號test123456和md5加密過的密碼。
放行,得到經過加密的內容,可確定就是呼叫了此處的加密函式。
後又證實響應包解密呼叫的是MM類下的test06函式,請求包加密函式test05及響應包解密函式test06都是呼叫Dll中對應的函式。
這裡我使用的是SharpDevelop編譯的,使用Visual Studio總是會報錯…
public static string decryptResponse(string cipher){
byte[] bytes = Encoding.UTF8.GetBytes(cipher);
byte[] array = new byte[bytes.Length + 128];
int count = Program.test06(ref bytes[0], ref array[0]);
string text = Encoding.UTF8.GetString(array, 0, count);
return text;
}
public static string encryptRequest(string plain){
byte[] bytes = Encoding.UTF8.GetBytes(plain);
int num = bytes.Length * 2 + 128;
if(num<32){
num = 64;
}
byte[] array = new byte[num];
int num2 = 0;
num2 = test05(ref bytes[0], ref array[0]);
string result = Encoding.UTF8.GetString(array, 0, num2);
return result;
}
加密
解密
再用Python的Flask框架在本地寫一個代理轉發程式,方便在BurpSuite中進行重放測試。
流程如下:
- 本地傳送明文資料包到代理
- 代理接收到請求包
- 呼叫程式對請求包進行加密
- 將加密後的資料包轉發給伺服器
- 呼叫程式對伺服器返回的內容解密
- 返回給明文資料到本地
from flask import request, Flask
from urllib.parse import quote
import requests
import os
headers = {
'User-Agent': 'Mozilla',
'Content-Type': 'application/x-www-form-urlencoded',
'Accept-Encoding': 'gzip, deflate',
}
app = Flask('example')
@app.route('/example', methods=['POST'])
def proxy():
form = request.form
request_plain = ''
for key in form:
request_plain += '&{}={}'.format(key, form[key])
response_plain = test(request_plain)
return response_plain
def encrypt(filename):
encrypt_cmd = 'crypto.exe -encrypt {}'.format(filename) #要加密的內容 從檔案讀取
result = os.popen(encrypt_cmd) # 執行exe
request_cipher = quote(result.read()) #加密後的內容 經過一次url編碼把 + 號 轉成 %2B 服務端才能識別
return request_cipher
def decrypt(filename):
decrypt_cmd = 'crypto.exe -decrypt {}'.format(filename) #要解密的內容 從檔案讀取
result = os.popen(decrypt_cmd) # 執行exe
response_plain = result.read() # 讀取解密後的內容
return response_plain
def test(request_plain):
url = 'http://example.com/api/'
plain_txt = 'plain.txt'
with open(plain_txt, 'w') as f1:
f1.writelines(request_plain) # 存放明文到plain.txt
request_cipher = encrypt(plain_txt) # 加密明文
response = requests.post(url=url, data=request_cipher, headers=headers) #傳送請求
cipher_txt = 'cipher.txt'
with open(cipher_txt, 'w') as f2:
f2.writelines(response.text) #存放密文到cipher.txt
response_plain = decrypt(cipher_txt) # 解密密文
return response_plain
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9999, debug=True)
這裡每次請求的介面都是一樣的,改變的只是請求體中的引數。在CodeService中有所有介面的明文,全部提取出來。
即可正常的在BurpSuite中進行測試~
最後成功在一個介面中發現SQL注入。
原文轉載至:https://blog.csdn.net/qq_32727277/article/details/102783316