分析CVE-2015-1641的記錄

Editor發表於2018-08-16
0x1 實驗環境

Win7_32位,Office2007;


0x2 工具

Windbg,OD,火絨劍,UltraEdit,oletools;


0x3 漏洞簡述

word在解析docx文件的displacedByCustomXML屬性時未對customXML物件進行驗證,可以傳入其他標籤物件進行處理,造成型別混淆,通過在word中嵌入構造好的RTF檔案,其中經過精心構造的標籤以及對應的屬性值被displacedByCustomXML解析以及後續函式處理後會造成任意記憶體寫入。


0x4 樣本hash值

8bb066160763ba4a0b65ae86d3cfedff8102e2eacbf4e83812ea76ea5ab61a31

下載連結:

https://github.com/houjingyi233/office-exploit-case-study/blob/master/CVE-2015-1641/8bb066160763ba4a0b65ae86d3cfedff8102e2eacbf4e83812ea76ea5ab61a31.bin.gz


0x5 分析記錄

在分析前先做好虛擬機器快照,獲取RTF樣本後使用oletools工具中的rtfobj.pyc指令碼分析,這裡將檔案命名為aa.doc,在cmd命令模式中來到rtfobj.pyc所在的目錄,並將aa.doc一塊放到該目錄,接著執行命令“rtfobj.pyc aa.doc”,得到分析結果如下:一共四個檔案,id為0的是“otkloadr.wRAssembly.1”,用來載入 OTKLOADR.DLL 模組,其功能會在之後分析到:  

                          

分析CVE-2015-1641的記錄


把其他三個OLE物件分別根據他們各自的id用“rtfobj.pyc-s [id] aa.doc”命令依次分離並儲存,其中有兩個是“.doc”檔案,現在樣本已經被分離,雙擊執行也不會有危險:


分析CVE-2015-1641的記錄


將其中id為2的"aa.doc_object_0002042c.doc"的字尾改為“.docx”後,開啟word就會崩潰,可以預測,漏洞就在這個OLE裡面觸發的:


分析CVE-2015-1641的記錄


在分析這個樣本的過程中,由於對RTF檔案構造方式不熟悉,使得我在構造樣本的時候阻滯了很長時間,東拼西湊就是不能製造crash,後邊把問題放到了看雪論壇,前輩們一下就解決了,其實RTF檔案的構造不復雜:將原始rtf 樣本用文字方式開啟,搜尋 “objdata” 字串,可找到與 rtfobj.py 提取後相應 id 的內容,手動抽取對應id的內容另存為一個合法的 rtf 檔案即可。前面提到,這個RTF樣本一共由四個OLE物件組成,用notepad++開啟原始樣本,然後搜尋“objdata” 字串,發現一共有四個這樣的字串,也就是那四個OLE,觸發漏洞的OLE的id為2,也就是原始樣本中的第三個OLE,長這樣:


分析CVE-2015-1641的記錄


抽取複製OEL的時候一定要把括號成對匹配好,把這個OLE複製出來,即它的開頭到下一個OLE的開頭的部分,然後新建一個文字文件,並把字尾改為“.rtf”格式,然後在這個文件中先寫好“{\rtf}”,然後貼上OLE進去即可:


分析CVE-2015-1641的記錄


然後把這個RTF檔案用word開啟,就會崩潰;中間失敗過幾次,後來發現是複製OLE的時候括號複製多了。


接著來定位漏洞觸發的位置,先開啟Windbg,再開啟Winword.exe,用偵錯程式附加Winword.exe後執行存在漏洞的OLE檔案,程式在“0x67C39d30“這個地址出現異常,導致崩潰,原因是[ECX]引用了一個不存在的地址;


 分析CVE-2015-1641的記錄


這個指標[7C38BD50]會指向哪裡?先把這個存在漏洞的OLE解壓,在解壓目錄的資源組織檔案“document.xml”中發現如下的程式碼:上面ECX的值被內嵌成smarttTag標籤的element的屬性值。


分析CVE-2015-1641的記錄


smartTag標籤是一個智慧標籤,可對名字、地址等自動識別,displacedByCumtomXml屬性表示此處要替換為另一個customxml標籤,”next”表示後一個,”prev“表示前一個;樣本作者在smartTag的element中構造了0x7C38BD50,Word在解析docx文件處理displacedByCustomXML屬性時未對customXML物件進行驗證,所以能傳入smartTag標籤物件。


單獨載入觸發漏洞的OLE時索引到一個不存在的地址,因為這個地址位於“MSVCR71.DLL”中,而這個DLL正是通過第一個OLE物件“otkloadr.wRAssembly.1”引入的。將第一個OLE物件:{\object\objocx{\*\objdata0105000002000000160000006f746b6c6f6164722e5752417373656d626c792e3100000000000000000001000000410105000000000000}},新增到觸發漏洞的OLE前面,然後重新載入合併後的RTF執行,通過windbg下條件斷點,這裡先記錄下crash發生的時候“0x7C38BD50”所在的模組地址,待會通過它來下條件斷點:


分析CVE-2015-1641的記錄


條件斷點:

bp 

wwlib!DllGetClassObject+0x50e6".if(ecx=7c38BD50){}.else{gc}"


分析CVE-2015-1641的記錄


0x7C38BD50是smartTag標籤的element值,0xFFFFE696(十進位制為4294960790)是moveFromRangeStart的值,隨後對這兩個值進行計算得到一個地址0x7C38BD74。計算過程如下:


分析CVE-2015-1641的記錄


隨後開始解析第二個smartTag,smartTag標籤的element值此時為0x7C38BD68,moveFromRangeStart的值為0x7C376FC3(十進位制為2084007875),計算出的地址為0x7C38A428,最後通過memcpy函式將0x7C376FC3覆蓋到地址0x7C38A428中,在偵錯程式可以看到,0x7C38A428為虛表指標:


分析CVE-2015-1641的記錄


而在7C38A428被覆蓋之前,它指向的是kernel32!FlsGetValue:


分析CVE-2015-1641的記錄


覆蓋之後的0x7c38a428指向的便是攻擊者想要執行的程式碼位置:


分析CVE-2015-1641的記錄


接著往下執行會先經過一大片地址為“7C342404”的“ret”,然後進入ROP鏈,再往後就是shellcode。

將id為1的OLE解壓後,在解壓目錄的“activeX1.bin”中看到用來堆噴的資料塊:nop指令上面的是ROP鏈,heapspary前會使用大量地址為0x7c342404 的ret-sled,


分析CVE-2015-1641的記錄


通過XML來載入“activeXL.bin”的堆資料:


分析CVE-2015-1641的記錄


在堆噴資料看到ROP鏈之前有大量的“ret sled”,可以通過這個地址來下斷點進入shellcode,方法為:在進入MSVCR71.dll後,通過“uf 7C342304 ”命令來檢視它所在的模組地址:MSVCR71!calloc+0xb1,並在該處下斷;然後用“bd”命令禁用之前的條件斷點,F10執行後就能來到地址0x7C342404。


如下圖,當程式在“0x7C342404”處斷下時,通過“Memory”視窗輸入Virtual為“ESP”可以看到堆噴資料,如果不能進入到堆噴資料,有兩種解決方案:可以將虛擬機器的記憶體設定為2G;或者找到rop鏈在堆中的位置,接著在執行“ret”準備跳進堆噴資料的時候將棧頂值修改為ROP鏈的起始位置;


分析CVE-2015-1641的記錄


執行完“0x7C342404”處的“ret”後,便可以接著跟到ROP鏈,F10單步執行:然後通過NOP進入shellcode。


在Windbg中分析shellcode的時候一直沒能順利跟下去,於是在OD中來分析,斷點還是在“0x7C342404”:開啟OD和Winword.exe後,用OD附加Winword.exe,接著把完整樣本拖進word,這個時就可以下斷點,因為shellcode是最後執行,在這之前要先進行堆噴,再觸發漏洞,時間上來得及。


當程式在“0x7C342404”處斷下後,發現很久也跟不到ROP鏈,這時可以藉助之前Windbg的分析結果,發現ROP鏈的首個位置為“0x7C3651EB”,然後在該位置下斷,同時把“0x7C342404”處的斷點禁用,接著F9執行,便能來到ROP鏈的開頭。

在ROP鏈中通過呼叫VirtualProtect關閉起始地址0x090008b4後的DEP保護:


分析CVE-2015-1641的記錄


接著執行地址0x090008b4處的“nop+shellcode”:


分析CVE-2015-1641的記錄


首先獲取kernel32.dll基址:


分析CVE-2015-1641的記錄


接著比較API的hash值來獲取所需API函式,這樣的好處在於減少了shellcode的大小:


分析CVE-2015-1641的記錄


接著用VirtualAlloc分配可執行的記憶體空間,為執行shellcode做準備:


分析CVE-2015-1641的記錄


接著通過呼叫 GetFileSize遍歷程式中開啟的檔案控制程式碼,獲取開啟的樣本檔案的控制程式碼:


分析CVE-2015-1641的記錄


CreateFileMapping建立該檔案的共享檔案資料:


分析CVE-2015-1641的記錄


MapViewOfFile來獲取共享資料的記憶體地址:


分析CVE-2015-1641的記錄


判斷幾個標誌位是否為“{\rt,0xfefefefe,0xfe,0xffffffff”,是則將shellcode拷貝到VirtualAlloc分配的可執行的記憶體空間:


分析CVE-2015-1641的記錄


但是在之後的分析中,多次除錯也沒有跟到真實shellcode的位置,於是嘗試用Windbg來分析,根據上一階段的分析可知,第一階段的shellcoed先判斷幾個標誌字串是否為“{\rt,0xfefefefe,0xfe,0xffffffff”,是的話就將真實shellcode拷貝到VirtualAlloc分配的可執行的記憶體空間,如上圖所示:順利的話就會執行“0x090009F9”(偏移0x09F9)地址處的指令。


然後關掉OD,開啟Windbg和Winword.exe,用Windbg附加Winword.exe,先在“0x7C342404”,即“ret”鏈的位置下斷,然後將原始樣本附加到Winword.exe,執行後來到“ret”,接著在“0x7C3651EB”,即ROP鏈的開頭下斷,並用“bd 0”禁用之前的斷點,執行後來到ROP鏈的開頭,根據上面的分析,真實shellcode會在偏移“0x09F9”處開始執行,用“bc 0”,“bc 1”先將之前的斷點刪除,再在“0x090009F9”下斷,執行後順利來到第二階段的shellcode:


分析CVE-2015-1641的記錄


接著將後面的4KB的資料,即第二部分 shellcode,拷貝到函式 VirtualAlloc 申請的具有可執行許可權的記憶體中,然後跳轉過去執行:


分析CVE-2015-1641的記錄


之後會在這部分shellcode的偏移0x2e處解密shellcode,解密的大小為0x3CC位元組:


分析CVE-2015-1641的記錄


接著根據標誌字串“0xBABABABABA”獲得payload的起始位置,然後xor 0xCAFEBABE解碼payload,終止標誌為0xBBBBBBBB:


分析CVE-2015-1641的記錄


接著建立檔案,釋放payload:


分析CVE-2015-1641的記錄


可以根據API引數在UE編輯器看到路徑和建立的檔案“svchost.exe”:


分析CVE-2015-1641的記錄


接著用WinExec函式執行“svchost.exe”:


分析CVE-2015-1641的記錄


WinExec函式執行後,在監控軟體(火絨劍)中可以看到釋放的惡意程式,它的作用主要是進行資訊的竊取:


分析CVE-2015-1641的記錄


在惡意 payload 執行後會對樣本中的部分資料進行異或操作,目的是使其成為看上去正常的word,這部分機器碼的開頭是“0xBB”,結尾是“0xBCBC”,


分析CVE-2015-1641的記錄


重寫之後看到的word就是正常開啟的空白文件:


分析CVE-2015-1641的記錄


原始樣本所在的word文件:


分析CVE-2015-1641的記錄




看雪ID:大晟 


本文由看雪論壇 大晟 原創

轉載請註明來自看雪社群

原文連結: https://bbs.pediy.com/thread-230289.htm

u

分析CVE-2015-1641的記錄


相關文章