为什么要写插件而不是手动看包
mitmproxy 手动看包适合探索,但逆向工程经常需要批量处理:自动解密响应、自动提取 token、自动记录特定接口。这些靠手点不现实——mitmproxy 的插件系统(Python addon)就是干这个的。
mitmdump -s myaddon.py --listen-port 8888
# 手机代理指向 8888,所有流量经过你的 Python 代码插件骨架:事件驱动
mitmproxy 插件是事件驱动的,常用事件钩子:
from mitmproxy import http, ctx
class DecryptAddon:
def request(self, flow: http.HTTPFlow):
# 请求经过时触发(发往服务器前)
if 'api.target.com' in flow.request.pretty_host:
ctx.log.info(f'[REQ] {flow.request.method} {flow.request.path}')
ctx.log.info(f'[BODY] {flow.request.get_text()}')
def response(self, flow: http.HTTPFlow):
# 响应经过时触发(返回客户端前)
if 'api.target.com' in flow.request.pretty_host:
body = flow.response.get_text()
ctx.log.info(f'[RESP] {body[:500]}')
addons = [DecryptAddon()]实战场景一:自动解密 AES 响应
目标 App 的响应体是 AES 加密的(密钥已从 App 逆出),插件自动解密后展示:
from mitmproxy import http, ctx
from Crypto.Cipher import AES
import base64, json
KEY = b'1234567890abcdef' # 从 App 逆出的密钥
IV = b'0102030405060708'
class AutoDecrypt:
def response(self, flow: http.HTTPFlow):
if 'api.target.com' not in flow.request.pretty_host:
return
try:
raw = base64.b64decode(flow.response.get_text())
cipher = AES.new(KEY, AES.MODE_CBC, IV)
plain = cipher.decrypt(raw)
plain = plain[:-plain[-1]] # 去 PKCS7 填充
data = json.loads(plain)
# 把解密结果写回响应(App 端无感,mitmproxy 界面直接看明文)
flow.response.set_text(json.dumps(data, ensure_ascii=False, indent=2))
except Exception as e:
ctx.log.warn(f'解密失败: {e}')
addons = [AutoDecrypt()]注意:把解密结果写回响应会让 App 收到明文——如果 App 有响应完整性校验会崩。稳妥做法是只记录不改写(写日志/存文件),或只在分析阶段改写。
实战场景二:自动提取并维护 token
App 的 token 每小时刷新,手动抓包复制太蠢。插件自动提取:
import json, time
class TokenHarvester:
def __init__(self):
self.tokens = []
def response(self, flow: http.HTTPFlow):
# 登录接口的响应里提取 token
if '/login' in flow.request.path:
data = json.loads(flow.response.get_text())
token = data.get('data', {}).get('token')
if token:
self.tokens.append({'token': token, 'time': time.time()})
# 落盘供协议程序读取
with open('/tmp/tokens.json', 'w') as f:
json.dump(self.tokens, f)
addons = [TokenHarvester()]协议程序读 /tmp/tokens.json 就能拿到最新 token——mitmproxy 成了 token 的自动收割机。
实战场景三:请求重放与修改
class RequestModifier:
def request(self, flow: http.HTTPFlow):
if '/api/order' in flow.request.path:
# 修改请求参数(测试服务端校验逻辑)
body = json.loads(flow.request.get_text())
body['price'] = '0.01' # 改价测试
flow.request.set_text(json.dumps(body))
addons = [RequestModifier()]精髓:三个工程要点
- mitmdump 比 mitmproxy 适合生产。mitmproxy 是交互界面,mitmdump 是无头命令行——跑插件服务用 mitmdump,稳定且资源占用低
- flow 对象是完整上下文。
flow.request、flow.response、flow.client_conn、flow.error全在,甚至可以拿到 TLS 信息(flow.server_conn.certificate_list)做证书分析 - 插件热重载。
mitmdump -s addon.py运行中改了 addon.py 会自动重载——调试插件时不用重启,改完保存即生效
总结
- mitmproxy 插件 = Python 事件钩子,request/response 两个钩子覆盖 90% 需求
- 三大实战场景:自动解密、token 收割、请求修改
- 解密写回要小心完整性校验,稳妥方案是只记录
- 生产用 mitmdump,插件热重载加速调试
交流微信:run1255