从古埃及象形文字加密(公元前2000年)到二战恩尼格玛机的机械密码,人类对信息安全的探索跨越了数千年。1949年,香农(Claude Shannon)在《保密系统的通信理论》中奠定现代密码学基础,而1976年Diffie-Hellman密钥交换协议与RSA算法的诞生,则标志着非对称加密技术的成熟。至此,现代密码学形成三大支柱:非对称加密、对称加密与哈希算法,三者常以组合形态构建多层安全体系,例如通过RSA传输AES密钥,再以SHA-256验证数据完整性。
中国自主研发的国密算法(SM系列)通过国家密码管理局认证,形成涵盖加密、签名、认证的全栈技术体系:
SM2(非对称):基于椭圆曲线密码学(ECC),用于数字签名与密钥交换,密钥长度仅需256位即可达到RSA 3072位的安全强度。
SM3(哈希):生成256位消息摘要,应用于区块链数据完整性验证。
SM4(对称):采用Feistel结构,支持128位分组加密,在物联网设备中实现低功耗高效加密。
国密算法已经在诸多行业领域进行应用,如金融领域、电子政务、物联网安全等等。如网上银行通过SM2实现交易签名(如转账金额哈希值计算),SM4加密传输支付数据,SM3验证交易报文完整性。
拆分技术栈来看,在Web前端安全方面,国密算法已经通过技术适配与生态融合渗透入JS程序方方面面,JS代码使用加密算法实现对数据、角色、权限等的全方位保护已成为业界常态。
而在红蓝对抗实战中,JS加密构建的防护屏障既是技术筛选器,也是攻防博弈的「双刃剑」。
当红队开启BurpSuite监听流量时,满屏的加密报文往往让大多数人望而却步。数据显示,约68%的初级攻击者在此阶段选择放弃,剩余攻坚者需面对三重核心挑战:加密流量解析、动态密钥拦截和加密环境依赖机制。
但自研算法的破解、密钥保管不当、逻辑混淆不完善,都可能造成成熟的攻击者通过AST语法树特征提取定位加密核心(如识别CryptoJS.AES.encrypt调用模式),例如某金融应用案例,攻击者通过还原RSA-OAEP加密逻辑,继续开展高频撞库攻击。此时,对防护者来说,这边就开始存在一个悖论。当算法被逆向破解,原本的安全屏障将转化为攻击通道,如某政务系统因SM4密钥硬编码泄露,导致公民信息遭拖库,而大多数防护设备仅仅对加密流量的加密格式进行校验,而非内容语义,则带有攻击载荷的报文可直接穿透规则库检测。
本文的出发点是基于红队人员分析JS加密算法工作,使用DeepSeek等AI大模型,助力寻找加密模式与密钥,进行伪造流量,从而Bypass防护体系,进而也赋能防守团队。
文末有惊喜哦,分析工具已经先一步发布啦!
【注意】
本文所述技术方案均为网络安全领域的学术探讨,旨在促进防御体系的技术演进,严禁任何形式的非法利用。作者及研究团队:
1. 不提供、不支持、不鼓励将文中方法用于未授权测试或攻击行为
2. 不承担因技术误用导致的任何法律及道德责任
3. 不公开任何可能降低攻击门槛的模型细节(如exploit生成模块的奖励函数设计)相关技术实施应严格遵守《网络安全法》《数据安全法》及所在国法律法规,建议在隔离测试环境中验证学术猜想。
4. 技术锋芒的指向应是加固系统而非突破防线——这是所有安全研究者不可逾越的伦理基线。
01
认识常见加密算法
加密算法的演变是人类对抗信息泄露、追求通信安全的缩影,其发展可分为古典密码与现代密码两大阶段,技术核心从语言学模式转向数学难题驱动。
篇幅有限,我们仅简单叙述古典密码部分。古典密码的核心是“置换”,比如凯撒密码(公元前1世纪):将明文字母按固定位数偏移(如右移3位),例如,“HELLO”加密为“KHOOR”,存在缺陷明显:密钥空间仅25种可能,易被频率分析破解。因此古典加密就有明显的局限性,极度依赖算法保密性,一旦泄露即失效,而基于暴力破解和数学规律统计方面,也非常脆弱。(下图即凯撒密码的明密文转换规则)
而在20世纪中叶,克劳德·香农在《通信的数学理论》中提出信息熵与完美保密性概念,标志着密码学从语言学艺术转向数学科学。现代密码体系建立在三大数学支柱之上:
计算复杂性理论:将安全性归结为NP困难问题(如大数分解、离散对数)。
概率论与统计学:设计抗频率分析的混淆机制(如AES的S盒非线性变换)。
抽象代数:构建有限域运算(如SM4的32轮迭代结构)与椭圆曲线代数系统。
于是,逐渐衍生出了当今重要的三类加密算法:非对称加密、对称加密以及哈希算法。这三类算法在现实场景中也往往组合起来使用,以发挥最佳效果。下文逐一介绍。
对称加密以高效性著称,但其核心挑战在于密钥分发与模式选择。主要分为流加密和分组加密两种类型,下表是两种类型的架构对比
DES到AES是对称加密算法的两个杰出代表,也代表对称加密的两个发展阶段,以下是从DES到AES的技术跃迁
DES的Feistel架构剖析:
初始置换(IP):通过58位置换表打乱输入块,消除明文的统计特征。
16轮Feistel迭代:每轮将64位分为左右32位,右半部分经扩展置换(E盒)、S盒代换、P盒置换后与左半异或。
致命缺陷:56位密钥空间被1998年EFF的Deep Crack机器23小时暴力破解。
AES的SPN结构革新:
状态矩阵(State):将128位明文转换为4×4字节矩阵,实现并行处理。
四大核心操作:
SubBytes:通过GF(2⁸)有限域的乘法逆元+S盒仿射变换实现非线性混淆。
ShiftRows:矩阵行循环移位,打破字节纵向关联。
MixColumns:列混合通过多项式乘法实现扩散(最后一轮省略)。
AddRoundKey:轮密钥异或操作引入密钥依赖性。
抗攻击能力:对差分攻击免疫度达2⁻¹⁵⁰,远超DES的2⁻⁴⁷。
而对称加密不只是从算法来保证信息安全,还通过不同加密模式来适配不同风险要求、使用场景,加密模式可以说是安全边界的决定性因素,加密模式主要有ECB、CBC、PCBC、CFB、OFB、CTR六种,少侠们如果有兴趣也可以继续了解。
对称加密算法解决了数据加密的问题。以AES加密为例,在现实世界中,小明要向路人甲发送一个加密文件,他可以先生成一个AES密钥,对文件进行加密,然后把加密文件发送给对方。因为对方要解密,就必须需要小明生成的密钥。
现在问题来了:如何传递密钥?
在不安全的信道上传递加密文件是没有问题的,因为黑客拿到加密文件没有用。但是,如何如何在不安全的信道上安全地传输密钥?要解决这个问题,密钥交换算法即DH算法:Diffie-Hellman算法应运而生。这里我们不对DH算法进行详解,只需要知道,DH算法就是典型的非对称加密算法。
非对称加密算法与对称加密算法的最大区别在于加密密钥和解密密钥不再相同。这种加密方式主要适用于 “多个加密者,一个解密者” 的模式,解决了对称密钥只能处理一对一解密用户关系的局限。在这种多对一的关系中,出现了公钥体系,即一个公钥对应一个私钥。公钥是公开的,任何数据发送者都可以使用公钥对数据进行加密,但只有对应的私钥才能解密公钥加密的内容。著名的非对称加密算法包括 DSA 算法、RSA 算法、Elgamal 算法、背包算法、Rabin 算法、D - H 算法、ECC 算法等,其背后涉及从大数分解到复杂的椭圆曲线上的离散对数问题等复杂数学原理。尽管不同算法的数学支撑不同,但模式相似,均采用公私钥密钥对的方式,公钥可解密私钥加密的信息,私钥可解密公钥加密的信息。
然而,非对称加密算法的执行效率较低,这成为其实际应用中的最大阻碍。因此,大部分应用主要将非对称加密算法用于身份验证,而非在通讯中使用。
哈希算法用于验证数据是否被篡改,与前两者不同。它将任意长度原文转为固定长度字符串,且只能加密不能解密,不同输入理论上对应不同输出。常见的有 MD5、SHA - 1 及 SHA 224/256/512 等算法。不过,MD5 和 SHA - 1 已被证明不安全,目前推荐使用 SHA256/512 等安全性高的算法。
因此在现代加密算法中,对称加密高效,非对称加密革新公钥体系,哈希算法守护数据完整性,它们各司其职又相互协作。
国密算法体系:中国自主密码标准
为摆脱对国际算法的依赖,中国推出自主可控的国密算法(GM/T),覆盖对称加密、非对称加密、哈希及流密码,成为国家信息安全战略的核心技术。主要有以下类型:
02
JS代码保护技术
在讲JavaScript(JS)所使用的加密算法之前,先介绍常见的JS保护技术,因为读懂JS代码才是寻找和识别加密算法的基础。
JS代码保护技术旨在保护代码的安全性和隐私性,防止代码被恶意篡改、逆向工程或未经授权的访问。以下是一些常见的JS加密技术。
1. 代码混淆
代码混淆是一种通过改变代码的结构和语法,而不改变其功能的方式来保护代码。混淆后的代码难以阅读和理解,增加了逆向工程的难度。如使用UglifyJS进行代码混淆,UglifyJS是一个流行的JavaScript压缩和混淆工具。
# 安装UglifyJSnpm install uglify-js -g# 假设我们有一个名为example.js的文件# 原始代码 example.jsfunctionadd(a, b){return a + b;}console.log(add(1, 2));# 使用UglifyJS进行混淆uglifyjs example.js -o example.min.js
混淆后的代码如下:
2. 代码加密
代码加密是将代码转换为密文,只有在运行时才解密执行。如简单的Base64编码:
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
3. 动态加载与懒加载
动态加载和懒加载技术可以减少初始加载的代码量,同时增加代码的安全性。通过在需要时动态加载代码,可以避免一次性暴露所有代码。如一下html代码中,根据功能场景动态加载JS脚本:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
4. 运行时加密
运行时加密是在代码运行时对关键部分进行加密和解密,增加代码的安全性。如下列运行时加密函数
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
5. 沙箱环境
沙箱环境是一种隔离的执行环境,用于限制代码的访问权限,防止恶意代码对系统造成损害。如使用iframe创建沙箱环境
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>JavaScript Sandbox</title></head><body><iframeid="sandbox"sandbox="allow-scripts"></iframe><script>const sandbox = document.getElementById('sandbox');const scriptCode = `function sandboxFunction() { console.log('This is a sandbox function.'); } sandboxFunction();`;const doc = sandbox.contentDocument || sandbox.contentWindow.document; doc.open(); doc.write(`<script>${scriptCode}</script>`); doc.close();</script></body></html>
关键代码为:<iframe id="sandbox" sandbox="allow-scripts"></iframe>。这里创建了一个 <iframe> 元素,并为其设置了 id 为 sandbox。sandbox 属性是关键,它将这个 <iframe> 变成了一个沙箱环境。allow-scripts 是 sandbox 属性的一个值,表示允许在这个沙箱中运行脚本。如果不设置这个值,默认情况下沙箱内的脚本是被禁止运行的。sandbox 属性可以接受多个值,每个值代表一种权限设置,多个值之间用空格分隔。常见的值如下:
allow-scripts:允许在沙箱中运行脚本。
allow-same-origin:允许沙箱内的文档与外部文档具有相同的源,这样沙箱内的代码就可以访问一些同源的资源。
allow-forms:允许在沙箱中提交表单。
allow-popups:允许在沙箱中打开新窗口。
通过合理组合这些值,可以根据具体需求精确控制沙箱的权限,确保代码在安全的环境中运行。
需要注意的是,虽然以上技术可以增加代码的安全性,但并不能完全防止代码被逆向工程。在实际应用中,应结合多种安全措施来保护代码。
03
JS代码使用加密算法介绍
以下是针对 JavaScript 中常用加密算法的详细介绍及实现示例,涵盖 AES、RSA 和国密算法(SM2/SM3/SM4)。
AES算法使用
示例代码如下,可直接在Node环境中运行:
const crypto = require('crypto');// AES-256-CBC 加密functionencryptAES(text, key, iv) {const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);let encrypted = cipher.update(text, 'utf8', 'base64'); encrypted += cipher.final('base64');return encrypted;}// AES-256-CBC 解密functiondecryptAES(encryptedText, key, iv) {const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);let decrypted = decipher.update(encryptedText, 'base64', 'utf8'); decrypted += decipher.final('utf8');return decrypted;}// 示例用法const key = crypto.randomBytes(32); // 256位密钥const iv = crypto.randomBytes(16); // 16字节 IVconst plainText = 'Hello AES!';const encrypted = encryptAES(plainText, key, iv);const decrypted = decryptAES(encrypted, key, iv);console.log('AES 加密结果:', encrypted);console.log('AES 解密结果:', decrypted);
RSA加密使用
先安装依赖:npm install node-forge
尝试生成密钥对:
const forge = require('node-forge');// 生成一个RSA密钥对const keypair = forge.pki.rsa.generateKeyPair({bits: 2048});console.log('Public Key: ', keypair.publicKey);console.log('Private Key: ', keypair.privateKey);
示例代码如下,可直接在Node环境中运行:
const forge = require('node-forge');// 1. 生成密钥对functiongenerateKeyPair() {const keyPair = forge.pki.rsa.generateKeyPair({ bits: 2048 });return {publicKey: forge.pki.publicKeyToPem(keyPair.publicKey) .replace(/rn/g, 'n'), // 统一换行符 privateKey: forge.pki.privateKeyToPem(keyPair.privateKey) .replace(/rn/g, 'n') };}// 2. 加密functionencryptRSA(text, publicKeyPem) {const publicKey = forge.pki.publicKeyFromPem(publicKeyPem);// 使用 forge.util.encodeUtf8 处理中文字符const buffer = forge.util.createBuffer(forge.util.encodeUtf8(text));const encrypted = publicKey.encrypt(buffer.getBytes(), 'RSA-OAEP');return forge.util.encode64(encrypted); // 直接使用 forge 的 Base64 编码}// 3. 解密functiondecryptRSA(encryptedBase64, privateKeyPem) {const privateKey = forge.pki.privateKeyFromPem(privateKeyPem);const decoded = forge.util.decode64(encryptedBase64);return privateKey.decrypt(decoded, 'RSA-OAEP');}// 4. 示例运行const { publicKey, privateKey } = generateKeyPair();const originalText = 'Hello RSA!';// 加密const encrypted = encryptRSA(originalText, publicKey);console.log('加密结果:', encrypted);// 解密const decrypted = decryptRSA(encrypted, privateKey);console.log('解密结果:', decrypted);
SM2(非对称加密)
先安装依赖:npm install sm-crypto
示例代码为:
const sm2 = require('sm-crypto').sm2;// 生成 SM2 密钥对const keyPair = sm2.generateKeyPairHex();const publicKey = keyPair.publicKey; // 04 开头公钥const privateKey = keyPair.privateKey;// 加密const encryptSM2 = (text) => sm2.doEncrypt(text, publicKey);// 解密const decryptSM2 = (cipherText) => sm2.doDecrypt(cipherText, privateKey);// 示例用法const text = 'Hello SM2!';const encrypted = encryptSM2(text);const decrypted = decryptSM2(encrypted);console.log('SM2 加密结果:', encrypted);console.log('SM2 解密结果:', decrypted);
SM3(哈希算法)
示例代码为:
混淆后的代码如下:
0
SM4(对称加密)
示例代码为:
混淆后的代码如下:
1
04
识别JS使用的加密算法
俗话说,巧妇难为无米之炊,所以识别JS使用的加密算法,少侠们要先明确当前网站JS代码在哪里,是否使用JS加密,以及加密算法具体在哪里。
JS代码在哪里
如果直接将完整JS代码进行使用,就跳过这部分。
这里介绍主流的集中 JS 打包工具及特征:
比较常见的是Webpack,入口文件包含 __webpack_require__ 函数,模块代码包裹在函数中,带数字 ID:(function(module, exports, __webpack_require__) { ... }),一般包含 webpackJsonp 或 webpackChunk 标识。打包文件后,通常生成 main.[hash].js 和多个 chunk.[hash].js
Rollup,代码更简洁,无模块加载器,使用 import/export 语法保留(若未压缩),常见 rollup-plugin 生成的注释,打包文件中单文件居多(如 bundle.js)
Parcel,可以自动生成 parcelRequire 函数,模块路径保留为相对路径,文件中包含 //# sourceMappingURL= 注释,一般打包文件结果为多文件 + .map 文件。
Vite (基于 Rollup/Esbuild),开发环境使用原生 ES Module (<script type="module">),生产构建后代码结构与 Rollup 类似,包含 __vite__map 或 __VITE_ASSET__ 标记。打包文件为assets/index.[hash].js。
Browserify,会使用 require 函数加载模块,模块包裹在 (function e(t, n, r) { ... }) 结构中。打包文件为单文件 bundle.js。
是否使用JS加密
直接获取到JS或者通过找到打包方法对应找到JS代码,就可以进行第二阶段分析
事实上,在抓包中直接发现数据加密,这是最直观的体现(PS:不影响抓包改包的加密,关注它干嘛hhh)。
如果想提前判断网站是否使用JS加密,可以结合上文提到,通常使用加密的站点,JS中会使用crypto-js、sm-crypto等库,那我们就可以通过使用Wappalyzer识别JS库,进而找到使用加密手段传输数据的站点目标。
也可使用Burpsuite Intruder功能配合插件批量扫描JS文件,其中启用HaE插件:https://github.com/gh0stkey/HaE
设置扫描条件,比如
混淆后的代码如下:
2
加密算法在哪里
通过关键字,对应也可以解决加密算法在哪里的问题。
但具体情况具体分析,比如结合抓包时的场景,F12寻找源码分析,找到控制输入输出的函数,再通过关键词进行定位。
篇幅有限,这里不做过多展开了。
实例分析
下面结合实例来进行分析。遇到某个站点,输入用户名密码admin:123456,发现被加密:
众所周知,在不知道加密规则的情况下,是无法进行爆破的。
而在首页html中,发现直接将加密算法写于其中:
通过命名发现疑似使用国密算法sm3和sm4,同时查看源代码,发现使用国密算法,sm3为哈希算法,sm4为对称加密算法:
接下来对该加密函数进行分析:
首先,代码中生成动态种子,nowDate = "cari" + new Date().getTime(),生成一个包含时间戳的字符串,如 cari1672531200000,确保每次加密的密钥不同,防止重放攻击。
接着,sm3HashHex = sm3(nowDate),使用 SM3 哈希算法(国密算法)对 nowDate 做哈希,输出 64位十六进制字符串(256位二进制)。
然后,定义密钥(Key)与 IV ,基于SM3哈希算法的64位十六进制字符串生成,可以看到都是32位十六进制字符,也就是128位,符合SM4算法此时的要求
混淆后的代码如下:
3
继而,通过SM4算法、CBC模式进行对称加密,使用CBC模式也是IV参数之所以需要生成和配置的原因。并且值得关注的是,SM4默认 PKCS#7进行填充。
最后,返回数组:[nowDate, encryptedUsername, encryptedPassword],其中nowDate用于服务端还原密钥和 IV。encryptedUsername/encryptedPassword:SM4-CBC 密文(Base64 或十六进制格式,依赖库实现)。
将nowDate与burpsuite抓包数据进行对齐,再次加密,密文一样(没理由不一样)
接着就可以通过python写脚本,利用加密算法生成用户名和密码的密文,进行爆破。也可直接生成指定nowDate的用户名和密码的密文,使用burpsuite直接进行爆破。
这里我采用前者简单一试。
加密算法的Python实现脚本如下:
混淆后的代码如下:
4
Nice,现在封装一下,发送请求,并集成入弱口令字典:
混淆后的代码如下:
5
为了检验有效性,先发送错误的newDate和用户名密码的组合,发现是500响应:
使用现有脚本,批量发送请求后,成功开始批量测试:
AST(抽象语法树,Abstract Syntax Tree)
事实上,更加复杂的加密场景非常多,主要是因为经历了JS打包、代码加密混淆等流程,这种时候最关键的就是理出抽象语法树,即AST。
抽象语法树(Abstract Syntax Tree) 是源代码的 结构化表示 ,将代码从字符序列(如 if (x > 0) { x++; } )转换为树形数据结构,每个节点代表语法元素(如条件语句、变量声明等)。
主流语言 AST 工具生态
语言 | 解析器/工具 |
JavaScript | Esprima, Acorn, Babel, TypeScript Compiler API |
Python | ast, astparse, pylint |
Java | ANTLR, JavaParser |
Go | go/parser, go/ast |
以 JavaScript 为例,解析源码生成 AST
使用Esprima或Acorn等解析器:
混淆后的代码如下:
6
遍历 AST(深度优先),通过递归或迭代器访问节点:
混淆后的代码如下:
7
修改 AST,使用Babel或AST Transform库改造节点:
混淆后的代码如下:
8
生成新代码,将修改后的 AST 转换回源码:
混淆后的代码如下:
9
相关资源如下,通过掌握 AST 技术,可以解锁少侠们的代码自动化处理的强大能力,显著提升审计效率:
AST Explorer(在线可视化编辑 AST) https://astexplorer.net/
书籍:《Parsing Techniques: A Practical Guide》(第二版)
视频课程:Frontend Masters 的《ASTs and Parser Generators》
05
DeepSeek赋能解构JS算法
DeepSeek本身能赋能很多方面,比如算法识别、密钥寻找、环境依赖分析,事实上对于一些自定义函数的逆向分析也能进行发力,比如一些对称加密函数复杂的P盒、S盒的寻找,以解析自定义加密算法核心逻辑,因作者这方面案例积累尚浅,后续再进行文章补足。
接下来主要讲解DeepSeek在JS加密算法细节洞悉方面的能力体现。
实现一:加密算法识别
技术要素一:AST语法树特征提取
利用DeepSeek解析JS代码生成抽象语法树(AST),训练模型识别常见加密库特征(如CryptoJS.AES.encrypt
、sm4.encrypt
)。比如检测到sm4.encrypt
调用时,自动标记为国密SM4算法,并提取密钥生成逻辑(如动态种子nowDate
)
如针对上方示例中的代码,直接让DeepSeek进行分析
生成结果如下:
步骤1:解析代码生成AST,使用JavaScript解析器(如Babel)将代码转换为AST:
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
0
步骤2:遍历AST检测加密函数调用,识别sm4.encrypt
等特定调用:
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
1
步骤3:提取密钥生成逻辑,分析变量赋值和条件语句,提取动态密钥生成逻辑:
提取keyText
和ivText
的赋值逻辑
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
2
步骤4:识别动态种子(如nowDate
),跟踪nowDate
的生成,识别时间戳动态生成:
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
3
针对示例代码的分析结果:
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
4
关键AST特征如下:
加密函数调用:
MemberExpression
匹配sm4.encrypt
。参数分析:
第二参数为密钥(
keyText
),追踪其变量赋值链。第三参数中的
iv
属性,提取其值来源。
条件分支:检测if (sm3HashHex.length > 32)
中的密钥分割逻辑。
动态值:识别new Date().getTime()
和字符串拼接操作。
技术要素二:动态执行路径追踪
模拟JavaScript执行环境,跟踪加密函数从参数生成到最终调用的完整链路,解决静态分析中无法处理的动态变量赋值、闭包依赖等问题。
环境沙箱构建
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
5
通过vm2
创建隔离环境,注入常见加密库(如Node.js原生crypto
、sm-crypto
)的模拟实现。
2. 执行钩子植入
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
6
在加密API调用时触发钩子,记录调用参数及其赋值路径。
3.动态参数溯源
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
7
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
8
当检测到sm3(nowDate)
调用时,自动关联nowDate
变量的赋值语句(如new Date().getTime()
)。
输出示例:
// 原始代码const originalCode = `functiongreet(){ console.log('Hello, World!');}`;// 加密:使用Base64编码const encryptedCode = btoa(originalCode);console.log('Encrypted Code:', encryptedCode);// 解密并执行const decryptedCode = atob(encryptedCode);eval(decryptedCode);greet();
9
技术要素三:加密库指纹识别
通过代码模式匹配与特征向量库比对,精准识别加密库名称、版本及算法实现细节。
特征向量库构建
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
0
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
1
2. 代码片段向量化
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
2
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
3
3. 相似度比对模型
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
4
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
5
输出示例:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
6
实现二:动态密钥生成逻辑还原
动态密钥生成逻辑还原是加密算法分析中的核心挑战,尤其在面对依赖时间戳、随机数、环境参数等动态因素的密钥生成机制时。只有明确所有逻辑,以供渗透人员顺利进行下一步测试工作。
技术要素一:代码模式归纳,动态密钥模式识别
通过静态代码分析与机器学习模型,自动化识别常见动态密钥生成模式(如时间戳拼接、随机数哈希),并还原其逻辑。简单来说,通过分析代码,生成对应代码的AST,通过标注不同模式分别对应的结果,然后通过机器学习训练得到模型。当然,在已有的AI大模型场景下,进行蒸馏也可,符合本文内容,所以在这里写一下。
具体实现步骤如下:
a. 模式特征提取基于AST解析常见动态因子代码模式:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
7
b. 模型训练与分类使用AST序列化 + 文本分类模型(如BiLSTM):
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
8
c. 代码逻辑还原示例输入代码:
<!DOCTYPE html><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>Dynamic Script Loading</title></head><body><buttonid="loadScript">Load Script</button><script>const loadScriptButton = document.getElementById('loadScript'); loadScriptButton.addEventListener('click', function () {const script = document.createElement('script'); script.src = 'dynamicScript.js';document.body.appendChild(script); });</script></body></html>
9
输出还原结果:
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
0
技术要素二:数学关系推导:密钥派生参数提取
对PBKDF2、HMAC等密钥派生函数进行参数反推,提取迭代次数、盐值、哈希算法等关键参数。实现方案如下:
a. 静态参数提取基于AST遍历识别函数调用参数:
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
1
b. 动态符号执行对复杂数学关系(如异或、移位)进行符号化推导:
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
2
c. 输出示例输入代码:
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
3
输出结果:
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
4
技术要素三:环境依赖分析:浏览器指纹模拟
检测密钥生成对浏览器环境(URL、UserAgent、Canvas指纹)的依赖,并生成模拟参数绕过动态校验。实现方案如下:
a. 环境依赖检测通过AST识别环境相关API调用:
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
5
b. 模拟环境生成构建虚拟环境参数库,供渗透测试工具调用,或提取这些特征,在手动渗透或者编写脚本扫描时,将环境指纹进行指定。
functionencrypt(text, key) {let encrypted = '';for (let i = 0; i < text.length; i++) { encrypted += String.fromCharCode(text.charCodeAt(i) + key); }return encrypted;}functiondecrypt(text, key) {let decrypted = '';for (let i = 0; i < text.length; i++) { decrypted += String.fromCharCode(text.charCodeAt(i) - key); }return decrypted;}// 加密关键代码const key = 3;const originalFunction = `function secretFunction() { console.log('This is a secret function.');}`;const encryptedFunction = encrypt(originalFunction, key);// 运行时解密const decryptedFunction = decrypt(encryptedFunction, key);eval(decryptedFunction);//解密后即可得到加密前的函数,进行执行secretFunction();
6
06
JS代码使用加密算法介绍
地址:https://github.com/EastSword/YuChangSword
简单写了一个工具,后续继续优化使用,请少侠们下载和提建议,记得Star哦~
(1)输入目标
(2)过程输出:
(3)结果输出
因实际场景下,加密算法涉及复杂的引用和混淆,所以工具还需长期使用和打磨,如少侠们使用中发现问题或者增加能力的需求,及时联系我们,或者在github上面提issue~
07
总结
本文探讨了加密算法在JavaScript加密防护中的应用及其攻防博弈中的双刃剑效应。JS加密在Web前端防护中面临严峻挑战:加密流量解析、动态密钥拦截和环境依赖机制成为攻击者的主要突破点。文章通过实例揭示,硬编码密钥、自研算法漏洞可能使安全屏障转化为攻击通道。
DeepSeek等AI技术为加密算法逆向提供了新思路,通过AST语法树解析可精准识别SM4加密调用模式,提取动态密钥生成逻辑,并自动化构造攻击载荷。同时,AI赋能防守方实现加密流量语义分析,突破传统规则库检测的局限。当前防护体系需强化密钥生命周期管理、动态混淆机制与运行时环境校验,以应对红队高频撞库、流量伪造等威胁。
未来,AI驱动的自动化加密分析将重塑攻防平衡,推动安全防护向智能动态防御演进。
东方隐侠将与江湖同仁一起,关注、跟进、学习!
关注东方隐侠安全团队 一起打造网安江湖
东方隐侠安全团队,一支专业的网络安全团队,将持续为您分享红蓝对抗、病毒研究、安全运营、应急响应等网络安全知识,提供一流网络安全服务,敬请关注!
公众号|东方隐侠安全团队
请添加团队微信号|东方隐侠安全团队
用于拉少侠们进团队交流群
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...