在做渗透测试时数据包被加密很难受?从而导致挖不到?看不懂?没关系,解开它我们不要9999不要8888只需要看着文章就能拿下它,把它一层一层的剥开让数据包光溜溜的在你面前无处可逃。
这里用到了mitmproxy联动burp,你要问我是什么,那就接着往下看!
0x01 mitmproxy
介绍
功能
-
- 拦截HTTP和HTTPS请求和响应,并实时修改它们 -
- 保存完整的HTTP对话,以便稍后重播和分析 -
- 重播HTTP对话的客户端 -
- 重播之前记录的服务器的HTTP响应 -
- 反向代理模式将流量转发到指定的服务器 -
- macOS和Linux上的透明代理模式 -
- 使用Python对HTTP流量进行脚本更改 -
- 用于拦截的SSL/TLS证书是实时生成的 -
- 还有很多,还有更多......
mitmproxy项目的工具是一组前端,公开了常见的底层功能。当我们谈论“mitmproxy”时,我们通常指的是三个工具中的任何一个——它们只是同一核心代理的不同前端。
mitmproxy是一个具有SSL/TLS能力的交互式拦截代理,具有HTTP/1、HTTP/2和WebSockets的控制台接口。
mitmweb是mitmproxy的基于Web的界面。
mitmdump是mitmproxy的命令行版本。想想HTTP的tcpdump。
看了这么多是不是感觉屌起来,这里我们着重看(使用Python对HTTP流量进行脚本更改)用python脚本直接更改数据包,那后面都知道是什么了吧。直接就是将流量代理到mitmproxy带上js的解密脚本转发到burp那不嘎嘎拿下嘛。
安装
官网 https://mitmproxy.org
GitHub https://github.com/mitmproxy/mitmproxy
这里还是直接看官方的文档安装就行了就不赘述了
https://docs.mitmproxy.org/stable/#features
成功运行后,启用代理访问以下链接安装证书:http://mitm.it/
如果实在不懂就多看看官方文档(我是懒b不想截图了)
常用参数
-p 指定端口
-s 指定需要加载的python脚本
-m 指定模式[regular,transparent,socks5,reverse:SPEC,upstream:SPEC]
--ssl-insecure 忽略https
0x02 联动Burp
这里通过JS逆向已经将key以及加密算法调出来了(得需要js逆向的前置知识),mitmproxy刚刚不是讲了可以联动python脚本,我们直接使用魔法将python解密和加密脚本变出来(因为解密后还得加密还原数据包发送到服务器)。
这里我在一次授权测试项目中发现是AES-EBC模式进行加解密的(比较敏感脱敏也没办法发),根据这个变出脚本(demo)
key为私钥
Decrypt:
import mitmproxy.http
import mitmproxy.ctx
from mitmproxy import flowfilter, ctx
import base64
from urllib.parse import unquote
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
def decrypt_aes_ecb(ciphertext):
key = "xxxxxxx"
ciphertext = base64.b64decode(ciphertext)
cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
decrypted_data = cipher.decrypt(ciphertext)
decrypted_data = unpad(decrypted_data, AES.block_size)
decrypted_text = decrypted_data.decode('utf-8')
print(decrypted_text)
return decrypted_text
def encrypt_message(message):
key = "xxxxxxx"
message = message.encode('utf-8')
cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
ct_bytes = cipher.encrypt(pad(message, AES.block_size))
encrypt_text = base64.b64encode(ct_bytes).decode('utf-8')
return encrypt_text
class Decrypt:
def request(self, flow: mitmproxy.http.HTTPFlow):
# 请求解密
url = str(flow.request.url)
if flow.request.url.startswith("https://xxxx.com/"):
for name, value in flow.request.urlencoded_form.items():
try:
flow.request.urlencoded_form[name] = decrypt_aes_ecb(value)
except ValueError:
pass
def response(self, flow: mitmproxy.http.HTTPFlow):
response_data = flow.response
excluded_extensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.js', '.css', '.woff', '.ttf']
if flow.request.pretty_url.startswith("https://xxxx.com/") and not any([ext in flow.request.path for ext in excluded_extensions]):
if '"{/"' in flow.response.get_text(): //这里根据返回包去判断
bodydata = encrypt_message(response_data.text)
flow.response.text = bodydata
print(flow.response.text)
addons = [
Decrypt()
]
Encrypt:
import mitmproxy.http
import mitmproxy.ctx
from mitmproxy import flowfilter, ctx
import base64
import re
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from urllib.parse import unquote
def decrypt_aes_ecb(ciphertext):
key = "xxxx"
ciphertext = base64.b64decode(ciphertext)
cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
decrypted_data = cipher.decrypt(ciphertext)
decrypted_data = unpad(decrypted_data, AES.block_size)
decrypted_text = decrypted_data.decode('utf-8')
return decrypted_text
def encrypt_message(message):
key = "xxxx"
decoded_message = unquote(message)
message = message.encode('utf-8')
cipher = AES.new(key.encode('utf-8'), AES.MODE_ECB)
ct_bytes = cipher.encrypt(pad(message, AES.block_size))
encrypt_text = base64.b64encode(ct_bytes).decode('utf-8')
return encrypt_text
class Encrypt:
def request(self, flow: mitmproxy.http.HTTPFlow):
# 判断请求 URL 是否属于目标域名
if flow.request.pretty_url.startswith("https://xxxxx.com/"):
# 遍历表单数据,并将其进行 AES-ECB 加密
try:
for name, value in flow.request.urlencoded_form.items():
if "==" in value:
pass
else:
print(value)
encrypted_msg = encrypt_message(value).encode("utf-8")
flow.request.urlencoded_form[name] = encrypted_msg
print(f"加密后的数据包:'{name}': {encrypted_msg}")
except Exception as e:
pass
def response(self, flow: mitmproxy.http.HTTPFlow):
if flow.request.pretty_url.startswith("https://xxx.com/"):
res = flow.response.get_text()
#这里的判断是加密后的数据包还添加了一个固定字符串
if "test|" in res:
ctx.log.info("原始服务器响应数据 => " + res)
data = res.replace("test|", "")
flow.response.set_text(decrypt_aes_ecb(data))
addons = [
Encrypt()
]
麻烦忽略我的小学生代码,这里使用的是两个脚本,一个里面对数据包解密、返回包加密,一个对数据包加密、返回包解密。请看草图(真的很潦草,跟着箭头走)
图有点问题,当时忘改了返回包那的逻辑是 加密返回包->解密后的返回包->更改后的解密返回包->加密后的更改返回包
浏览器代理第一个mitmproxy启动的端口,第一个对数据包解密、返回包加密放Burp前面Burp代理设置为该脚本,另外一个设置为Burp的上游代理。
原神启动
第一个 mitmdump -p 8180 -m upstream:http://127.0.0.1:2233 --ssl-insecure -s 脚本名
设置上游代理
第二个 mitmweb -p 7777 -s 脚本名称
直接从加密到脱光解开,渗透结束非常安全。
没解密之前,看不懂根本看不懂
解密后直接拿下
其实这个根据这个逻辑将常见的加密算法把他们的脚本都写出来,然后在碰到相同算法的时候直接填进去就可以直接用了,不用现写脚本节约时间。
到这里也就结束了,现在做渗透也是越来越难了,混淆加密等等一系列(特别是内卷,进行严厉的批评)都压在我这颗什么都不会的小草身上,但是还得一直学习下去让自己能茁壮成长(不然没饭吃,直接饿死),所以有大哥能看穿我的脆弱带我转行吗,啥也不会就是会舔。
原文始发于微信公众号(Poker安全):JS加解密之mitmproxy联动Burp全自动加解密数据包
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论