緩沖區溢出攻擊
一、實驗目的:
加深對IA-32函數調用規則和棧幀結構的理解
二、實驗要求:
構造5個攻擊字符串,對目標程序實施緩沖區溢出攻擊。
5次攻擊難度遞增,分別命名為
Smoke (讓目標程序調用smoke函數)
Fizz (讓目標程序使用特定參數調用Fizz函數)
Bang (讓目標程序調用Bang函數,並篡改全局變量)
Boom (無感攻擊,並傳遞有效返回值)
Nitro (棧幀地址變化時的有效攻擊)
需要調用的函數均在目標程序中存在
三、實驗內容:
getbuf函數:存在緩沖區溢出漏洞,buf只有0x28字節長度。
棧:
Smoke:
任務是讓目標程序調用smoke函數,觀察這個棧,要想調用smoke函數就要把smoke函數的地址放到getbuf上面的返回地址處。
找到smoke函數的地址:0x8048c28
接下來,只要構造0x28+4+4=48字節長度的字節碼就可以將返回地址覆蓋,最后四個字節的內容放smoke函數的地址保證返回地址是被smoke函數的地址覆蓋,因為是小端存儲,也就是:28 8c 04 08,前面放一些00湊出44個字節。
用管道輸入,通過hex2raw之后輸入bufbomb程序。成功:
Fizz:
構造攻擊字串造成緩沖區溢出,使目標程序調用fizz函數,並將cookie值作為參數傳遞給fizz函數,使fizz函數中的判斷成功,需仔細考慮將cookie放置在棧中什么位置。
先找到cookie值:每次運行之后,都有cookie,所以cookie值可以確定是:0x4bbafd61。小段存儲:61 fd ba 4b
然后就是把這個值作為參數給fizz函數。觀察棧發現,參數是放到了返回地址的上面,並且和返回地址相鄰。先用fizz函數地址覆蓋掉返回地址,可以執行fizz函數,並且要將fizz函數的返回地址覆蓋掉,並用cookie覆蓋掉上面的參數。這樣就可以跳轉到fizz函數,並且在跳轉后自己取到cookie作為參數,fizz函數的返回地址就用00 00 00 00覆蓋掉。
Fizz函數的地址:0x08048c52 即( 52 8c 04 08)
拼好后的樣子:
成功:
Bang:
要求更改全局變量
要自己寫一個惡意代碼,更改全局變量,賦值為cookie,更改完還要轉到bang函數繼續執行。
先找到全局變量的位置:在bang函數里看到有兩個內存地址,正好和源程序里的判斷相等對應,接下來確定哪一個是全局變量。
用gdb調試,在getbuf函數設斷點,運行,查看一下兩個地址的值,很明顯,0x804d100是全局變量。
Mov指令賦值,之后要跳轉到bang函數——將0x08048cad壓棧,結合起來就是這樣:
然后用gcc –m32 –c 編譯成.o可重定位目標文件,然后objdump –d 反編譯出機器碼。如如:
這是惡意代碼,我們需要的是這些16進制的機器碼,我把它們放到buf區域里,然后執行就ok。
要執行這些代碼就需要讓控制流可以跳到這,只要把這段惡意代碼的首地址放到getbuf函數的返回地址處就可以了,也就是buf緩沖區的首地址放到返回地址。接下來找buf緩沖區的首地址:
看一下getbuf函數,發現,在圖中0x80491f7處,ebp減小 開辟了一段空間,也就是buf區域,eax寄存器中放的就是該空間的首地址,即buf首地址。
用gdb調試,在下一行設置斷點,查看eax的值:
也就是 38 35 68 55
拼好的字節碼是:
還是管道輸入。
成功:
Boom:
要求被攻擊程序能返回到原調用函數test繼續執行——即調用函數感覺不到攻擊行為。也就是要恢復ebp的值。
另外,構造攻擊字符串,使得getbuf都能將正確的cookie值返回給test函數,而不是返回值1。
設置返回值也就是更改eax的值,可以用mov指令設置eax存的為cookie值。
更改完要進入test函數繼續執行下面的指令,也就是下圖中這個位置,將這個地址壓棧。
綜合起來,代碼為:
用同bang那關一樣的方法,得到字節碼:
惡意代碼准備好了,將返回地址更改為指向這個代碼的位置,把惡意代碼放到buf緩沖區內,返回地址和bang一樣。
接下來要恢復ebp的值,先得到ebp舊值。
Gdb調試:在getbuf第一行,push ebp 設置斷點。查看ebp的值。
ebp=0x55683590,即90 35 68 55
用這個值覆蓋ebp值。ebp值在返回地址的低方位,放在返回地址前。
綜合如下:
同樣,管道輸入。
成功:
Nitro:
構造攻擊字符串使getbufn函數(注,在kaboom階段,bufbomb將調用testn函數和getbufn函數),返回cookie值至testn函數,而不是返回值1。
需要將cookie值設為函數返回值,復原被破壞的棧幀結構,並正確地返回到testn函數。
這里和上一個的不同之處在於地址空間隨機化。還有這是在testn函數和getbufn函數里。
ebp是隨機的,但是ebp相對esp是絕對的,根據上面的圖中結合棧結構得出
ebp = esp + 0x24 + 4 = esp + 28
getbufn函數返回后要從0x8048e4a開始執行,將這個地址壓棧。
設置cookie給eax。
綜合得出惡意代碼為:
轉換為字節碼。
getbufn函數:
要填入0x208+4+4=528字節。
因為隨機,不知道程序會跳到哪里,所以把惡意代碼放到最后面,用nop滑行。
(nop不會執行任何操作,只有PC加一,機器碼是90。)
所以,前面塞滿90,最后面寫上惡意代碼程序,以及最后要跳的位置。
尋找要跳的地址:
由於隨機化,buf首地址不確定。用gdb調試:在0x8049218設斷點,看eax的值。(每執行一次,要用c命令繼續,進而執行下一次)
例如:
一共5次。
buf首地址的取值范圍在0x55683328~0x556833c8
取最高地址0x556833c8(c8 33 68 55)作為返回地址,這樣就會一路滑行到惡意代碼,執行惡意代碼。
綜合上述:
同上管道輸入。
注意:hex2raw也要加-n!
成功:
有問題歡迎留言~