文章总结: 本文介绍JsRpc工具与mitmproxy、Burp联动实现加密自动化渗透测试。JsRpc基于WebSocket实现浏览器与本地Go服务端通信,通过注入JS脚本调用浏览器原生环境执行加密函数,避免Node.js补环境。实战演示了在加密靶场中分析AES加密、注入JsRpc环境并动态注册函数,最终实现自动化调用加密函数。该方法可简化JS逆向中的加密处理流程,提升渗透测试效率。 综合评分: 75 文章分类: 渗透测试,红队,内网渗透,安全工具,逆向分析
【古法渗透】 jsrpc mitmproxy联动burp实现加密自动化
原创
暗月大徒弟 暗月大徒弟
moonsec
2026年8月4日 12:12 广东
在小说阅读器读本章
去阅读
免责声明:本公众号所提供的文字和信息仅供学习和研究使用,不得用于任何非法用途。我们强烈谴责任何非法活动,并严格遵守法律法规。读者应该自觉遵守法律法规,不得利用本公众号所提供的信息从事任何违法活动。本公众号不对读者的任何违法行为承担任何责任。
一、介绍
JsRpc 是黑脸怪开源、Go 后端 + 前端 JS 注入、基于 WebSocket 双向长连接 的 RPC 远程调用工具,核心定位:JS 逆向免补环境神器,项目地址:https://github.com/weixinpad/JsRpc
二、运行原理
浏览器页面注入一段 JsRpc 环境 JS,主动通过 WebSocket 连接本地 Go 服务端;你在 Python/HTTP 接口下发指令,让目标网页原生浏览器环境执行 JS 代码 / 加密函数,结果回传给本地,彻底不用在 Node.js 里模拟 DOM、BOM、浏览器内置 API 补环境。
三、整体结构
- Server 服务端:Go 语言编写,监听 HTTP + WebSocket,默认端口 12080
- Browser 客户端:浏览器页面注入 JsEnv_De.js 脚本(JS 客户端)
- Caller 调用端:Python /curl/ Burp / 自己写的程序,通过 HTTP 发指令
核心通信链路:调用端 → HTTP → Go 服务 → WebSocket 长连接 → 浏览器执行 JS → 原路返回结果
四、jsrpc实战操作
下载js前端加密对抗练习靶场 https://github.com/SwagXz/encrypt-labs 在本地进行搭建
使用phpstudy 搭建 网站 修改database.php数据库配置信息 导入sql导入数据库 访问即可
账号和密码 admin/123456
加密分析
登录之后 选择 aes固定key
查看网络发现是一段密文
js分析
搜寻关键词 encrypt 查看代码 js代码都是经混饶 断点调试
查看整个加密方式 使用CryptoJS库对进行aes进行加密 固定的iv和key都是 1234567890123456
const _0x67b862 = CryptoJS['enc']['Utf8']['parse']('1234567890123456')
, _0x2d9cd5 = CryptoJS['enc'][_0x2fe90c(0x118, 0x11a)]['parse']('1234567890123456')
, _0x1375d7 = CryptoJS['AES'][_0x2fe90c(0x119, 0x11c)](_0x807d91, _0x67b862, {
'iv': _0x2d9cd5,
'mode': CryptoJS[_0x2fe90c(0x11a, 0x11b)]['CBC'],
'padding': CryptoJS[_0x2fe90c(0x11b, 0x11e)][_0x2fe90c(0x11c, 0x12c)]
})[_0x2fe90c(0x11d, 0x10e)]()
, _0x550d63 = 'encryptedData=' + encodeURIComponent(_0x1375d7);
主要的作用对传入的字符串字符串进行aes加密接着url编码返回赋值
这是没有经过混饶的代码
function encryptData(data) {
const key = CryptoJS.enc.Utf8.parse('1234567890123456');
const iv = CryptoJS.enc.Utf8.parse('1234567890123456');
return CryptoJS.AES.encrypt(data, key, {
iv: iv,
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString();
}
使用jsrcp调用该混饶代码
在jsrcp目录中运行该window_amd64.exe服务器端
在目录中 resouces\JsEnv_Dev.js 赋值该代码到js终端中执行
var rpc_client_id, HlClient = function (wsURL) {
this.wsURL = wsURL;
this.handlers = {
_execjs: function (resolve, param) {
try {
var fn = new Function('return (async () => { return (' + param + ') })()');
var result = fn();
if (result && typeof result.then === 'function') {
result.then(function(res) {
resolve(res !== undefined ? res : "执行成功(无返回值)");
}).catch(function(err) {
resolve("执行错误: " + (err.message || err));
});
} else {
resolve(result !== undefined ? result : "执行成功(无返回值)");
}
} catch (err) {
resolve("语法错误: " + (err.message || err));
}
}
};
this.socket = undefined;
if (!wsURL) {
throw new Error('wsURL can not be empty!!')
}
this.connect()
}
HlClient.prototype.connect = function () {
if (this.wsURL.indexOf("clientId=") === -1 && rpc_client_id) {
this.wsURL += "&clientId=" + rpc_client_id
}
console.log('begin of connect to wsURL: ' + this.wsURL);
var _this = this;
try {
this.socket = new WebSocket(this.wsURL);
this.socket.onmessage = function (e) {
_this.handlerRequest(e.data)
}
} catch (e) {
console.log("connection failed,reconnect after 10s");
setTimeout(function () {
_this.connect()
}, 10000)
}
this.socket.onclose = function () {
console.log('rpc已关闭');
setTimeout(function () {
_this.connect()
}, 10000)
}
this.socket.addEventListener('open', (event) => {
console.log("rpc连接成功");
this._reportActions();
});
this.socket.addEventListener('error', (event) => {
console.error('rpc连接出错,请检查是否打开服务端:', event.error);
})
};
HlClient.prototype.send = function (msg) {
this.socket.send(msg)
}
HlClient.prototype.regAction = function (func_name, func) {
if (typeof func_name !== 'string') {
throw new Error("an func_name must be string");
}
if (typeof func !== 'function') {
throw new Error("must be function");
}
console.log("register func_name: " + func_name);
this.handlers[func_name] = func;
this._reportActions();
return true
}
HlClient.prototype._reportActions = function () {
var actions = Object.keys(this.handlers);
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
this.send(JSON.stringify({
"action": "_registerActions",
"message_id": "",
"response_data": JSON.stringify(actions)
}));
}
}
HlClient.prototype.handlerRequest = function (requestJson) {
var _this = this;
try {
var result = JSON.parse(requestJson)
} catch (error) {
console.log("请求信息解析错误", requestJson);
return
}
if (result["registerId"]) {
rpc_client_id = result['registerId']
return
}
if (!result['action'] || !result["message_id"]) {
console.warn('没有方法或者消息id,不处理');
return
}
var action = result["action"], message_id = result["message_id"]
var theHandler = this.handlers[action];
if (!theHandler) {
this.sendResult(action, message_id, 'action没找到');
return
}
try {
if (!result["param"]) {
const async_result = theHandler(function (response) {
_this.sendResult(action, message_id, response);
})
if (async_result && typeof async_result.then === "function") {
async_result.catch(e => {
_this.sendResult(action, message_id, "" + e);
});
}
return
}
var param = result["param"]
try {
param = JSON.parse(param)
} catch (e) {
}
theHandler(function (response) {
_this.sendResult(action, message_id, response);
}, param)
} catch (e) {
console.log("error: " + e);
_this.sendResult(action, message_id, "" + e);
}
}
HlClient.prototype.sendResult = function (action, message_id, e) {
if (typeof e === 'object' && e !== null) {
try {
e = JSON.stringify(e)
} catch (v) {
console.log(v)
}
}
this.send(JSON.stringify({"action": action, "message_id": message_id, "response_data": e}));
}
如图
注入环境之后连接通信 grup是组 一般不用设置使用默认的就可以了
var demo = new HlClient("ws://127.0.0.1:12080/ws?group=zzz");
在服务端上回显信息表示连接成功。
动态注册函数
在js中选择替换修改js内容 选择文件夹
修改后文件进行保存 ctrl+f5进行刷新
const _0x67b862 = CryptoJS['enc']['Utf8']['parse']('1234567890123456')
const _0x2d9cd5 = CryptoJS['enc'][_0x2fe90c(0x118, 0x11a)]['parse']('1234567890123456')
demo.regAction("encryptest", function (resolve,param) {
const _0x807d91 = JSON['stringify'](param);
const _0x1375d7 = CryptoJS['AES'][_0x2fe90c(0x119, 0x11c)](_0x807d91, _0x67b862, {
'iv': _0x2d9cd5,
'mode': CryptoJS[_0x2fe90c(0x11a, 0x11b)]['CBC'],
'padding': CryptoJS[_0x2fe90c(0x11b, 0x11e)][_0x2fe90c(0x11c, 0x12c)]
})[_0x2fe90c(0x11d, 0x10e)]()
const _0x550d63 = 'encryptedData=' + encodeURIComponent(_0x1375d7);
resolve(_0x550d63);
});
encryptest 是注册的函数名 resolve是返回的内容 param是传入的参数
再进行调用
http://127.0.0.1:12080/go?group=zzz&action=encryptest¶m={"username":"admin","password":"123456"}
python编写调用脚本
encrypt_demo.py
import json
import requests
def encrypt(data):
url = "http://127.0.0.1:12080/go"
params = {
"group": "zzz",
"action": "encryptest",
"param": data
}
response = requests.get(url, params=params)
context = response.json()['data']
return context
data={"username":"admin","password":"123456"}
body_data = json.dumps(data)
print(encrypt(body_data))
执行返回 返回加密的字符串
五、mitmproxy联动 burp调用jsrpc
mitmproxy 是一个“中间人代理”。它位于你的客户端(如浏览器、手机应用程序)和目标服务器之间,拦截、检查、和重放所有流经的 HTTP/HTTPS 请求和响应。
将mitmproxy作为burp的上游代理,当请求包经过mitmproxy时,通过python脚本处理请求体(&searchCond之前的部分)后传给jsrpc进行加密,mitmproxy将请求体中的sign替换后发送给服务端,流程图如下。
安装
pip install mitmproxy
mitmproxy 是可以加载python脚本处理数据包
import json
from urllib.parse import parse_qs
from mitmproxy import http
import requests
def encrypt(data):
url = "http://127.0.0.1:12080/go"
params = {
"group": "zzz",
"action": "encryptest",
"param": data
}
response = requests.get(url, params=params)
context = response.json()['data']
return context
class Demo:
def request(self, flow: http.HTTPFlow) -> None:
url = "/encrypt/aes.php"
if flow.request.method == "POST" and flow.request.path == url:
if "encryptedData" in flow.request.text:
# 解析POST表单请求体,转成字典
data = parse_qs(flow.request.text)
encrypt_data = data.get("encryptedData", [''])[0]
new_data = encrypt(encrypt_data)
flow.request.text = new_data
addons = [Demo()]
使用命令
mitmproxy -p 端口 -s 指定脚本
执行命令
mitmproxy -p 8899 -s C:\Users\moon\PycharmProjects\PythonProject\encrypt_burp.py
运行没有出错 在burp中设置上游代理
接着提交数据包 返回true
接着可以测试穷举
参考 https://www.cnblogs.com/xiaoqiuni/p/18860405
需要本文相关工具
关注公众号回复【20260804】
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:moonsec 暗月大徒弟 暗月大徒弟《【古法渗透】 jsrpc mitmproxy联动burp实现加密自动化》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。











评论