一次前端RSA加密之使用Mitmdump自动化加解密渗透测试
字数 1087 2025-08-23 18:31:09

前端RSA加密之使用Mitmdump自动化加解密渗透测试

1. 概述

本文详细记录了在一次渗透测试中遇到前端RSA加密时的完整解决方案,包括JS逆向分析、加密算法破解、代码提取以及使用Mitmdump实现自动化加解密的完整流程。

2. 加密机制分析

2.1 加密流程

  1. 随机值生成:系统调用y(32)函数生成两个32位随机值no

    • 基于字符串"0123456789ABCDEFabcdef"生成
  2. 数据加密

    • d1:使用n作为key和o作为iv值,对原始报文进行AES加密(CBC模式)
    • d2:使用服务端公钥和随机值n生成的RSA加密值
    • d3:使用服务端公钥和随机值o生成的RSA加密值
  3. 请求结构:最终请求体为{"d1":"...","d2":"...","d3":"..."}格式

2.2 解密流程

  1. 响应体解密
    • 使用客户端私钥解密d2得到n
    • 使用客户端私钥解密d3得到o
    • 使用no解密d1得到原始报文

3. JS逆向过程

3.1 定位加密函数

  1. 在浏览器控制台搜索"d1:"定位加密代码位置
  2. 通过断点调试分析加密流程:
    • a的生成处下断点
    • 单步调试进入Object(v["f"])函数
    • 确认使用了CBC模式的AES加密

3.2 关键变量分析

  • e:AES key值(来自n)
  • i:AES iv值(来自o)
  • t:加密前的请求体值
  • r:RSA公钥值

3.3 Webpack代码提取技巧

  1. 定位入口函数:在HTML中搜索call关键字
  2. 通用提取模板
var test_module;
(function(e) {
    var u={};
    function f(c) {
        if (u[c]) return u[c].exports;
        var n = u[c] = {
            i: c,
            l: !1,
            exports: {}
        };
        return e[c].call(n.exports, n, n.exports, f),
        n.l = !0,
        n.exports
    }
    test_module=f;
})({
    // 提取的加密函数代码
})
  1. 加密函数提取:找到AES加密函数所在模块,提取完整代码
"4b2a": function(t, e, i) {
    "use strict";
    i.d(e, "a", (function() { return n })),
    i.d(e, "c", (function() { return o })),
    i.d(e, "b", (function() { return a })),
    i.d(e, "d", (function() { return u })),
    i.d(e, "f", (function() { return c })),
    i.d(e, "e", (function() { return f }));
    i("d3b7");
    var r = i("7c74").sm2;
    function n() {
        var t = r.generateKeyPairHex();
        return new Promise((function(e) { t && e(t) }))
    }
    function o(t, e) {
        var i = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1,
        n = "04" + r.doEncrypt(t, e, i);
        return n
    }
    function a(t, e) {
        var i = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : 1,
        n = r.doDecrypt(t.substring(2), e, i);
        return n
    }
    var s = i("7c74").sm3;
    function u(t) {
        var e = s(t);
        return e
    }
    var h = i("7c74").sm4;
    function c(t, e, i) {
        var r = h.encrypt(t, e, { mode: "cbc", iv: i });
        return r
    }
    function f(t, e, i) {
        var r = h.decrypt(t, e, { mode: "cbc", iv: i });
        return r
    }
}
  1. 调用方法
function test_enc(t, e, i) {
    var test=test_module("7a74");
    var r = test.encrypt(t, e, { mode: "cbc", iv: i });
    return r
}

4. Mitmdump自动化加解密实现

4.1 Python脚本模板

import execjs
from mitmproxy import flowfilter
from mitmproxy.http import HTTPFlow
import subprocess
import json
from functools import partial

# 解决中文编码问题
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')

# 加载JS代码
with open("test.js","r",encoding="utf-8") as f:
    js_code=f.read()
    f.close()
ctx=execjs.compile(js_code)

# 配置密钥
publickey="替换为公钥"
privatekey="替换为私钥"

def enc(data):
    [d1,d2,d3]=ctx.call("req_enc",data,publickey)
    return [d1,d2,d3]

def dec(d1,d2,d3):
    result=ctx.call("res_dec",d1,d2,d3,privatekey)
    return result

class FilterFlow:
    def request(self, flow):
        if flow.request.url.startswith("https://目标地址/"):
            req=flow.request.get_text()
            if '"d1":' in req: return
            print("加密数据前:".format(req))
            data=enc(req)
            d1,d2,d3 = data[0],data[1],data[2]
            json_data={"d1":d1,"d2":d2,"d3":d3}
            result=json.dumps(json_data)
            print("加密数据后:".format(result))
            flow.request.set_text(result)

    def response(self, flow:HTTPFlow):
        if flow.request.url.startswith("https://目标地址/"):
            resp=flow.response.get_text()
            data=json.loads(resp)
            d1,d2,d3 = data["d1"],data["d2"],data["d3"]
            result=dec(d1,d2,d3)
            flow.response.set_text(result)

addons = [FilterFlow(),]

4.2 代理配置方案

方案一:仅响应体解密(Burp上游代理)

mitmdump -p 9090 -s ./test.py --ssl-insecure

Burp设置:

  1. User Options > Upstream Proxy Servers > Add
  2. 配置目标域名为9090端口

方案二:完整加解密(Burp上下游代理)

  1. 上游代理
mitmdump -p 9090 -s ./test.py --ssl-insecure
  1. 下游代理
mitmdump -p 7070 -s ./test.py --mode upstream:https://127.0.0.1:8080 --ssl-insecure
  1. 浏览器配置代理为Mitm的7070端口

4.3 与其他工具集成

使用SQLMap等工具时,将流量代理至Burp:

python sqlmap.py -u "https://目标地址/?id=1" --batch --proxy=http://127.0.0.1:8080

5. 应用场景

该方法适用于以下场景(需能获取加解密或防篡改的源代码):

  1. Web网页端做了防篡改及加解密
  2. App端做了防篡改及加解密
  3. 小程序端做了防篡改及加解密

6. 参考资源

  1. 利用mitmproxy+burpsuite实现请求和响应加解密
  2. Webpack逆向分析技巧
  3. SM2/SM3/SM4国密算法文档
前端RSA加密之使用Mitmdump自动化加解密渗透测试 1. 概述 本文详细记录了在一次渗透测试中遇到前端RSA加密时的完整解决方案,包括JS逆向分析、加密算法破解、代码提取以及使用Mitmdump实现自动化加解密的完整流程。 2. 加密机制分析 2.1 加密流程 随机值生成 :系统调用 y(32) 函数生成两个32位随机值 n 和 o 基于字符串"0123456789ABCDEFabcdef"生成 数据加密 : d1 :使用 n 作为key和 o 作为iv值,对原始报文进行AES加密(CBC模式) d2 :使用服务端公钥和随机值 n 生成的RSA加密值 d3 :使用服务端公钥和随机值 o 生成的RSA加密值 请求结构 :最终请求体为 {"d1":"...","d2":"...","d3":"..."} 格式 2.2 解密流程 响应体解密 : 使用客户端私钥解密 d2 得到 n 使用客户端私钥解密 d3 得到 o 使用 n 和 o 解密 d1 得到原始报文 3. JS逆向过程 3.1 定位加密函数 在浏览器控制台搜索 "d1:" 定位加密代码位置 通过断点调试分析加密流程: 在 a 的生成处下断点 单步调试进入 Object(v["f"]) 函数 确认使用了CBC模式的AES加密 3.2 关键变量分析 e :AES key值(来自 n ) i :AES iv值(来自 o ) t :加密前的请求体值 r :RSA公钥值 3.3 Webpack代码提取技巧 定位入口函数 :在HTML中搜索 call 关键字 通用提取模板 : 加密函数提取 :找到AES加密函数所在模块,提取完整代码 调用方法 : 4. Mitmdump自动化加解密实现 4.1 Python脚本模板 4.2 代理配置方案 方案一:仅响应体解密(Burp上游代理) Burp设置: User Options > Upstream Proxy Servers > Add 配置目标域名为9090端口 方案二:完整加解密(Burp上下游代理) 上游代理 : 下游代理 : 浏览器配置代理为Mitm的7070端口 4.3 与其他工具集成 使用SQLMap等工具时,将流量代理至Burp: 5. 应用场景 该方法适用于以下场景(需能获取加解密或防篡改的源代码): Web网页端做了防篡改及加解密 App端做了防篡改及加解密 小程序端做了防篡改及加解密 6. 参考资源 利用mitmproxy+burpsuite实现请求和响应加解密 Webpack逆向分析技巧 SM2/SM3/SM4国密算法文档