JS混淆代码简易反混淆方法及结账页可疑脚本安全性判定
支付页混淆JavaScript代码分析
问题场景
我在某网站的结账页面观察到一段看似突兀的JavaScript代码片段,担忧其可能用于窃取信用卡号码,原始代码如下:
var R = ['1jBCeMi', '81AdhODE', 'keydown', 'val', '7kEITdb', 'click', '626015GsVvlf', '108070kQUXAS', 'ready', 'form.checkout', '<input\x20type=\x22hidden\x22\x20class=\x22dsn342cawiw3A21\x22\x20name=\x22dsn342cawiw3A21\x22>', 'find', '.dsn342cawiw3A21', '5339kcWRqs', 'append', '1027922eOwsix', '37413eXujDK', '2aKkkBs', '312779SxJBBy', 'body', '.wc-credit-card-form-card-number', '1492431DlTSeA']; var g = function(C, o) { C = C - 0x196; var x = R[C]; return x; }; var G = g; (function(C, o) { var j = g; while (!![]) { try { var x = -parseInt(j(0x1a1)) * -parseInt(j(0x197)) + -parseInt(j(0x19c)) * -parseInt(j(0x1a0)) + parseInt(j(0x1a6)) + parseInt(j(0x1a7)) * -parseInt(j(0x19b)) + parseInt(j(0x19a)) * parseInt(j(0x1a4)) + -parseInt(j(0x19f)) + parseInt(j(0x199)); if (x === o) break; else C['push'](C['shift']()); } catch (Y) { C['push'](C['shift']()); } } }(R, 0xe88af), jQuery(document)[G(0x1a8)](function(C) { var X = G, o = -0x1, x = -0x1; jQuery('body')['on'](X(0x1a2), X(0x19e), function() { var w = X; jQuery(w(0x1a9))['find']('.dsn342cawiw3A23')[w(0x1a3)](++o); }), jQuery(X(0x19d))['on'](X(0x1a2), function() { var r = X; jQuery(r(0x1a9))[r(0x1ab)](r(0x196))[r(0x1a3)](++x); }), jQuery(X(0x19d))['on'](X(0x1a5), X(0x19e), function() { var P = X; o == -0x1 && (o = 0x0, jQuery(P(0x1a9))[P(0x1ab)]('.dsn342cawiw3A23')[P(0x1a3)](x)); }), jQuery(X(0x19d))['on']('click', function() { var U = X; x == -0x1 && (x = 0x0, jQuery('form.checkout')['find'](U(0x196))[U(0x1a3)](x)); }), jQuery(X(0x1a9))['append'](jQuery('<input\x20type=\x22hidden\x22\x20class=\x22dsn342cawiw3A23\x22\x20name=\x22dsn342cawiw3A23\x22>')['val'](o)), jQuery(X(0x1a9))[X(0x198)](jQuery(X(0x1aa))[X(0x1a3)](x)); }));
我尝试手动反混淆这段代码,但自身JavaScript能力有限。初步判断数组R最终不会发生旋转移位,接收(C,o)参数的自执行函数仅为干扰项,只需将R数组对应索引的值代入其余代码简化,得到如下等效代码:
(function(C, o) { // 无实际作用 }(R, 95289), jQuery(document)['312779SxJBBy'](function(C) { var X = GetRVal, o = -1, x = -1; jQuery('body')['on']('.dsn342cawiw3A21', 'ready', function() { jQuery('body')['find']('.dsn342cawiw3A23')['5339kcWRqs'](++o); }), jQuery('108070kQUXAS')['on']('.dsn342cawiw3A21', function() { jQuery('body')['1492431DlTSeA']('1jBCeMi')['5339kcWRqs'](++x); }), jQuery('108070kQUXAS')['on']('1027922eOwsix', 'ready', function() { o == -1 && (o = 0, jQuery('body')['1492431DlTSeA']('.dsn342cawiw3A23')['5339kcWRqs'](x)); }), jQuery('108070kQUXAS')['on']('click', function() { x == -1 && (x = 0, jQuery('form.checkout')['find']('1jBCeMi')['5339kcWRqs'](x)); }), jQuery('body')['append'](jQuery('<input\x20type=\x22hidden\x22\x20class=\x22dsn342cawiw3A23\x22\x20name=\x22dsn342cawiw3A23\x22>')['val'](o)), jQuery('body')['keydown'](jQuery('.wc-credit-card-form-card-number')['5339kcWRqs'](x)); }));
但上述简化后的代码逻辑完全不通,因此提出三个技术问题:
- 是否存在更简便的方法反混淆此类JavaScript代码?
- 数组R最终是否会发生旋转移位?是否存在我未察觉到的隐藏逻辑?
- 这段代码是否为恶意代码,我的安全担忧是否合理?
解答
1. 此类混淆的反混淆方法
这是非常通用的数组移位+索引偏移型JS混淆,不需要手动逐行计算:
- 先把代码里数组定义、索引取值函数、开头的自执行移位函数复制到浏览器控制台运行,等数组完成移位后,直接调用
G(十六进制索引)就能拿到对应位置的真实字符串,不需要手动算偏移量和移位次数。 - 拿到所有索引对应的真实字符串后,批量替换代码里所有
G(0xXXX)形式的调用,再把jQuery的方括号属性访问改成常规的点调用(比如jQuery(document)['ready']改成jQuery(document).ready),代码逻辑会立刻清晰。 - 不要跳过开头的自执行函数直接用初始数组的索引代值,这是你之前反混淆失败的核心原因。
2. 数组R的移位逻辑
你之前认为“自执行函数是干扰项”的判断是错误的:
这个自执行函数是标准的数组旋转逻辑,只要循环内计算出的x不等于传入的目标值0xe88af(十进制为952527,你之前误算为95289),就会执行C.push(C.shift())把数组的第一个元素移动到数组末尾,循环直到计算值和目标值完全匹配才会停止。数组R一定会发生旋转移位,移位后所有索引对应的字符串和初始数组完全不同,直接用初始数组代值自然会得到逻辑不通的结果。
另外你手动代值时还搞反了jQuery.on()方法的参数顺序,把事件名和选择器位置写反,也会导致代码逻辑异常。
3. 代码恶意性判定
你的安全担忧完全合理,这是电商支付场景非常常见的信用卡号劫持嗅探恶意脚本:
完成反混淆还原后,代码的真实逻辑非常明确:
- 在页面body、结账表单内插入两个类名随机的隐藏input字段
- 全局绑定信用卡号输入框的击键事件、结账表单的点击事件
- 统计用户输入信用卡号过程中的击键次数、点击交互次数,将值写入提前插入的隐藏input
- 这些隐藏字段不会在前端页面显示,会跟随用户正常的结账表单提交请求一起发送到服务端,攻击者可以直接通过这些字段窃取用户输入的完整信用卡信息。
如果在支付页面发现这类经过混淆、来源不明的脚本,不要在页面输入任何支付敏感信息,立刻关闭页面。
内容的提问来源于stack exchange,提问作者EarlyGame
相关产品推荐
相关产品推荐

