谷歌紧急修复了两个洞,说是已经被黑客组织利用了,大家及时更新
- https://securelist.com/chrome-0-day-exploit-cve-2019-13720-used-in-operation-wizardopium/94866/
以下是这两个漏洞的链接,目前都不可访问,Poc我没搜到,这段时间再跟进一下
CVE-2019-13720: Use-after-free in audio
- https://bugs.chromium.org/p/chromium/issues/detail?id=1019226
CVE-2019-13721: Use-after-free in PDFium
- https://bugs.chromium.org/p/chromium/issues/detail?id=1013868
这几周的UXSS有点多,然而我不懂
WebKit:UXSS Issue 1914: WebKit: Universal XSS in JSObject::putInlineSlow and JSValue::putToPrimitive
- https://bugs.chromium.org/p/project-zero/issues/detail?id=1914
WebKit:整数溢出导致UXSS和类型混淆
Issue 1919: WebKit: Integer overflow in NodeRareData::m_connectedFrameCount can lead to UXSS and type confusion
- https://bugs.chromium.org/p/project-zero/issues/detail?id=1919
JSC:bailout过程中的一个类型混淆
Issue 1924: JSC: Type confusion during bailout when reconstructing arguments objects
- https://bugs.chromium.org/p/project-zero/issues/detail?id=1924
Chrome:绕过Site Isolation以及本地文件泄露
Issue 1928: Chrome: Site Isolation bypass and local file disclosure via Payment Handler API
- https://bugs.chromium.org/p/project-zero/issues/detail?id=1928
最近把CRBUG-880207分析了一下,感谢JR师傅,宏阳师傅,p4nda师傅,ditto师傅,路遥师傅对我在这个漏洞分析过程遇到问题时的帮助
这个漏洞是因为Turbofan对Math.expm1
进行JIT优化的时候,未正确评估返回值的类型,漏了-0
这个类型,在Typer
的时候,传播了错误的类型信息,Turbofan根据错误的信息去掉了CheckBound
这个节点,最后获得越界读写,造成了RCE
在Typer
阶段,会对Math.expm1
返回如下几个类型,我们可以看到,这里没有-0
这个类型
Type Typer::Visitor::JSCallTyper(Type fun, Typer* t) {
...
switch (function.shared().builtin_function_id()) {
...
case BuiltinFunctionId::kMathAbs:
case BuiltinFunctionId::kMathExp:
case BuiltinFunctionId::kMathExpm1:
return Type::Union(Type::PlainNumber(), Type::NaN(), t->zone());
我们来看Math.expm1
的定义:
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Refereance/Global_Objects/Math/expm1
Math.expm1() 函数返回 E**x - 1, 其中 x 是该函数的参数, E 是自然对数的底数 2.718281828459045 Math.expm1(1) // 1.7182818284590453 Math.expm1(-38) // -1 Math.expm1(“-38”) // -1 Math.expm1(“foo”) // NaN
那我们传入-0
会发生什么呢?
d8> Math.expm1(-0)
0
可以看到终端输出的是0
,如果我们用Object.is
来比较呢?
d8> Object.is(Math.expm1(-0), -0)
true
d8> Object.is(Math.expm1(-0), 0)
false
所以我们可以得到一个结论:Math.expm1(-0)
得到的结果是-0
那么这个结论有什么用呢?
我们结合一开始的优化代码来分析,在对Math.expm1
进行Typer
的时候,Turbofan认为这个函数只能返回以下几个类型,这其中并不包含-0
,-0
在Turbofan里用MinusZero
来表示
return Type::Union(Type::PlainNumber(), Type::NaN(), t->zone());
也就是说:在优化结束之后,会把Object.is(Math.expm1(-0), -0)
直接折叠为false
,也就是常量折叠
我们接下来通过跟踪优化过程来分析
➜ x64.debug git:(CRBUG-880207) ./d8 --allow-natives-syntax --trace-turbo Poc.js
......
false
在Typer
阶段,注意看红色框框里的内容,我们可以看到Math.expm1
的Type
为PlainNumber | NaN
,这个Type
不包含-0
,右边的节点类型是MinusZero
也就是-0
,这两个数据传入SameValue
节点进行比较,这明显是恒不相等的
所以在typed lowering
阶段,这三个节点会进行常量折叠为false
所以我们可以看到打印出来的是false
漏洞的成因大概就是这样,至于如何利用这里简单讲一下,详细的利用过程正在单独写文章
首先我们利用这个错误的类型推断,去传播错误的类型信息,但是太早被分析出来跟-0比较会被常量折叠,所以我们可以利用逃逸分析这个阶段,代码如下,以下这种方式,就可以防止在逃逸分析前进行常量折叠,然后逃逸分析之后的Simplified Lowering阶段会进行最后一次typing,就会错误的判断这里是一个恒为false的Type
,之后把这个错误的Type
传播下去,那么后面数组的存取前的checkbound
节点就被会优化掉,不太好用的相对地址读写原语Get,然后我们写掉这个数组后面的一个数组长度,一个好用的相对地址读写原语Get!剩下的就是常规利用操作了
function foo(x) {
let a = [0.1, 0.2, 0.3, 0.4];
let o = {mz: -0};
let b = Object.is(Math.expm1(x), o.mz);
return a[b * 1337];
}
再次感谢各位师傅们的帮助!