经过一段时间的研究,发现暂时没有办法做到针对非对称加密的加解密双流程,但是如果仅仅请求是密文,返回是明文的情况下,可以实现利用JSRPC配合mitmdump实现半自动化首先我们看一下原始请求和响应
大家可以看到,请求是加密的,响应是明文的,这里就可以满足我们的需求了,如果返回也是加密的,就没法用我说的方法了,因为非对称加密拿不到私钥,没有解密函数是没法解密的,但是因为有公钥,所以可以明文加密
此时需要看一下加密的方式,直接去F12,全局搜索encrypt就行,一般情况下如果js没混淆是可以找到的
一眼丁真,因为我们现在示例是登录请求,实际上干活的时候后续的内容也一样都是rsa加密的,只不过不是一个处理流程,这里用登录请求进行演示,如果大家感兴趣为啥这是rsa加密,大家可以跟踪一下username: n.encrypt(e.username).toString(),由于篇幅原因,这里不进行演示
jsrpc大家自行去github下载即可,下载自己电脑对应的版本,然后直接运行就行
因为这个加密函数体是n,所以我们可以先全局注册一下n函数,其实不注册也可以,这里演示的原因是因为,有些加密函数比较复杂,需要多个函数联调,所以演示一下注册流程,注册的时候,需要开启动态调试,将断点打在加密之前就行
进入控制台,因为这里用的主体函数其实是n,一般情况,注册的原因是为了书写规范点,后续调用jsrpc注册的时候方便点
接下来直接放过断点,然后断点取消就行,并将jsrpc的jsenv_dev.js代码整个拷贝到控制台
首先连接jsrpc服务器,这里面默认端口就行,group的名字大家可以自己定义,叫啥都行,ws是服务端,go是客户端
var demo = new Hlclient("ws://127.0.0.1:12080/ws?group=zzz");
编写jsrpc的函数,因为我们是非对称加密,所以只编写加密函数就行,注意,一定要连接jsrpc后再注册
demo.regAction("encode",function (resolve,param) {
username=param.username
password=param.password
var request = {
"username":n.encrypt(username),
"password":n.encrypt(password),
}
var data={"request":""}
data["request"] = request
resolve(data);})
代码逻辑很简单,大家按照格式写就行,因为传参的username和password是明文的,所以在写的时候也要写明文;encode是加密函数的名字,param是传参,data是object对象的data,request是object里的一个对象,是我们的请求体,这几个名字都是可以改的,不会影响我们测试,就是方便大家看写完之后,大家可以测试一下
访问一下jsrpc的客户端,param填写明文的请求体就行,至于请求体怎么获取,在前端js代码随便找个明文传参的地方做个输出打印就行,这样的话每次请求就会输出一个明文请求,大家直接就能拿着请求去加密
这个时候说明jsrpc阶段成功了,如果是对称加密,只需要把解密函数注册进去就可以解密,下一期用一下好胸弟的靶场给大家演示一下,大家也可以关注一下三十的安全屋,里面有非常详细的教程
上一期讲到了mitmdump上下游代理实现明文加解密,但是mitmdump有一个缺点,就是如果自己用就需要写加解密函数,但是很显然rsa的这种非对称加密直接就趴窝了,但是没关系,我们只用上游代理,关联jsrpc,这样的话就可以实现,burpsuite明文请求传递给mitmdump,mitmdump再经过jsrpc加密,jsrpc把加密后的内容回馈给mitmdump,这样就可以半自动化测试,怎么也比在控制台里测快,我个人是这么认为
不废话,直接上代码
from mitmproxy import http, ctx
import json
import requests
from urllib.parse import urlencode, quote
def encrypt_params(username, password):
"""调用jsrpc接口进行参数加密"""
try:
param_json = json.dumps({"username": username, "password": password})
encoded_param = quote(param_json, safe='')
url = f"http://127.0.0.1:12080/go?group=zzz&action=encode¶m={encoded_param}"
response = requests.get(url, timeout=5)
if response.status_code == 200:
encrypted_data = response.json()
ctx.log.info(f"原始加密响应: {encrypted_data}")
# 关键修复:解析 data 字段的字符串为JSON
data_dict = json.loads(encrypted_data["data"])
return (
data_dict["request"]["username"],
data_dict["request"]["password"]
)
return (None, None)
except Exception as e:
ctx.log.error(f"加密失败: {str(e)}")
return (None, None)
def request(flow: http.HTTPFlow) -> None:
# 只处理POST请求(根据实际情况调整)
if flow.request.method != "POST":
return
# 根据Content-Type处理不同格式
content_type = flow.request.headers.get("Content-Type", "")
# 处理JSON格式请求
if "application/json" in content_type:
try:
original_body = json.loads(flow.request.content)
except json.JSONDecodeError:
return
if "username" in original_body and "password" in original_body:
username = original_body["username"]
password = original_body["password"]
# 调用加密接口
enc_user, enc_pass = encrypt_params(username, password)
if enc_user and enc_pass:
# 替换加密后的参数
original_body["username"] = enc_user
original_body["password"] = enc_pass
# 更新请求体
flow.request.content = json.dumps(original_body).encode()
ctx.log.info("成功加密JSON参数")
# 处理表单格式请求
elif "application/x-www-form-urlencoded" in content_type:
form_data = flow.request.urlencoded_form
if "username" in form_data and "password" in form_data:
username = form_data["username"]
password = form_data["password"]
# 调用加密接口
enc_user, enc_pass = encrypt_params(username, password)
if enc_user and enc_pass:
# 替换加密后的参数
form_data["username"] = enc_user
form_data["password"] = enc_pass
# 更新请求体
flow.request.content = urlencode(form_data).encode()
ctx.log.info("成功加密表单参数")
代码的逻辑就是burpsuite请求体传递给mitmdump,mitmdump用请求直接去jsrpc里加密,然后替换请求传递给服务器,这样服务器传过来的就是密文的
运行脚本
mitmdump -p 9091 -s mitmdumpen.py --ssl-insecure
burpsuite此时不能发密文请求了,因为发了之后会二次加密,导致服务端不能识别,但是可以直接明文了
此时可以看到,jsrpc对明文进行了加密
mitmdump也返回了密文