逆向思维:从CryptoJS加密到Burp联动——实战解析前端自定义加密的爆破新思路
逆向思维:从CryptoJS加密到Burp联动——实战解析前端自定义加密的爆破新思路
在Web安全测试中,前端加密逻辑往往成为阻碍传统爆破手段的"绊脚石"。当遇到采用CryptoJS等库实现的自定义加密时,单纯依赖Burp Suite内置的编码功能往往力不从心。本文将从一个真实案例出发,通过逆向思维拆解加密流程,并探索超越jsEncrypter插件的多维度解决方案。
1. 前端加密机制深度解析
现代Web应用普遍采用前端加密来提升数据传输安全性,其中CryptoJS是最常见的JavaScript加密库之一。其典型加密流程通常包含以下核心步骤:
// 示例:CryptoJS的Base64编码流程 var words = CryptoJS.enc.Utf8.parse(plainText); // 将明文转换为WordArray对象 var encrypted = CryptoJS.enc.Base64.stringify(words); // 进行Base64编码关键点在于识别加密函数的调用链。通过Chrome DevTools的调试功能,我们可以:
- 在Network面板定位登录请求
- 通过Call Stack回溯加密函数调用路径
- 在Sources面板设置断点观察参数变化
注意:现代前端框架可能对加密逻辑进行了多层封装,需要耐心追踪实际执行代码。
下表对比了常见前端加密方式的识别特征:
| 加密类型 | 典型特征 | 识别难度 |
|---|---|---|
| Base64 | 结尾常带=号,字符集固定 | ★☆☆☆☆ |
| AES | 包含CryptoJS.AES.encrypt调用 | ★★☆☆☆ |
| RSA | 出现setPublicKey等密钥操作 | ★★★☆☆ |
| 自定义算法 | 混合多种加密方式,无标准特征 | ★★★★☆ |
2. 传统解决方案:jsEncrypter的实战与局限
jsEncrypter作为Burp Suite的经典插件,其工作原理是通过PhantomJS建立本地JS执行环境。典型配置流程包括:
- 下载目标站点的加密JS文件(如crypto-js.js)
- 修改phantomjs_server.js引入加密逻辑:
var fs = require('fs'); var cryptoJs = fs.absolute('crypto-js.js'); load(cryptoJs); function js_encrypt(payload){ // 在此处实现与前端一致的加密逻辑 return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(payload)); }- 启动PhantomJS服务:
phantomjs phantomjs_server.js然而,这种方案存在明显局限性:
- 性能瓶颈:每个请求都需要与PhantomJS进程通信
- 环境差异:Node.js与浏览器环境可能存在兼容性问题
- 调试困难:错误信息往往不够直观
3. 突破性思路:纯Python加密模拟方案
为克服jsEncrypter的局限,我们可以用Python直接实现加密逻辑。以PyCryptodome库为例:
from base64 import b64encode from Crypto.Util.Padding import pad def custom_encrypt(plaintext): # 模拟CryptoJS.enc.Utf8.parse utf8_bytes = plaintext.encode('utf-8') # 模拟CryptoJS.enc.Base64.stringify return b64encode(utf8_bytes).decode('ascii')将此方案集成到Burp中可通过两种方式:
- 使用Burp API编写自定义插件:
IExtensionHelpers helpers = BurpExtender.callbacks.getHelpers(); String encrypted = PythonExecutor.encrypt(plaintext); byte[] request = helpers.buildHttpMessage(headers, helpers.stringToBytes(encrypted));- 通过外部代理中转:
# 启动Python加密服务 python3 encrypt_proxy.py --port 8081 # 配置Burp将请求转发到代理4. 高级技巧:动态Hook与实时调试
对于更复杂的加密场景,可采用动态Hook技术。以Frida框架为例:
Interceptor.attach(Module.findExportByName("crypto-js.js", "encrypt"), { onEnter: function(args) { console.log("加密输入: " + Memory.readUtf8String(args[0])); }, onLeave: function(retval) { console.log("加密输出: " + Memory.readUtf8String(retval)); } });结合浏览器自动化工具如Puppeteer,可实现全自动化的加密分析:
const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://target.com/login'); // 在加密函数处注入调试代码 await page.evaluate(() => { window.debugEncrypt = function(plain) { return originalEncryptFunction(plain); }; }); // 获取加密结果 const encrypted = await page.evaluate(p => window.debugEncrypt(p), 'test123'); console.log(encrypted); await browser.close(); })();5. 防御视角:如何提升前端加密安全性
从开发者的角度,强化前端加密可采取以下措施:
- 混淆关键代码:
// 原始代码 function encrypt(pwd){return CryptoJS.AES.encrypt(pwd, key)} // 混淆后 var _0xad3b=[/*...*/];function _0x3827(_0x12d4f3,_0x58a38d){/*...*/}- 环境检测:
if(!window.crypto || !window.crypto.subtle){ // 检测到非浏览器环境 return false; }- 动态密钥生成:
function getDynamicKey(){ let ts = Math.floor(Date.now()/1000); return CryptoJS.SHA256(navigator.userAgent + ts).toString(); }在实际项目中,我曾遇到一个巧妙的反调试案例:加密函数会在检测到DevTools时返回假数据,解决方案是在页面加载完成前打开调试工具。这种攻防对抗的细节往往决定了测试的成败。
