mitmproxy在微信小程序渗透测试中的应用
微信小程序作为一种流行的轻量级应用平台,其安全性问题日益受到重视。小程序的网络请求往往涉及敏感信息传输,因此,对请求包的加解密处理尤为重要。然而,由于小程序的封闭性和加密性,对请求包的分析和测试存在一定难度。本文将探讨如何利用mitmproxy工具解决微信小程序渗透测试中的请求包加解密问题。
mitmproxy的作用
mitmproxy是一个功能强大的中间人代理工具,它能够拦截、分析、修改经过代理的HTTP(S)流量。通过mitmproxy,渗透测试人员可以解密HTTPS流量中经过算法加密的请求参数和响应包,查看和修改请求与响应数据,从而深入分析小程序的安全性,以下是请求流量的走向示意图:
mitmproxy在实际案例中的使用
1.安装mitmproxy根证书
mitmproxy的安装过程不做记录,需要注意的点是安装mitmproxy根证书,安装好mitmproxy后,使用everything搜索到mitmproxy的证书存放目录,导入到计算机中
2.编写mitmproxy下游加解密脚本
通过对数据包的分析发现,数据包的中的请求参数和响应参数中的bizContent字段是经过aes的加密,目前已知aes的密钥和加密模式为ECB
1.使用Proxifier代理微信小程序流量
设置代理端口
设置代理的规则
2.编写burp下游代理的解密脚本:
from mitmproxy import flowfilter, ctx # 导入mitmproxy的模块,用于流量过滤和日志记录
from mitmproxy.http import HTTPFlow # 导入HTTPFlow类,表示HTTP请求和响应的集合
from base64 import b64decode # 导入base64库的解码功能
import base64 # 导入base64库用于编码
import json # 导入json库用于处理JSON数据
from Crypto.Cipher import AES # 导入AES加密模块
from Crypto.Util.Padding import unpad, pad # 导入填充和去填充功能
# 定义使用AES ECB模式加密数据的函数
def aes_encrypt(ciphertext):
key = b'xxxxxxxx' # 定义16字节的密钥
data_bytes = pad(ciphertext.encode('utf-8'), AES.block_size) # 对数据进行填充
cipher = AES.new(key, AES.MODE_ECB) # 创建AES ECB模式的Cipher对象
encrypted_data = cipher.encrypt(data_bytes) # 加密数据
encoded_encrypted_data = base64.b64encode(encrypted_data) # 将加密数据转换为Base64编码
return encoded_encrypted_data.decode('utf-8') # 返回解码后的Base64字符串
# 定义使用AES ECB模式解密数据的函数
def aes_decrypt(ciphertext):
key = 'xxxxxxxx' # 密钥应该是字节串,这里应该直接提供字节串而不是字符串
key_bytes = bytes(key, 'utf-8') # 将密钥转换为字节串
cipher_text_bytes = b64decode(ciphertext) # 解码Base64编码的密文
cipher = AES.new(key_bytes, AES.MODE_ECB) # 创建AES ECB模式的解密器
decrypted_text = cipher.decrypt(cipher_text_bytes) # 解密数据
try:
plaintext = unpad(decrypted_text, AES.block_size) # 移除PKCS7填充
return plaintext.decode('utf-8') # 返回解密后的字符串
except ValueError as e: # 捕获填充错误
print(f"解密后无法移除填充: {e}")
return None
class Mimit():
def request(self, flow):
# 在请求处理函数中,解析请求体为JSON格式
req = json.loads(flow.request.get_text())
# 检查'bizContent'字段是否存在且不为空
if 'bizContent' in req and req['bizContent'] != '':
data = aes_decrypt(req['bizContent']) # 解密数据
ctx.log.info("请求数据 => " + data) # 记录解密后的数据
req['bizContent'] = data # 更新'bizContent'字段
flow.request.set_text(json.dumps(req)) # 设置更新后的请求体
def response(self, flow):
# 在响应处理函数中,解析响应体为JSON格式
rep = json.loads(flow.response.get_text())
# 检查'bizContent'字段是否存在且不为空
if 'bizContent' in rep and rep['bizContent'] != '':
data = aes_encrypt(rep['bizContent']) # 加密数据
ctx.log.info("响应数据 => " + data) # 记录加密后的数据
rep['bizContent'] = data # 更新'bizContent'字段
flow.response.set_text(json.dumps(rep)) # 设置更新后的响应体
# 将插件实例化为一个列表,以便mitmproxy加载
addons = [Mimit()]
3.执行下游解密脚本
mitmdump -p 7070 -s dec.py --mode upstream:http://127.0.0.1:8080 --ssl-insecure
burp中的默认端口依然保持不变
3.编写mitmproxys上游加解密脚本
1.编写burp上游加解密脚本
from mitmproxy import flowfilter, ctx # 导入用于流量过滤和日志记录的模块
from mitmproxy.http import HTTPFlow # 导入HTTPFlow模块,用于处理HTTP请求和响应
# 导入base64库用于编码和解码操作
from base64 import b64decode
import base64
# 导入json库用于解析和序列化JSON数据
import json
# 导入Crypto.Cipher.AES模块用于AES加密和解密
from Crypto.Cipher import AES
# 导入Crypto.Util.Padding模块用于数据的填充和去填充操作
from Crypto.Util.Padding import unpad, pad
# 定义使用AES ECB模式加密数据的函数
def aes_encrypt(ciphertext):
key = b'xxxxxxxx' # 定义16字节的密钥
data_bytes = pad(ciphertext.encode('utf-8'), AES.block_size) # 对数据进行PKCS7填充
cipher = AES.new(key, AES.MODE_ECB) # 创建AES ECB模式的Cipher对象
encrypted_data = cipher.encrypt(data_bytes) # 加密数据
encoded_encrypted_data = base64.b64encode(encrypted_data) # 将加密数据转换为Base64编码
return encoded_encrypted_data.decode('utf-8') # 返回Base64编码的字符串
# 定义使用AES ECB模式解密数据的函数
def aes_decrypt(ciphertext):
key = 'xxxxxxxx' # 密钥应该是字节串,这里直接提供字符串,将在函数内部转换
cipher_text_bytes = b64decode(ciphertext) # 解码Base64编码的密文
key_bytes = bytes(key, 'utf-8') # 将字符串形式的密钥转换为字节串
cipher = AES.new(key_bytes, AES.MODE_ECB) # 创建AES ECB模式的解密器
decrypted_text = cipher.decrypt(cipher_text_bytes) # 解密数据
try:
plaintext = unpad(decrypted_text, AES.block_size) # 移除PKCS7填充
return plaintext.decode('utf-8') # 返回解密后的字符串
except ValueError as e: # 捕获并处理解密过程中可能出现的填充错误
print(f"解密后无法移除填充: {e}")
return None
# 定义Mimit类,用于处理HTTP请求和响应
class Mimit():
def request(self, flow):
# 在请求处理函数中,解析请求体为JSON格式
req = json.loads(flow.request.get_text())
# 检查'bizContent'字段是否存在且不为空
if 'bizContent' in req and req['bizContent'] != '':
data = aes_encrypt(req['bizContent']) # 对'bizContent'字段进行AES加密
ctx.log.info("请求数据 => " + data) # 记录加密后的请求数据
req['bizContent'] = data # 更新JSON对象中的'bizContent'字段
flow.request.set_text(json.dumps(req)) # 设置更新后的请求体
def response(self, flow):
# 在响应处理函数中,解析响应体为JSON格式
rep = json.loads(flow.response.get_text())
# 检查'bizContent'字段是否存在且不为空
if 'bizContent' in rep and rep['bizContent'] != '':
data = aes_decrypt(rep['bizContent']) # 对'bizContent'字段进行AES解密
ctx.log.info("响应数据 => " + data) # 记录解密后的响应数据
rep['bizContent'] = data # 更新JSON对象中的'bizContent'字段
flow.response.set_text(json.dumps(rep)) # 设置更新后的响应体
# 将Mimit类的实例添加到addons列表,以便mitmproxy加载
addons = [Mimit()]
2.设置burp中的上游代理端口
3.执行上游加解密脚本
mitmdump -p 9090 -s enc.py --ssl-insecure
评论区