JS逆向-加密算法解密与Sign签名绕过
在渗透测试中,前端加密是阻碍参数篡改、重放攻击和漏洞验证的常见障碍。无论是登录密码加密、API签名还是返回数据加密,只有破解或模拟其算法,才能构造有效请求、发现后端漏洞。本笔记从实战出发,系统梳理加密算法定位、解密模拟的方法论,以及Sign签名机制的绕过技术,涵盖“扣代码”与“替代库”两种核心策略。
1. 加密算法定位:找到加密入口
定位加密函数是解密的第一步,常用两种方法:
|
方法 |
操作 |
适用场景 |
|
调用堆栈回溯 |
在发起网络请求的XHR断点处,通过调用堆栈向上回溯,寻找加密函数。 |
加密逻辑与请求发送紧密耦合,易找到调用关系。 |
|
关键字全局搜索 |
在Sources面板中搜索请求参数名(如 |
加密函数命名规范或参数名可见。 |
实战步骤:
- 网络面板定位请求:找到包含加密参数(如
param、sign)的请求。 - XHR断点拦截:在Sources面板设置XHR断点(URL包含关键字),刷新页面触发断点。
- 调用堆栈分析:断点处查看Call Stack,从栈顶向下查找,重点关注名称含
encrypt、hash、submit等函数。 - 进入加密函数:点击栈帧进入可疑函数,观察参数和作用域,找到加密逻辑。
2. 解密策略:扣代码 vs 替代库模拟
根据算法复杂度和依赖环境,可选择两种策略:
|
策略 |
原理 |
优点 |
缺点 |
适用场景 |
|
扣代码(JS模拟) |
将加密函数及其依赖的完整代码从浏览器中复制,在Node.js中运行。 |
无需理解算法细节,100%还原。 |
代码可能庞大、依赖Web环境(需模拟DOM)、混淆度高时难以扣全。 |
加密函数独立,无复杂外部依赖(如WebAssembly、Canvas)。 |
|
替代库模拟 |
分析算法类型(AES、RSA、MD5),用Python/Node.js的标准库重新实现。 |
代码简洁、可控,适合自动化集成。 |
需要识别算法类型和参数(key、iv、mode)。 |
算法标准、密钥已知或可逆向提取。 |
3. 请求数据解密实战(扣代码模拟)
场景:登录请求参数password被加密,需模拟加密算法以爆破密码。
步骤:
- 定位加密函数:
-
- 在登录请求处打断点,通过调用堆栈找到处理密码的函数,例如
hidetxtPassword。 - 进入该函数,观察其调用了
encrypt方法,可能位于某个外部JS文件。
- 在登录请求处打断点,通过调用堆栈找到处理密码的函数,例如
- 提取加密代码:
-
- 在Sources面板找到包含加密算法的JS文件,可能是Webpack打包后的文件。
- 将整个文件内容保存为本地
.js文件。若文件过大,可只复制关键函数及其依赖。
- 搭建Node.js运行环境:
-
- 创建新目录,执行
npm init -y初始化。 - 安装必要依赖(如
crypto-js、jsdom等,若需模拟浏览器环境)。 - 将保存的JS文件放入目录,并创建测试脚本
encrypt.js。
- 创建新目录,执行
- 编写调用脚本:
// 假设加密函数为 window.encryptPassword
const fs = require('fs');
// 加载提取的JS代码(如果它依赖全局对象,可能需要模拟)
eval(fs.readFileSync('extracted.js', 'utf8'));
// 调用函数
let encrypted = window.encryptPassword('123456');
console.log(encrypted);
-
- 根据浏览器中断点处的调用方式,在Node.js中调用该函数。
- 如果遇到
window、document未定义,可使用jsdom模拟或修改代码剥离依赖。
- 验证:
-
- 运行脚本,对比浏览器中生成的加密值是否一致。若一致,则扣代码成功。
渗透测试应用:在爆破脚本中调用此加密函数,生成有效加密密码。
4. 返回数据解密实战(替代库模拟)
场景:API返回的数据(如result)是密文,需解密后查看明文内容。
步骤:
- 定位解密函数:
-
- 在返回数据的响应断点处(可在XHR断点命中后,在回调函数中下断),查看调用堆栈,找到处理返回数据的函数。
- 例如,发现
webInstace.shell函数调用了一个解密方法,参数为响应数据。
- 分析算法参数:
-
- 进入解密函数,观察其使用的算法和密钥来源。例如:
-
-
CryptoJS.AES.decrypt(encryptedData, key, { mode: CryptoJS.mode.ECB })- 密钥
key可能是一个常量,或由其他函数生成(如SHA1(secret)取前32位)。
-
- 确定算法类型:
-
- 识别算法(AES、DES、RSA等)和模式(ECB、CBC等)、填充方式。
- 从代码中提取密钥生成逻辑。
- 使用替代库实现:
Python示例(AES-128-ECB):
from Crypto.Cipher import AES
import base64, hashlib
def decrypt(data_b64, key_secret):
# 密钥生成:SHA1(key_secret)[:32]
key = hashlib.sha1(key_secret.encode()).hexdigest()[:32]
cipher = AES.new(key.encode(), AES.MODE_ECB)
encrypted = base64.b64decode(data_b64)
decrypted = cipher.decrypt(encrypted)
# 去除填充(PKCS7)
pad_len = decrypted[-1]
return decrypted[:-pad_len].decode('utf-8')
decrypted = decrypt('encrypted_base64_string', 'secret_constant')
print(decrypted)
-
- 在Python或Node.js中导入对应库,如
pycryptodome(Python)或crypto-js(Node.js)。 - 根据提取的密钥生成逻辑,编写解密函数。
- 在Python或Node.js中导入对应库,如
- 验证:
-
- 用相同密钥和算法解密浏览器中获取的密文,与页面显示明文对比,一致则成功。
渗透测试应用:自动化获取解密后的数据,用于后续攻击(如提取敏感信息、越权测试)。
5. Sign签名机制与绕过实战
Sign机制是保护API接口完整性的常见手段,也是渗透测试中绕不开的“拦路虎”。
5.1 Sign机制概述
Sign是一种基于密钥和算法对请求参数进行哈希或加密生成的校验值,通常附加在请求头或参数中,用于:
- 防篡改:确保请求数据在传输中未被修改。
- 防重放:结合时间戳(timestamp)和随机数(nonce),使同一请求仅一次有效。
- 身份认证:验证请求来源的合法性。
常见算法:MD5、SHA系列、HMAC、AES等。
5.2 Sign对渗透测试的影响
|
影响类型 |
具体表现 |
渗透测试应对策略 |
|
正面影响 |
1. 提高安全性,减少低风险漏洞(如简单重放)。 |
- 需结合逆向工程和动态调试。 |
|
负面影响 |
1. 增加复杂度:逆向混淆代码耗时,动态调试受限。 |
- 掌握JS逆向、HOOK技术。 |
5.3 案例:算法逆向绕过(调用堆栈定位)
目标:某API接口/api/questions/lists,请求头需携带Sign参数。
逆向步骤:
- XHR断点定位:在Sources面板设置XHR断点,关键字
/api/questions/lists,触发请求后断下。 - 调用堆栈回溯:在Call Stack中找到生成
Sign的调用点,发现:
t.headers.Sign = h
h = bs()(o + c + r + n + o)
- 分析bs()和参数值:
-
- 在
bs()处下断点,发现其为MD5算法。 - 各参数值:
- 在
-
-
o:硬编码常量"12b6bb84e093532fb72b4d65fec3f00b"c:从Cookie中提取的值"dbbc7981-906b-45c5-8102-edf02376f9c4"r:当前URL去掉/api后的路径"/questions/lists"n:当前时间戳(new Date).getTime()
-
- 验证签名生成:在控制台手动计算:
crypto.MD5(o + c + r + n + o).toString()
与请求头中的Sign对比,一致。
- 编写Python脚本自动化:用
hashlib.md5复现,在Burp Intruder中调用外部脚本生成签名,实现爆破。
绕过思路:
- 若签名仅依赖客户端可控参数(如时间戳、固定密钥),则可在本地完全模拟。
- 若密钥硬编码在JS中,可直接提取。
6. 工具与辅助技巧
|
工具/技术 |
用途 |
说明 |
|
AI助手(如ChatGPT) |
辅助分析混淆代码、生成解密脚本 |
将加密函数或算法描述提供给AI,可快速生成对应语言实现。 |
|
JsRPC |
远程调用浏览器中的加密函数 |
在浏览器中注入RPC服务,Python脚本通过WebSocket实时调用加密函数,无需扣代码。 |
|
Yakit热加载 |
在Burp中动态执行JS解密 |
编写Yakit插件,将解密函数加载到Burp中,自动解密请求/响应数据。 |
|
AutoDecode |
Burp插件,自动调用JS解密 |
配置解密函数后,自动对匹配的请求/响应进行解码。 |
|
浏览器本地替换 |
修改JS代码并保存,测试效果 |
在Sources面板修改加密函数,右键选择“Save for overrides”,可永久替换本地代码。 |
7. 总结:Sign绕过方法论
|
步骤 |
关键操作 |
技巧 |
|
1. 定位签名生成点 |
XHR断点、全局搜索关键字( |
优先使用XHR断点,快速定位到请求发起位置。 |
|
2. 分析签名参数 |
查看作用域中的变量值,确定哪些参数参与签名。 |
关注时间戳、随机数、路径、Cookie、固定密钥等。 |
|
3. 提取算法和密钥 |
单步调试进入加密函数,识别算法类型;若密钥硬编码,直接复制。 |
若算法被混淆,可借助AI还原逻辑。 |
|
4. 本地复现签名 |
用Python/Node.js实现相同算法,并测试与浏览器生成的签名是否一致。 |
若依赖浏览器环境(如 |
|
5. 集成到测试工具 |
在Burp中调用外部脚本(如Python脚本)生成签名,或使用Yakit热加载。 |
确保每次请求都附带有效签名,从而进行后续测试(如注入、越权)。 |
8. 学习建议
|
阶段 |
核心技能 |
目标 |
|
定位 |
熟练使用F12断点、调用堆栈、搜索 |
快速找到加密/解密函数入口。 |
|
提取 |
扣代码技巧(复制依赖、模拟环境) |
获取完整的可执行加密逻辑。 |
|
模拟 |
算法识别、标准库使用 |
用Python/Node.js实现相同功能,便于自动化。 |
|
集成 |
JsRPC、Burp插件、Yakit |
将解密能力无缝融入渗透测试流程。 |
核心思想:签名机制虽增加了测试门槛,但一旦破解,即可完全模拟客户端行为,进而深入测试服务端漏洞。始终记住:签名保护的只是传输完整性,而非业务安全本身。掌握这些技巧,你将能突破前端加密屏障,更深入地测试后端安全,发现更多逻辑漏洞。

更多推荐
所有评论(0)