CVE-2014-0321漏洞成因分析

1. 簡介

  最近在補以前落下的想學的東西,古河以前已經在微薄裏面公佈了此漏洞的poc及利用思路,不過在看古河的文章前我先獨立分析一下其漏洞成因,記錄下本身的分析流程。windows

2. 實驗環境

  操做系統:Win8.1 x86 RTM瀏覽器

  瀏覽器:Internet Explorer 11 32bits (補丁打到KB2909921)函數

  漏洞編號:CVE-2014-0321學習

  微軟補丁:MS14-012spa

3. 漏洞分析

3.1. 分析Crash

3.1.1. 運行poc,查看crash

  直接運行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前還有別的函數調用,以下圖所示:對象

 

3.1.2. 釋放重用的對象類型

  而CInsertSpliceUndo::SetData的父函數則爲CSpliceTreeEngine::InsertSplice,經過IDA,發現第一個參數爲struct CTreeNode *。所以,釋放後被重用的即爲struct CTreeNode *,以下圖所示:

 

 

  所以,接下來在CInsertSpliceUndo::SetData處設置斷點,查看進入函數時,起參數1是否已經被釋放,若沒有釋放,則進一步跟蹤釋放位置。

3.2. 跟蹤調試、分析漏洞成因

3.2.1. 調試工做準備

  開啓gflags.exe的Page Heap功能。

3.2.2. 定位對象釋放位置

  設置條件斷點,在進入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("");致使了對象的釋放。

 

3.2.3. 觀察函數執行流程

  基於上面的分析,下次添加斷點

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 }"

 

 

  查看被斷下來時的調用回溯,此時調用流程已經比較明顯,經過此處的斷點狀態咱們能夠獲取如下幾個信息:

  1. IE內部經過MSHTML!CEventMgr::DispatchEvent進行事件監聽並隨後經過MSHTML!CEventMgr::Dispatch進行事件分發,分發給相應的事件監聽器進行處理。
  2. IE內部經過jscript9!Js::JavascriptExternalFunction::ExternalFunctionThunk解析並處理HTML中的JS語句
  3. 在執行replaceNode語句時,IE內部觸發了onerror事件,並執行其回調函數,document.write("");操做將致使某個CTreeNode對象被釋放

 

3.2.4. 驗證對象釋放並重用

  根據以上分析,下次調試設置如下斷點,驗證執行流程,肯定被釋放的對象

  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

 

 

3.2.5. 內存佔位

  CTreeNode對象被document.write("");釋放後,當即進行內存佔位,

 

  實際大小爲0x60,因爲不能經過Create user mode stack trace database功能進行堆回溯,所以在Page Heap開啓下沒法追蹤佔位過程。可是經過poc,能夠觀察到對象已經被穩定佔位。

3.2.6. 小結

  此漏洞的效果總結來講就是對釋放後重用的CTreeNode節點對象進行了穩定佔位。但因爲這個被釋放掉的對象的可控性過低,很難在JS裏面方便訪問,所以利用起來有至關大的難度。

4. 漏洞利用

  此漏洞的利用難度至關大,最近準備抽時間按照古河提供的思路嘗試寫EXP進行學習。請先參考資料的連接,瞭解此漏洞的利用方法。

 

5. 參考資料

[1]  CVE-2014-0321 - Exploiting IE11 on windows 8.1 32bits:

http://weibo.com/p/1001603732980651659108

相關文章
相關標籤/搜索