【古法渗透】jsrpcmitmproxy联动burp实现加密自动化

admin 2026-08-08 06:30:20 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文介绍JsRpc工具与mitmproxy、Burp联动实现加密自动化渗透测试。JsRpc基于WebSocket实现浏览器与本地Go服务端通信,通过注入JS脚本调用浏览器原生环境执行加密函数,避免Node.js补环境。实战演示了在加密靶场中分析AES加密、注入JsRpc环境并动态注册函数,最终实现自动化调用加密函数。该方法可简化JS逆向中的加密处理流程,提升渗透测试效率。 综合评分: 75 文章分类: 渗透测试,红队,内网渗透,安全工具,逆向分析


cover_image

【古法渗透】 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 补环境。

三、整体结构

  1. Server 服务端:Go 语言编写,监听 HTTP + WebSocket,默认端口 12080
  2. Browser 客户端:浏览器页面注入 JsEnv_De.js 脚本(JS 客户端)
  3. 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&param={"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实现加密自动化》

评论:0   参与:  0