操作系統(tǒng)開發(fā)人員總是熱衷于提高漏洞防御技術,所以微軟在Windows10和Windows8.1Update3(2014年11月發(fā)布)系統(tǒng)中已經默認啟用了一種新的機制,這種技術稱為控制流防護(Control Flow Guard , CFG)。
早先的抑制技術如地址空間布局隨機化(ASLR)和數(shù)據執(zhí)行保護(DEP),雖然并不完美,但已經成功地使得漏洞利用變得更加困難。ASLR導致了堆噴射的發(fā)展,而DEP導致了漏洞利用代碼中返回導向編程(ROP)技術的發(fā)展。
為了探索CFG這種特殊的技術,我使用Windows 10技術預覽版(build6.4.9841)系統(tǒng),并使用VS2015預覽版來創(chuàng)建測試程序。最新的Windows 10技術預覽版(build10.0.9926)系統(tǒng)的CFG實現(xiàn)有一個細微的變化,我將會在后文指出。
為了完全實現(xiàn)CFG機制,編譯器和操作系統(tǒng)都必須恰當?shù)刂С炙?。作為一種系統(tǒng)級的漏洞利用抑制機制,CFG的實現(xiàn)需要編譯器、操作系統(tǒng)用戶模式庫和內核模塊的配合。MSDN上的一篇博文介紹了開發(fā)者需要怎樣做才能支持CFG機制。
控制流防護機制分析
微軟的CFG是專注于間接調用的保護機制,以下面我所創(chuàng)建的測試程序為例,來講解該機制的大致原理。
首先,我們看一下在CFG機制未啟用時,上圖紅線所圈部分的代碼編譯之后的結果:
在上圖中顯示了一種間接調用類型,在編譯時期它的目標地址并未確定,而是在運行時才確定該地址。這樣,我們就能通過以下方式來進行漏洞利用代碼的調用:
微軟的CFG實現(xiàn)主要集中于抑制問題,即如果間接調用被利用來調用一個無效的目標(在exploit中,這可能是shellcode的第一步),CFG則可以有效抑制。
這個無效目標有一個與眾不同的特征:在大多數(shù)情況下,它不是一個有效函數(shù)的起始地址。微軟CFG的實現(xiàn)基于這樣一個理念:間接調用的目標必須是一個有效函數(shù)的起始地址。那么,啟用了CFG之后生成的匯編代碼如何呢?
在間接調用之前,目標地址會傳遞給函數(shù)_guard_check_icall,而CFG機制正是在該函數(shù)中實現(xiàn)。在之前不支持CFG機制的Windows系統(tǒng)版本中,該函數(shù)未做任何事。在支持CFG的Windows 10中,_guard_check_icall調用了_guard_check_icall函數(shù),該函數(shù)以目標地址作為參數(shù),并按以下流程執(zhí)行:
1、訪問一個位圖(調用CFGBitmap),該位圖代表進程空間所有函數(shù)的開始位置,進程空間中每8個字節(jié)的狀態(tài)對應CFGBitmap中的一個位。如果在每8個字節(jié)組中有一個函數(shù)起始地址,則CFGBitmap中對應的位會被設置為1,否則會被設置為0。下圖是一個例子用來展示CFGBitmap的一部分。
2、將目標地址轉換為CFGBitmap中的一個位,以00b01030為例:
最高位的3個字節(jié)(上圖中藍線圈中的24位)代表CFGBitmap的偏移量(以4字節(jié)為單元)。在該例子中,最高位的3個字節(jié)值等于0xb010。因此,指向CFGBitmap中一個4字節(jié)單元的指針就是CFGBitmap的基地址加上0xb010。
與此同時,第4到第8位(上圖紅線圈中的5位)代表值X。如果目標地址與0×10對齊(目標地址&0xf==0),則X就是單元內的位偏移值。如果目標地址沒與0×10對齊(目標地址&0xf!=0),則X|0×1就是位偏移值。
在這個例子中,目標地址是0x00b01030,X的值為6。表達式0x00b01030&0xf的值等于0,這表明位偏移也是6。
3、接下來我們看下第2步中所提到的位。如果這個位等于1,這就表明該間接調用目標有效,因為它是一個函數(shù)的起始地址;如果該位等于0,表明該間接調用目標無效,因為它不是一個函數(shù)的起始地址。如果間接調用目標有效,則函數(shù)將什么也不做。如果目標無效,將會拋出一個異常,以此阻止利用代碼的執(zhí)行。
控制流防護的實現(xiàn)有助于阻止某些類型的漏洞利用。而從長遠來看,這將有助于減少因軟件漏洞而帶來的威脅。
文章來源:FreeBuf黑客與極客(FreeBuf.COM)