-
Notifications
You must be signed in to change notification settings - Fork 3
Metasploit 中混淆 JavaScript 代码
避免检测是在漏洞利用开发过程中要考虑的重要功能. 如果你的 Exploit 程序一直被检测到, 那么无论你的漏洞利用多么出色或在技术上具有挑战性, 在实际的渗透测试中很有可能不是很有用. 特别是浏览器漏洞利用严重依赖 JavaScript 来触发漏洞, 因此许多防病毒或基于签名的入侵检测/防御系统都会扫描 JavaScript 并将特定行标记为恶意. 下列代码曾经被多个防病毒供应商视为 MS12-063, 即使它不一定有害或恶意, 我们将在整个 Wiki 中以以下代码为例:
var arrr = new Array();
arrr[0] = windows.document.createElement("img");
arrr[0]["src"] = "a";
为避免被举报, 我们可以尝试一些常见的回避技巧. 例如, 你可以手动修改一点代码, 以使任何签名都无法识别它. 或者, 如果防病毒软件依靠缓存的网页来扫描漏洞, 则可能使浏览器不缓存你的代码, 因此你不会被发现. 或者在这种情况下, 你可以混淆你的代码, 这是本文的重点.
在 Metasploit 中, 有三种常见的方法来混淆 JavaScript. 第一个简单地是通过使用 rand_text_alpha
方法 (在 Rex 中) 来随机化变量名. 第二个是通过使用 ObfuscateJS 类. 第三个选择是 JSObfu 类.
使用 rand_text_alpha
是逃避的最基本形式, 但效果也最差. 如果这是你的选择, 则应该随机化任何可以随机化的内容而不会破坏代码.
通过使用上面的 MS12-063, 可以使用 rand_text_alpha
:
# Randomizes the array variable
# Max size = 6, Min = 3
var_array = rand_text_alpha(rand(6) + 3)
# Randomizes the src value
val_src = rand_text_alpha(1)
js = %Q|
var #{var_array} = new Array();
#{var_array}[0] = windows.document.createElement("img");
#{var_array}[0]["src"] = "#{val_src}";
|
ObfuscateJS 类类似于半自动化的 rand_text_alpha
技术, 效果更好. 它允许你替换符号名, 例如变量, 方法, 类和名称空间. 它也可以通过随机使用 fromCharCode 或 unescape 来混淆字符串. 它也可以通过随机使用 fromCharCode
或 unescape
来混淆字符串. 最后, 它可以清除 JavaScript 注释, 这很方便, 因为利用漏洞通常很难理解和阅读, 因此你需要注释来记住为什么以特定方式编写某些内容, 但是你不想在渗透测试时命令行显示或泄漏这些注释.
要使用 ObfuscateJS, 让我们再次使用 MS12-063 示例进行演示. 如果你想自己完成这些步骤而无需编写模块, 那么你可以运行 msfconsole, 然后切换到 irb, 如下所示:
$ ./msfconsole -q
msf > irb
[*] Starting IRB shell...
>>
然后你就可以开始了.
使用 ObfuscateJS 要做的第一件事是, 你需要模糊处理的 JavaScript 对其进行初始化, 因此在这种情况下, 请像下面这样开始:
js = %Q|
var arrr = new Array();
arrr[0] = windows.document.createElement("img");
arrr[0]["src"] = "a";
|
obfu = ::Rex::Exploitation::ObfuscateJS.new(js)
obfu
将返回 Rex::Exploitation::ObfuscateJS 对象. 它允许你做很多事情, 你实际上可以仅调用 methods
, 或者查看源代码以查看可用的方法 (带有其他 API 文档) . 但是出于演示目的, 我们将演示最常用的: obfuscate
方法.
要进行真正的模糊处理, 你需要调用 obfuscate
方法. 该方法接受一个 symbol 参数, 该参数允许你手动指定要混淆的符号名称 (variables, methods, classes 等) , 接受的参数应如下所示的 Hash 中:
{
'Variables' => [ 'var1', ... ],
'Methods' => [ 'method1', ... ],
'Namespaces' => [ 'n', ... ],
'Classes' => [ { 'Namespace' => 'n', 'Class' => 'y'}, ... ]
}
因此, 如果我想混淆变量 arrr
, 而且想混淆 src
字符串面量, 则方法如下:
>> obfu.obfuscate('Symbols' => {'Variables'=>['arrr']}, 'Strings' => true)
=> "\nvar QqLFS = new Array();\nQqLFS[0] = windows.document.createElement(unescape(String.fromCharCode( 37, 54, 071, 045, 0x36, 0144, 37, 066, 067 )));\nQqLFS[0][String.fromCharCode( 115, 0x72, 0143 )] = unescape(String.fromCharCode( 045, 0x36, 0x31 ));\n"
在某些情况下, 你实际上想知道符号名称的混淆后的名字. 一种情况是从元素的事件处理程序中调用 JavaScript 函数, 例如:
<html>
<head>
<script>
function test() {
alert("hello, world!");
}
</script>
</head>
<body onload="test();">
</body>
</html>
混淆后的版本如下所示:
js = %Q|
function test() {
alert("hello, world!");
}
|
obfu = ::Rex::Exploitation::ObfuscateJS.new(js)
obfu.obfuscate('Symbols' => {'Methods'=>['test']}, 'Strings' => true)
html = %Q|
<html>
<head>
<script>
#{js}
</script>
</head>
<body onload="#{obfu.sym('test')}();">
</body>
</html>
|
puts html
JSObfu 类曾经是 ObfuscateJS 的表亲, 但自 2014 年 9 月以来已被完全重写, 并打包为gem. 混淆更加复杂, 并且可以告诉它进行多次混淆. 你也不再需要手动指定要更改的符号名称.
在 Rex 中尝试 JSObfu
让我们再次回到 irb 来演示使用 JSObfu :
$ ./msfconsole -q
msf > irb
[*] Starting IRB shell...
>>
这次我们将做一个 "hello world" 示例:
>> js = ::Rex::Exploitation::JSObfu.new %Q|alert('hello, world!');|
=> alert('hello, world!');
>> js.obfuscate
这是输出:
window[(function () { var _d="t",y="ler",N="a"; return N+y+_d })()]((function () { var f='d!',B='orl',Q2='h',m='ello, w'; return Q2+m+B+f })());
像 ObfuscateJS 一样, 如果你需要获得符号名称的混销对应的名字, 仍然可以使用 #sym
方法. 我们将通过以下示例进行演示:
>> js = ::Rex::Exploitation::JSObfu.new %Q|function test() { alert("hello"); }|
=> #<Rex::Exploitation::JSObfu:0x00007fe112304fd0 @ast=nil, @code="function test() { alert(\"hello\"); }", @scope={}>
>> js.obfuscate
假设我们想知道方法名称 "test" 对应的混淆字符串名:
>> puts js.sym("test")
_
好, 请再次仔细检查:
>> puts js
function _(){window[(function () { var N="t",r="r",i="ale"; return i+r+N })()](String.fromCharCode(0150,0x65,0154,0x6c,0x6f));}
是的, 对我来说看起来不错.
最后, 让我们尝试混淆几次, 看看情况如何:
>> js = ::Rex::Exploitation::JSObfu.new %Q|alert('hello, world!');|
=> #<Rex::Exploitation::JSObfu:0x00007fe112304fd0 @ast=nil, @code="function test() { alert(\"hello\"); }", @scope={}>
>> js.obfuscate(:iterations=>3)
=> window[String[((function(){var s=(function () { var r="e"; return r })(),Q=(function () { var I="d",dG="o"; return dG+I })(),c=String.fromCharCode(0x66,114),w=(function () { var i="C",v="r",f="omCh",j="a"; return f+j+v+i })();return c+w+Q+s;})())](('Urx'.length*((0x1*(01*(1*020+5)+1)+3)*'u'.length+('SGgdrAJ'.length-7))+(('Iac'.length*'XLR'.length+2)*'qm'.length+0)),(('l'.length*((function () { var vZ='k'; return vZ })()[((function () { var E="h",t="t",O="leng"; return O+t+E })())]*(0x12*1+0)+'xE'.length)+'h'.length)*(function () { var Z='uA',J='tR',D='x'; return D+J+Z })()[((function () { var m="th",o="g",U="l",Y="en"; return U+Y+o+m })())]+'lLc'.length),('mQ'.length*(02*023+2)+('Tt'.length*'OEzGiMVf'.length+5)),(String.fromCharCode(0x48,0131)[((function () { var i="gth",r="len"; return r+i })())]*('E'.length*0x21+19)+(0x1*'XlhgGJ'.length+4)),(String.fromCharCode(0x69)[((function () { var L="th",Q="n",$="l",I="g",x="e"; return $+x+Q+I+L })())]*('QC'.length*0x2b+3)+(01*26+1)))]((function(){var C=String[((function () { var w="rCode",j="mCha",A="fr",B="o"; return A+B+j+w })())]((6*0x10+15),('riHey'.length*('NHnex'.length*0x4+2)+4),(01*95+13),(1*('Z'.length*(0x1*(01*(0x3*6+5)+1)+18)+12)+46),(0x1*(01*013+6)+16)),JQ=String[((function () { var NO="ode",T="rC",HT="fromCha"; return HT+T+NO })())](('J'.length*0x54+17),(0x2*051+26),('TFJAGR'.length*('ymYaSJtR'.length*'gv'.length+0)+12),(01*0155+2),(0xe*'FBc'.length+2),(0x1*22+10),(3*(01*043+1)+11)),g=(function(){var N=(function () { var s='h'; return s })();return N;})();return g+JQ+C;})());
使用 JSObfu 进行模块开发
在编写模块时, 不应像上面的示例那样直接调用 Rex. 相反, 你应该使用 JSObfu mixin 中的 #js_obfuscate
方法. 在模块中使用 JavaScript 时, 请务必这样编写:
# This returns a Rex::Exploitation::JSObfu object
js = js_obfuscate(your_code)
请注意, 默认情况下, 即使你的模块正在调用 #js_obfuscate
方法, 除非用户设置 JsObfuscate
数据存储区选项, 否则混淆不会开始. 此选项是一个 OptInt, 它允许你设置混淆的次数 (默认为 0) .
https://community.rapid7.com/community/metasploit/blog/2011/07/08/jsobfu