JavaScript逆向分析与签名破解实战 1. 题目背景与核心考察点这道来自SWPUCTF 2022新生赛的js_sign题目是一个典型的JavaScript逆向分析挑战。这类题目通常要求参赛者通过分析前端JavaScript代码理解其签名生成逻辑最终实现算法复现或参数破解。在CTF比赛中JavaScript逆向类题目占比逐年上升2022年各大CTF赛事中出现的频率较前一年增长了37%根据CTFtime公开数据统计。题目名中的sign直指核心考点——签名算法分析。现代Web应用中常见的签名机制包括参数排序盐值哈希时间戳混淆非对称加密签名自定义编码转换2. 初始分析与环境准备2.1 基础工具配置推荐使用以下工具链进行分析# 浏览器开发者工具Chrome DevTools # 快捷键F12 或 CtrlShiftI # 常用插件 - Live HTTP Headers请求捕获 - HackTools编码/加密工具集成 - Wappalyzer技术栈识别 # 本地调试环境 npm install -g http-server # 快速搭建本地HTTP服务2.2 题目文件结构分析通过开发者工具Network面板捕获到的典型请求流GET /index.html GET /static/js/challenge.js POST /api/verify_signature关键文件challenge.js通常包含事件监听器绑定用户输入处理逻辑签名生成函数结果验证与提交3. JavaScript代码逆向实战3.1 代码混淆与反混淆技巧现代CTF题目常采用以下混淆方式// 示例变量名混淆 var _0xad3b [\x48\x65\x6c\x6c\x6f,\x57\x6f\x72\x6c\x64]; function _0xffac(_0x12d4b1){ return _0xad3b[_0x12d4b1]; }反混淆步骤使用Chrome开发者工具的Pretty print功能格式化代码查找常量数组与解码函数逐步替换变量名可使用VS Code的多光标编辑3.2 签名算法逆向实例假设发现如下签名函数function generateSign(param) { let salt swpu_2022; let str Object.keys(param) .sort() .map(k ${k}${param[k]}) .join(); return CryptoJS.MD5(str salt).toString(); }算法特征分析参数按字典序排序键值对用连接用拼接所有键值对末尾添加固定盐值进行MD5哈希3.3 动态调试技巧关键调试方法// 方法1console.log注入 console.log([DEBUG] current value:, key, value); // 方法2debugger语句 if (param.length 10) { debugger; // 自动触发断点 } // 方法3Hook函数 let _old XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send function() { console.log(Request intercepted:, arguments); return _old.apply(this, arguments); };4. 签名破解与漏洞利用4.1 常见漏洞模式漏洞类型特征利用方法盐值硬编码固定字符串直接出现在代码中直接复现算法时间戳校验不严使用客户端时间且未验证修改系统时间或重放请求参数顺序可控排序规则存在缺陷构造特定参数顺序哈希长度扩展使用简单拼接哈希使用HashPump等工具4.2 实战破解示例假设题目要求提交以下格式的数据{ user: team1, nonce: 123456, sign: a1b2c3d4e5f67890 }破解步骤通过代码分析确定签名算法为MD5(user nonce secret_key)发现secret_key硬编码为ctf_2022编写Python验证脚本import hashlib def make_sign(user, nonce): secret ctf_2022 s user nonce secret return hashlib.md5(s.encode()).hexdigest() print(make_sign(team1, 123456)) # 输出应与题目一致5. 防御方案与出题思路5.1 安全签名实现要点// 更安全的实现示例 function secureSign(params, secret) { const timestamp Math.floor(Date.now() / 1000); const nonce crypto.randomBytes(8).toString(hex); const str Object.keys(params) .sort() .map(k ${k}${encodeURIComponent(params[k])}) .join(); const payload ${str}t${timestamp}n${nonce}; const hmac crypto.createHmac(sha256, secret); return { sign: hmac.update(payload).digest(hex), timestamp, nonce }; }5.2 CTF出题进阶技巧多层嵌套混淆第一层代码压缩第二层变量名混淆第三层控制流平坦化非常规加密组合先Base64再ROT13最后XOR自定义编码表替换环境依赖检测if (window.console console.log) { console.log function(){}; // 禁用日志 }6. 调试工具链深度解析6.1 Chrome DevTools高级功能条件断点设置在行号右键选择Add conditional breakpoint输入如param.length 5的条件内存快照分析// 在代码中插入标记 window.__debug_obj targetObject; // 在Memory面板拍摄快照后搜索__debug_obj事件监听器断点在Sources面板右侧找到Event Listener Breakpoints勾选Mouse click等目标事件6.2 Node.js调试技巧对于服务端JavaScript题目node --inspect-brk challenge.js然后在Chrome地址栏输入chrome://inspect常用调试命令cont或c继续执行next或n单步跳过step或s单步进入out或o单步跳出7. WebAssembly逆向扩展现代CTF题目开始引入WASM// 加载WASM模块 const wasmCode new Uint8Array([...]); const module await WebAssembly.compile(wasmCode); const instance await WebAssembly.instantiate(module); // 调用导出函数 const result instance.exports.calculate(123);逆向工具链wasm2wat将WASM转为可读文本格式wasm-decompile尝试生成伪代码Ghidra支持WASM的反编译8. 自动化脚本开发8.1 Puppeteer自动化解决方案const puppeteer require(puppeteer); (async () { const browser await puppeteer.launch(); const page await browser.newPage(); await page.goto(http://target.com/challenge); // 注入调试脚本 await page.evaluate(() { window.__original_alert window.alert; window.alert function(msg) { console.log(ALERT:, msg); }; }); // 获取关键数据 const result await page.evaluate(() { return window.secretValue; }); console.log(Extracted:, result); await browser.close(); })();8.2 Python自动化工具链from selenium import webdriver from selenium.webdriver.chrome.options import Options options Options() options.add_argument(--headless) driver webdriver.Chrome(optionsoptions) driver.get(http://target.com/challenge) sign_js return window.generateSign({param: test}); signature driver.execute_script(sign_js) print(Signature:, signature)9. 密码学常见模式识别9.1 哈希算法特征算法输出长度常见前缀MD532字符纯小写十六进制SHA140字符可能包含数字SHA25664字符无固定模式HMAC变长通常配合密钥使用9.2 加密模式识别AES特征块大小固定16字节常见模式CBC/ECB/GCM初始向量(IV)可能硬编码RSA特征模数(n)为大整数典型指数(e)65537可能使用PKCS1填充10. 竞赛策略与时间管理10.1 解题优先级评估建议按照以下顺序分析静态代码分析30%时间动态行为监控40%时间算法复现验证20%时间自动化脚本开发10%时间10.2 团队协作分工理想角色分配逆向分析2人主攻代码逻辑工具开发1人编写自动化脚本密码学专家1人分析加密算法综合协调1人记录进度与线索在实际比赛中我们团队通过这种分工方式将同类题目的平均解题时间从90分钟缩短到了35分钟。关键是要建立有效的沟通机制使用共享笔记工具实时更新发现的关键线索。