最近在補以前落下的想學的東西,古河以前已經在微薄裏面公佈了此漏洞的poc及利用思路,不過在看古河的文章前我先獨立分析一下其漏洞成因,記錄下本身的分析流程。windows
操做系統:Win8.1 x86 RTM瀏覽器
瀏覽器:Internet Explorer 11 32bits (補丁打到KB2909921)函數
漏洞編號:CVE-2014-0321學習
微軟補丁:MS14-012spa
直接運行poc,崩潰後查看狀態操作系統
看到crash緣由是test dword ptr [ecx+24h],30000h ds:0023:41414165=???????? 處引用了無效的內存空間。查看崩潰處的上下文。3d
在crash時的ecx來自進入函數CTreeNode::ComputeFormatsHelper時的參數1——ecx(請回顧Windows x86調用約定)。那麼這個參數1到底又從哪裏來呢。進一步回溯父函數:調試
此時的ecx已經沒有發生變化,再次回溯父函數:orm
經過mov ecx,dword ptr [ebp+8]能夠知道crash位置的ecx來自CInsertSpliceUndo::SetData的參數一[ebp+8]。且CInsertSpliceUndo::SetData調用CTreeNode::GetCharFormatHelper前還有別的函數調用,以下圖所示:對象
而CInsertSpliceUndo::SetData的父函數則爲CSpliceTreeEngine::InsertSplice,經過IDA,發現第一個參數爲struct CTreeNode *。所以,釋放後被重用的即爲struct CTreeNode *,以下圖所示:
所以,接下來在CInsertSpliceUndo::SetData處設置斷點,查看進入函數時,起參數1是否已經被釋放,若沒有釋放,則進一步跟蹤釋放位置。
開啓gflags.exe的Page Heap功能。
設置條件斷點,在進入CInsertSpliceUndo::SetData時斷下函數
bu MSHTML!CInsertSpliceUndo::SetData "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"*MSHTML!CElement::replaceNode*\")) { r $t0 = 1;.break } }; .if($t0 = 0) { gc }"
第一次斷下CInsertSpliceUndo::SetData時,觀察參數一:
SetData第一次被斷下來,此時對象還未被釋放,所以對此對象的釋放過程設置斷點。
bu ntdll!RtlFreeHeap ".if ( poi(esp+0xc) == 06a9efa0 ){} .else{gc}"
經過跟蹤,沒有發現問題……發現被釋放並佔位的是另一個CTreeNode對象,並且是在第二次調用SetData時,以下圖所示
因爲Page Heap的做用,致使對象釋放後並無佔位成功,對對象進行堆回溯,查看被釋放的位置。
由CFastDOM::CDocument::Trampoline_write可見JS中的document.write("");致使了對象的釋放。
基於上面的分析,下次添加斷點
bu MSHTML!CFastDOM::CHTMLElement::Trampoline_replaceNode
bu MSHTML!CFastDOM::CDocument::Trampoline_write
bu MSHTML!CInsertSpliceUndo::SetData "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"*MSHTML!CElement::replaceNode*\")) { r $t0 = 1;.break } }; .if($t0 = 0) { gc }"
查看被斷下來時的調用回溯,此時調用流程已經比較明顯,經過此處的斷點狀態咱們能夠獲取如下幾個信息:
根據以上分析,下次調試設置如下斷點,驗證執行流程,肯定被釋放的對象
bu MSHTML!CFastDOM::CHTMLElement::Trampoline_replaceNode
bu MSHTML!CFastDOM::CDocument::Trampoline_write //而後跟蹤其對某個對象的釋放過程
根據堆棧回溯,對MSHTML!CSpliceTreeEngine::InsertSplice+0x11fa處下斷點,進一步跟蹤分析重用
看看第1、二次進入SetData時的參數一(對象)的狀況
具體調試過程以下:
bu MSHTML!CFastDOM::CHTMLElement::Trampoline_replaceNode
bu MSHTML!CFastDOM::CDocument::Trampoline_write //而後跟蹤其對某個對象的釋放過程
設置快照,方便後邊回溯觀察對象的釋放。下面根據前面Page Heap的對象釋放記錄,跟蹤對象的釋放過程
條件斷點:
bu ntdll!RtlFreeHeap "r $t0 = 0;.foreach (v { k }) { .if ($spat(\"v\", \"*MSHTML!CMarkup::DestroySplayTree*\")) { r $t0 = 1;.break } }; .if($t0 = 0) { gc }"
上面這個斷點設置不太好,須要消耗大量時間,還不如一步步跟蹤至
bu MSHTML!CMarkup::DestroySplayTree+0x811
經過跟蹤及快照恢復功能發現DestroySplayTree被斷下來4次,其中第3次則爲後邊被釋放重用的對象。
對象被釋放前的狀態:
可見CTreeNode節點對象的建立過程及其大小(0x60)
對象被釋放後的狀態:
設置以下斷點,對onerror回調函數執行完畢後的狀況進行跟蹤
bu MSHTML!CSpliceTreeEngine::InsertSplice+0x11fa
跟蹤至以下位置,便可發現被重用對象做爲參數傳遞進了CInsertSpliceUndo::SetData
CTreeNode對象被document.write("");釋放後,當即進行內存佔位,
實際大小爲0x60,因爲不能經過Create user mode stack trace database功能進行堆回溯,所以在Page Heap開啓下沒法追蹤佔位過程。可是經過poc,能夠觀察到對象已經被穩定佔位。
此漏洞的效果總結來講就是對釋放後重用的CTreeNode節點對象進行了穩定佔位。但因爲這個被釋放掉的對象的可控性過低,很難在JS裏面方便訪問,所以利用起來有至關大的難度。
此漏洞的利用難度至關大,最近準備抽時間按照古河提供的思路嘗試寫EXP進行學習。請先參考資料的連接,瞭解此漏洞的利用方法。
[1] CVE-2014-0321 - Exploiting IE11 on windows 8.1 32bits: