wnagzihxa1n

wnagzihxa1n

iOS/Android Security

© 2021

浏览器安全周报 2019.11.04 - 2019.11.08

谷歌紧急修复了两个洞,说是已经被黑客组织利用了,大家及时更新

  • 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.expm1TypePlainNumber | NaN,这个Type不包含-0,右边的节点类型是MinusZero也就是-0,这两个数据传入SameValue节点进行比较,这明显是恒不相等的

IMAGE

所以在typed lowering阶段,这三个节点会进行常量折叠为false

IMAGE

所以我们可以看到打印出来的是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];
}

再次感谢各位师傅们的帮助!