JS逆向-数据包解签名实战案例
字数 1598 2025-08-10 16:34:25

JS逆向-数据包解签名实战案例教学文档

0x00 前言

本教学文档基于FreeBuf上的JS逆向实战案例,详细讲解如何分析并破解数据包中的签名机制。签名机制常用于API请求的身份验证和防篡改,常见签名字段如signappsign等。

免责声明:本文涉及的所有技术仅用于学习交流,严禁用于非法用途。未经授权请勿进行非法渗透测试,否则后果自负。

0x01 签名机制分析流程

1. 识别签名字段

通过抓包分析,确定目标网站的签名字段为sign

2. 定位签名代码

在浏览器开发者工具的Sources面板中搜索sign字段,通常签名逻辑会出现在app.*.js这类文件中。在本案例中,签名代码位于app.72b81572.js文件中。

3. 分析签名函数

找到的关键签名函数如下:

function k(e) {
    const t = g(),
        n = m();
    let a;
    a = e ? b(e) : {};
    const r = e ? `${c.a.stringify(a.hasParams)}&${t}&time=${n}` : `${t}&time=${n}`;
    return e = Object.assign({}, a.params, {
        sign: h()(decodeURIComponent(r)),
        time: n
    }), e
}

4. 参数分析

参数t

通过跟进g()函数,发现t的值为:

当前年份 + "5616" + 当前月份(两位数) + 当前日期(两位数)

例如:202356160812

参数n

通过跟进m()函数,发现n的值为当前时间戳(本案例中可不减去e值)。

参数a

a的值与传入参数e相同,e的内容即请求参数(GET)或请求体(POST)。

参数r

r是签名的明文,格式为:

请求内容 + "&" + t + "&time=" + n

注意:POST请求的JSON格式数据需要转换为key1=value1&key2=value2...的形式。

0x02 加密算法分析

通过调试发现加密类名为Md5,签名过程是对r字符串进行MD5哈希计算。

验证方法:

  1. 在签名代码行设置断点
  2. 获取r的值
  3. 计算r的MD5值
  4. 与代码执行的sign结果比较

0x03 mitmproxy脚本编写

mitmproxy是一个中间人代理工具,可以实时拦截和修改HTTP/HTTPS请求。以下是本案例的完整脚本:

from datetime import datetime
from mitmproxy import ctx
import hashlib
import random
import json
import time

class Modify:
    def __init__(self):
        self.plaintext = ''
        self.new_sign = ''
        current_datetime = datetime.now()
        self.today = f"{current_datetime.year}5616{current_datetime.month:02d}{current_datetime.day:02d}"

    def md5(self):
        md5_hash = hashlib.md5()
        md5_hash.update(self.plaintext.encode('utf-8'))
        self.new_sign = md5_hash.hexdigest()

    def request(self, flow):
        if flow.request.method == "POST":
            ctx.log.info(f'\n原POST请求体:{flow.request.text}')
            data = json.loads(flow.request.get_text())
            if data != '{}' and 'sign' in data:
                del data['sign']
                del data['time']
                for k in data:
                    self.plaintext += f"{k}={str(data[k])}&"
                timestamp = int(time.time() * 1000)
                self.plaintext += f"{self.today}&time={timestamp}"
                self.md5()
                data["sign"] = self.new_sign
                data["time"] = timestamp
                flow.request.set_text(json.dumps(data).replace(" ", ""))
                ctx.log.info(f'\n新POST请求体:{flow.request.text}')
                self.plaintext = ''
            else:
                ctx.log.info('无参数,无需改签')
        elif flow.request.method == "GET":
            ctx.log.info(f'\n原GET请求体:{flow.request.query}')
            query = flow.request.query
            if query != '{}' and 'sign' in query:
                del query['sign']
                del query['time']
                if query:
                    for k in query:
                        self.plaintext += f"{k}={str(query[k])}&"
                else:
                    self.plaintext = "&"
                timestamp = int(time.time()) * 1000
                self.plaintext += f"{self.today}&time={timestamp}"
                self.md5()
                query["sign"] = self.new_sign
                query["time"] = timestamp
                ctx.log.info(f'\n新GET请求体:{flow.request.query}')
                self.plaintext = ''
            else:
                ctx.log.info('无参数,无需改签')

    @staticmethod
    def response(flow):
        if '签名校验失败!' in flow.response.text:
            ctx.log.error(f'\n签名异常:\nurl => {flow.request.path}\n异常信息 => {flow.response.text}')

addons = [
    Modify()
]

mitmproxy常用命令

mitmdump -p 777 -s ./mitmscript.py --flow-detail 0

mitmproxy常用属性和方法

上下文对象(ctx)

  • ctx.log.info(): 在mitmproxy日志中输出信息
  • ctx.options: 访问mitmproxy配置选项
  • ctx.master: mitmproxy的Master对象
  • ctx.proxy: ProxyConfig对象
  • ctx.client: ClientConnection对象
  • ctx.server: ServerConnection对象
  • ctx.protocol: ProtocolHandler对象

回调函数

  • request(flow): 拦截请求时调用
  • response(flow): 拦截响应时调用
  • error(flow): 请求/响应出错时调用
  • clientconnect(flow): 客户端连接时调用
  • serverconnect(flow): 连接服务器时调用

flow.request常用属性

  • method: 请求方法(GET/POST等)
  • scheme: 协议(http/https)
  • host: 主机名
  • port: 端口号
  • path: 路径部分
  • url: 完整URL
  • headers: 请求头(字典)
  • cookies: Cookie信息(字典)
  • query: 查询参数(字典)
  • content: 请求内容(字节)
  • text: 请求内容(文本)
  • urlencoded_form: URL编码表单数据(字典)
  • multipart_form: 多部分表单数据(列表)

0x04 总结

本案例完整展示了如何:

  1. 识别签名字段
  2. 定位签名代码
  3. 分析签名参数生成逻辑
  4. 确定加密算法(MD5)
  5. 编写mitmproxy脚本实现自动签名

关键点:

  • 签名明文格式:请求参数 + 时间相关字符串
  • POST请求需要将JSON转换为键值对格式
  • 时间戳和日期字符串是签名的重要组成部分
  • MD5是常见的签名算法之一

通过掌握这些技术,可以更好地理解Web应用的安全机制,并用于合法的安全测试和研究。

JS逆向-数据包解签名实战案例教学文档 0x00 前言 本教学文档基于FreeBuf上的JS逆向实战案例,详细讲解如何分析并破解数据包中的签名机制。签名机制常用于API请求的身份验证和防篡改,常见签名字段如 sign 、 appsign 等。 免责声明 :本文涉及的所有技术仅用于学习交流,严禁用于非法用途。未经授权请勿进行非法渗透测试,否则后果自负。 0x01 签名机制分析流程 1. 识别签名字段 通过抓包分析,确定目标网站的签名字段为 sign 。 2. 定位签名代码 在浏览器开发者工具的Sources面板中搜索 sign 字段,通常签名逻辑会出现在 app.*.js 这类文件中。在本案例中,签名代码位于 app.72b81572.js 文件中。 3. 分析签名函数 找到的关键签名函数如下: 4. 参数分析 参数t 通过跟进 g() 函数,发现t的值为: 例如:202356160812 参数n 通过跟进 m() 函数,发现n的值为当前时间戳(本案例中可不减去e值)。 参数a a的值与传入参数e相同,e的内容即请求参数(GET)或请求体(POST)。 参数r r是签名的明文,格式为: 注意:POST请求的JSON格式数据需要转换为 key1=value1&key2=value2... 的形式。 0x02 加密算法分析 通过调试发现加密类名为 Md5 ,签名过程是对r字符串进行MD5哈希计算。 验证方法: 在签名代码行设置断点 获取r的值 计算r的MD5值 与代码执行的sign结果比较 0x03 mitmproxy脚本编写 mitmproxy是一个中间人代理工具,可以实时拦截和修改HTTP/HTTPS请求。以下是本案例的完整脚本: mitmproxy常用命令 mitmproxy常用属性和方法 上下文对象(ctx) ctx.log.info() : 在mitmproxy日志中输出信息 ctx.options : 访问mitmproxy配置选项 ctx.master : mitmproxy的Master对象 ctx.proxy : ProxyConfig对象 ctx.client : ClientConnection对象 ctx.server : ServerConnection对象 ctx.protocol : ProtocolHandler对象 回调函数 request(flow) : 拦截请求时调用 response(flow) : 拦截响应时调用 error(flow) : 请求/响应出错时调用 clientconnect(flow) : 客户端连接时调用 serverconnect(flow) : 连接服务器时调用 flow.request常用属性 method : 请求方法(GET/POST等) scheme : 协议(http/https) host : 主机名 port : 端口号 path : 路径部分 url : 完整URL headers : 请求头(字典) cookies : Cookie信息(字典) query : 查询参数(字典) content : 请求内容(字节) text : 请求内容(文本) urlencoded_form : URL编码表单数据(字典) multipart_form : 多部分表单数据(列表) 0x04 总结 本案例完整展示了如何: 识别签名字段 定位签名代码 分析签名参数生成逻辑 确定加密算法(MD5) 编写mitmproxy脚本实现自动签名 关键点: 签名明文格式:请求参数 + 时间相关字符串 POST请求需要将JSON转换为键值对格式 时间戳和日期字符串是签名的重要组成部分 MD5是常见的签名算法之一 通过掌握这些技术,可以更好地理解Web应用的安全机制,并用于合法的安全测试和研究。