如何测试加密站点
字数 1344 2025-08-24 10:10:13
加密站点渗透测试技术详解:BurpSuite与mitmproxy实战指南
0x1 前言
在渗透测试过程中,经常会遇到返回数据部分或全部加密的情况。本文详细介绍了两种处理加密站点的实用方法:BurpSuite插件和mitmproxy模块。这两种方法都需要使用Python编写脚本,适用于不同场景下的加密数据处理。
0x2 Burpy插件使用详解
2.1 应用场景
在对小程序接口测试时,发现返回的用户个人信息中关键字段(姓名、电话、身份证号等)被加密,需要通过解密数据来验证漏洞危害性。
2.2 安装与配置
- 下载Burpy插件:https://github.com/mr-m0nst3r/Burpy
- 配置BurpSuite:
- 设置Python路径
- 设置脚本路径
- 启动插件
2.3 脚本编写要点
主要需要实现encrypt和decrypt两个函数,对于局部加密的数据需要特别处理:
import json
from Crypto.Cipher import AES
import base64
class Burpy:
def __init__(self):
pass
def encrypt(self, header, body):
header["Cookie"] = "admin=1"
return header, body
def decrypt(self, header, body):
new_data = json.loads(body)
for i in new_data['data']['records']:
i["visitorName"] = str(aesd(i['visitorName']))
i["visitorTelephone"] = str(aesd(i['visitorTelephone']))
i["visitorIdentityNumber"] = str(aesd(i['visitorIdentityNumber']))
i["personName"] = str(aesd(i['personName']))
i["personTelephone"] = str(aesd(i['personTelephone']))
data = json.dumps(new_data, indent=4, ensure_ascii=False)
return header, data
def aesd(s):
BS = AES.block_size
pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
unpad = lambda s: s[0:-s[-1]]
key = b"xxxxxxxxxxxxxxxx"
ciphertext_b64 = s
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext_padded = cipher.decrypt(ciphertext)
plaintext = unpad(plaintext_padded)
return plaintext.decode()
2.4 使用方法
- 右键点击数据包,选择"Decrypt"查看解密数据
- 或开启"Auto Enc/Dec"功能自动处理
0x3 mitmproxy代理方案
3.1 基本响应包解密
以有道翻译为例,处理AES加密的响应数据:
from Crypto.Cipher import AES
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
import base64
class Mimit():
def response(self, flow):
resp = flow.response.get_text()
rep = AES_Decrypt(resp)
flow.response.set_text(rep)
def AES_Decrypt(data):
key = b'\x08\x14\x9d\xa7\x3c\x59\xce\x62\x55\x5b\x01\xe9\x2f\x34\xe8\x38'
iv = b'\xd2\xbb\x1b\xfd\xe8\x3b\x38\xc3\x44\x36\x63\x57\xb7\x9c\xae\x1c'
aes = AES.new(key, AES.MODE_CBC, iv)
rep = aes.decrypt(base64.urlsafe_b64decode(data)).decode('utf-8')
return rep
addons = [Mimit(),]
启动命令:
mitmdump -p 9090 -s ./test.py --ssl-insecure
3.2 请求体和响应体同时加密处理
对于双向加密的站点,需要设置两层代理:
- 下游代理:解密浏览器发送的数据,加密服务器返回的数据
- 上游代理:加密发送给服务器的数据,解密服务器返回的数据
下游代理代码
from mitmproxy import flowfilter, ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES
import base64
from urllib.parse import unquote
class Mimit():
def request(self, flow):
if flow.request.host == "127.0.0.1":
req = flow.request.get_text()
ctx.log.info("请求数据 => " + unquote(req))
if IsJson(req):
flow.request.set_text(req)
else:
data = AesDecrypt(req)
flow.request.set_text(data)
def response(self, flow):
rep = flow.response.get_text()
ctx.log.info("响应数据 => " + flow.response.get_text())
if IsJson(rep):
rep = Encrypt_data(rep, "aa834085ebd67a24")
flow.response.set_text(rep)
else:
flow.response.set_text(rep)
def AesDecrypt(s):
BS = AES.block_size
pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
unpad = lambda s: s[0:-s[-1]]
key = b"aa834085ebd67a24"
ciphertext_b64 = s
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext_padded = cipher.decrypt(ciphertext)
plaintext = unpad(plaintext_padded)
return plaintext.decode()
def Encrypt_data(data, key):
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
pad_pkcs7 = pad(data.encode('utf-8'), AES.block_size, style='pkcs7')
res = aes.encrypt(pad_pkcs7)
msg = str(base64.b64encode(res), encoding="utf-8")
return msg
def IsJson(data):
try:
data = json.loads(data)
return True
except:
return False
addons = [Mimit(),]
上游代理代码
from mitmproxy import flowfilter, ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES
import base64
from urllib.parse import unquote
class Mimit():
def request(self, flow):
if flow.request.host == "127.0.0.1":
req = flow.request.get_text()
ctx.log.info("请求数据 => " + unquote(req))
if IsJson(req):
data = Encrypt_data(req, "aa834085ebd67a24")
flow.request.set_text(data)
else:
flow.request.set_text(req)
def response(self, flow):
resp = flow.response.get_text()
ctx.log.info("返回数据 => " + resp)
if IsJson(resp):
flow.response.set_text(resp)
else:
resp = AesDecrypt(resp)
flow.response.set_text(resp)
def AesDecrypt(s):
BS = AES.block_size
pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
unpad = lambda s: s[0:-s[-1]]
key = b"aa834085ebd67a24"
ciphertext_b64 = s
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext_padded = cipher.decrypt(ciphertext)
plaintext = unpad(plaintext_padded)
return plaintext.decode()
def Encrypt_data(data, key):
aes = AES.new(key.encode("utf-8"), AES.MODE_ECB)
pad_pkcs7 = pad(data.encode('utf-8'), AES.block_size, style='pkcs7')
res = aes.encrypt(pad_pkcs7)
msg = str(base64.b64encode(res), encoding="utf-8")
return msg
def IsJson(data):
try:
data = json.loads(data)
return True
except:
return False
addons = [Mimit(),]
启动命令
下游代理:
mitmdump -p 7070 -s ./downstream.py --mode upstream:https://127.0.0.1:8080 --ssl-insecure
上游代理:
mitmdump -p 9090 -s ./upstream.py --ssl-insecure
0x4 与其他工具结合
4.1 与sqlmap结合
使用单层上游代理即可:
- 将解密好的payload给sqlmap
- sqlmap发送给上游代理
- 上游代理加密后发送给服务器
- 服务器返回数据给上游代理
- 上游代理解密后返回给sqlmap
启动命令:
mitmdump -p 9090 -s ./sqlmap_proxy.py --ssl-insecure
sqlmap命令:
sqlmap -r sql.txt -proxy http://192.168.1.5:9090
4.2 与xray结合
需要设置两层代理:
- 第一层代理:解密浏览器发送的数据
- 第二层代理:加密发送给xray的数据和解密xray返回的数据
第一层代理代码
from mitmproxy import flowfilter, ctx
from mitmproxy.http import HTTPFlow
from Crypto.Util.Padding import pad
import json
from Crypto.Cipher import AES
import base64
from urllib.parse import unquote
class Mimit():
def request(self, flow):
if flow.request.host == "127.0.0.1":
req = flow.request.get_text()
ctx.log.info("请求数据 => " + unquote(req))
if IsJson(req):
flow.request.set_text(req)
else:
data = AesDecrypt(req)
flow.request.set_text(data)
def response(self, flow):
pass
def AesDecrypt(s):
BS = AES.block_size
pad = lambda s: s + (BS - len(s) % BS) * bytes([BS - len(s) % BS])
unpad = lambda s: s[0:-s[-1]]
key = b"aa834085ebd67a24"
ciphertext_b64 = s
cipher = AES.new(key, AES.MODE_ECB)
ciphertext = base64.b64decode(ciphertext_b64)
plaintext_padded = cipher.decrypt(ciphertext)
plaintext = unpad(plaintext_padded)
return plaintext.decode()
def IsJson(data):
try:
data = json.loads(data)
return True
except:
return False
addons = [Mimit(),]
第二层代理代码
与之前的上游代理代码相同
配置与启动
-
启动下游代理:
mitmdump -p 7070 -s ./xray_downstream.py --mode upstream:https://127.0.0.1:8090 --ssl-insecure -
启动上游代理:
mitmdump -p 9090 -s ./xray_upstream.py --ssl-insecure -
配置xray代理,修改config文件
-
启动xray:
xray.exe -ws --listen 127.0.0.1:8090 -
配置浏览器代理端口为7070
0x5 测试环境搭建
前端代码示例
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>用户查询</title>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>
</head>
<body>
<script>
function decryptAES(data, key) {
var key = CryptoJS.enc.Utf8.parse(key);
var decrypt = CryptoJS.AES.decrypt(data, key, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
});
return CryptoJS.enc.Utf8.stringify(decrypt).toString();
};
function sendNumber() {
var num = $('#numberInput').val();
var data = { number: num };
var datas = JSON.stringify(data);
const aesKey = CryptoJS.enc.Utf8.parse("aa834085ebd67a24");
var encrypted = CryptoJS.AES.encrypt(datas, aesKey, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7
}).toString();;
console.log(encrypted);
$.ajax({
url: 'query.php',
type: 'POST',
data: encrypted,
success: function(response) {
var result = decryptAES(response, "aa834085ebd67a24");
document.getElementById("result").innerHTML = result;
},
error: function(xhr, status, error) {
console.log(error);
}
});
}
</script>
<input type="text" id="numberInput">
<button onclick="sendNumber()">发送</button>
<div id="result">结果:</div>
</body>
</html>
后端PHP代码示例
<?php
function aes_encrypt($data, $key) {
$cipher = "aes-128-ecb";
$options = OPENSSL_RAW_DATA;
$key = substr($key, 0, 16);
$result = openssl_encrypt($data, $cipher, $key, $options);
return base64_encode($result);
}
function aes_decrypt($data, $key) {
$cipher = "aes-128-ecb";
$options = OPENSSL_RAW_DATA;
$key = substr($key, 0, 16);
$result = openssl_decrypt(base64_decode($data), $cipher, $key, $options);
return $result;
}
$data = file_get_contents('php://input');
$number = aes_decrypt($data, "aa834085ebd67a24");
$num = json_decode($number, true)['number'];
$con = mysqli_connect("localhost", "root", "123456", "db_name");
if (mysqli_connect_errno()) {
echo "连接失败: " . mysqli_connect_error();
}
$result = mysqli_query($con, "SELECT * FROM v9_admin WHERE userid={$num}");
while($row = mysqli_fetch_array($result)) {
$str = array(
'username' => $row['username'],
'password' => $row['password'],
'lastloginip' => $row['lastloginip'],
'email' => $row['email']
);
}
$a = json_encode($str);
$results = aes_encrypt($a, "aa834085ebd67a24");
echo $results;
?>
0x6 总结与注意事项
-
加密类型判断:
- 全数据包加密处理较简单
- 局部加密数据需要精确识别加密字段
- JSON格式数据可通过
json.loads()判断是否为明文
-
算法逆向要点:
- 必须找到加密算法和密钥信息
- 需要调试前端JavaScript代码或逆向移动应用
- 常见加密方式:AES ECB/CBC模式、RSA等
-
工具选择建议:
- 简单解密需求:Burpy插件
- 复杂双向加密:mitmproxy多层代理
- 自动化扫描:结合xray或sqlmap
-
常见问题:
- 部分接口加密/部分不加密的情况需要特殊处理
- 防止二次加密导致数据异常
- 注意加密模式(ECB/CBC等)和填充方式(PKCS7等)
0x7 参考资源
通过本文介绍的技术方案,可以有效解决渗透测试过程中遇到的各种数据加密问题,提高测试效率和漏洞发现能力。