為了對抗漏洞利用攻擊,從window7開始,微軟在IE等程序中應(yīng)用了ALSR、DEP、GS等保護(hù)機(jī)制。隨著ROP等Bypass技術(shù)的出現(xiàn),微軟在Windows8系統(tǒng)使用了更嚴(yán)格的保護(hù)機(jī)制:HiASLR、anti-ROP、vt_guard以及各種anti-heapspray技術(shù)。
本文主要研究IE漏洞利用中的信息泄漏技術(shù),通過泄漏模塊地址信息或shellcode地址,繞過ALSR等防御機(jī)制。信息泄漏的主體思路是選定某個(gè)特殊對象,通過漏洞觸發(fā)修改該對象的某個(gè)字段,增加內(nèi)存讀寫范圍,從而獲取所需信息。
IE8下,最簡單有效的方法是修改BSTR對象。這種技術(shù)是Peter Vreugdenhil在 2010 ?Pwn2Own IE 8 上提出的。
BSTR結(jié)構(gòu)起始4字節(jié)為size字段,末尾為兩字節(jié)的NULL結(jié)束符,中間為wide char字符串。修改BSTR的size字段或NULL結(jié)束符,即可利用jscript腳本越界讀取BSTR相鄰內(nèi)存區(qū)域的內(nèi)容。具體實(shí)現(xiàn)過程如下:
step1:內(nèi)存中噴射BSTR和object。選擇合適長度的BSTR,使其占用的內(nèi)存大小和object相同。
噴射后的內(nèi)存布局為[s1][s2][b]…[s1][s2][b][s1][s2][b],[s1]和[s2]表示BSTR字符串,[b]表示object對象。
step2:釋放[s1]。
step3:觸發(fā)漏洞,覆蓋BSTR結(jié)構(gòu)的size字段或NULL結(jié)束符,即可越界讀取相鄰object對象的虛表指針vtptr,繼而獲得模塊的地址信息。根據(jù)模塊地址信息構(gòu)造動(dòng)態(tài)ROP鏈即可繞過DEP。為了精確寫入到BSTR 的Size字段或NULL結(jié)束符位置,有時(shí)需要放置多個(gè)BSTR位于Vulnerable Buffer和object對象之間。
圖1.3 溢出后內(nèi)存布局
能否成功泄漏vtptr,關(guān)鍵是選擇大小與Vulnerable Buffer相等的object,形成連續(xù)分配的內(nèi)存布局。如果Vulnerable Buffer Size較大,找不到與之相等的object對象,可以選擇讀取屬性數(shù)組AttrArray中的地址信息進(jìn)行泄漏。
AttrArray屬性數(shù)組中每個(gè)元素大小為0x10字節(jié),結(jié)構(gòu)如下:
假設(shè)定義如下select元素,初始化8個(gè)屬性。調(diào)用selob對象的cloneNode方法時(shí),程序創(chuàng)建對應(yīng)AttrArray數(shù)組。
基于AttrArray的泄漏過程如下所示??梢钥闯?,修改size字段后不僅能夠獲取對象指針objptr以及其虛表指針。還可以獲得字符串指針strptr。如果該字符串為shellcode,即可獲得shellcode的地址信息。
從IE9以后,引入了Nozzle技術(shù),禁止噴射BSTR,而且即使繞過Nozzle,分配的BSTR不在同一個(gè)堆塊中。此時(shí)可以選擇噴射屬性數(shù)組AttrArray,通過修改AttrArray中的BSTR指針完成信息泄漏。具體步驟如下:
Step1:創(chuàng)建對象A,將其0x7ffe個(gè)屬性值初始化為NULL。循環(huán)調(diào)用該對象的cloneNode方法,在內(nèi)存中噴射屬性數(shù)組,其中每個(gè)屬性數(shù)組占用的內(nèi)存大小為0x80000(0x7ffe*0x10+0x20)。這些屬性數(shù)組在內(nèi)存中是連續(xù)分布的。
Step2:遍歷所有的AttrArrayA,對每個(gè)AttrArrayA:
(1)每間隔0x1000個(gè)屬性,調(diào)用setAttribute方法將屬性值設(shè)置為字符串“AA…AA”,此時(shí)AttrArrayA將獲得一個(gè)指向該字符串的BSTR指針(如圖2.3箭頭a所示);
(2)創(chuàng)建一個(gè)body元素對象B,對應(yīng)元素?cái)?shù)組AttrArrayB。
選擇合適的BSTR長度以及對象B的元素個(gè)數(shù),使其占用的內(nèi)存大小相等,BSTR和AttrArrayB將在內(nèi)存連續(xù)分布,內(nèi)存布局為[s][a][s][a]…[s][a]。其中[s]表示BSTR,[a]表示數(shù)組AttrArrayB。
圖2.2? AttrArrayB和BSTR內(nèi)存分布
Step3:觸發(fā)漏洞,修改某個(gè)AttrArrayA中元素值strptr,使其指向相鄰AttrArrayB區(qū)域(如圖2.3箭頭b所示),此時(shí)即可成功讀取AttrArrayB中的地址信息。
圖2.3 溢出前后的內(nèi)存布局
注:這種泄漏技術(shù)適用于IE9、IE10以及IE11。
Ivan? Fratric在《Exploiting Internet Explorer11 64-bit on Windows 8.1 Preview》中提出通過噴射Javascript Array對象,修改Capacity字段,完成信息泄漏。這種技術(shù)同樣適用于32位系統(tǒng)下IE11漏洞。
在32位系統(tǒng)中,Javascript Array對象結(jié)構(gòu)如下。
其中?,Array對象Header長度為0x28。數(shù)組塊ArrayBlock結(jié)構(gòu)如下:
Array對象在內(nèi)存中的布局由數(shù)組長度決定:
(1)當(dāng)數(shù)組長度<=0x40,Array Header和ArrayBlock在內(nèi)存中是連續(xù)分布;
(2)當(dāng)數(shù)組長度>0x40,Array Header和ArrayBlock在內(nèi)存中分布不連續(xù)。
修改Capacity字段,增加Array數(shù)組的內(nèi)存讀寫范圍,即可獲得相鄰內(nèi)存區(qū)域的地址信息。具體步驟如下:
Step1:在內(nèi)存中噴射大量的Javascript Array對象(length<=40)。
圖3.1: 初始內(nèi)存布局
Step2:觸發(fā)漏洞,覆蓋某個(gè)Array對象的capacity字段。遍歷所有Array對象,通過Array.length定位被覆蓋的數(shù)組ArrayA。越界讀取ArrayA,獲得ArrayB的虛表地址VtptrB;越界寫入ArrayA將ArrayB的capacity設(shè)置為0x7fffffff,使得ArrayB獲得最大范圍的讀寫權(quán)限。
圖3.2:capacityA被修改后的越界讀寫
Step3:在內(nèi)存中寫入shellcode,繞過保護(hù)機(jī)制,執(zhí)行任意代碼。
(1)選定某個(gè)值n,從ArrayB[n]位置所在內(nèi)存地址開始,將shellcode依次寫入。
(2)選定某個(gè)值m,從ArrayB[m]位置所在的內(nèi)存地址開始,將虛表指針指VtptrB指向的虛表函數(shù)依次寫入,并修改其中兩個(gè)虛函數(shù)的地址為VirtualProtect地址和Shellcode地址。
(3)覆蓋VtptrB為fakeVtptr。當(dāng)程序調(diào)用虛函數(shù)時(shí),調(diào)用VirtualProct函數(shù)關(guān)閉DEP并成功執(zhí)行shellcode。
圖3.3 :exploit內(nèi)存布局
(文章來源:啟明星辰ADLab)