Cache Me Outside

Published: April 2, 2026

Description

While doing a heap exploit challenge you might encounter a heap dump. Figure out how to exploit this tcache binary. nc mercury.picoctf.net PORT

Remote

Download the binary and the heap dump file.

Analyze the binary with GDB/pwndbg to understand the heap layout.

wget <url>/heapedit
wget <url>/heapedit.zip
chmod +x heapedit

Solution

  1. Step 1Understand the heap layout with GDB
    Run the binary in GDB with pwndbg or peda. The program allocates a buffer and stores the flag on the heap. By examining the heap, you find the flag is located at offset -5144 bytes relative to a specific heap pointer that the program asks you to index into.
    gdb ./heapedit
    # In GDB:
    run
    heap chunks
    Learn more

    The tcache (thread-local caching) is a per-thread free list introduced in glibc 2.26 (2017). When you free a small chunk, it goes into the tcache bin for its size class. The next malloc() of the same size returns the tcache entry immediately -- very fast, but with minimal security checks compared to main arena bins.

    Tcache poisoning works by overwriting the fd (forward pointer) field of a freed tcache chunk to point to an attacker-controlled address. The next two malloc() calls return the attacker's address as if it were a valid heap chunk.

  2. Step 2Send the negative index to reach the flag
    When the program asks for an index, send -5144. This causes the program to write a null byte to the address (heap_base + (-5144)), which overwrites the tcache fd pointer. The next malloc() call returns the address where the flag is stored, and the program prints it.
    python3 << 'EOF' from pwn import * p = remote("mercury.picoctf.net", <PORT>) p.recvuntil(b"input:") p.sendline(b"-5144") p.recvuntil(b"input:") p.sendline(b"") print(p.recvall().decode()) EOF
    Learn more

    The negative index is derived from analyzing the heap layout: the distance in bytes between the buffer the program lets you write to and the tcache entry whose fd pointer you want to overwrite. Dividing the byte offset by the element size gives the negative index.

    The null byte write corrupts the tcache fd pointer to point to the flag's location on the heap. When the program subsequently calls malloc(), tcache returns this poisoned address, and the flag data is read back as if it were freshly allocated memory.

    Modern glibc versions (2.29+) added tcache safe-linking (mangling the fd pointer with a random key) and count-based checks to prevent simple tcache poisoning. Older glibc versions used in CTF challenges often lack these protections.

Flag

picoCTF{...}

Tcache poisoning overwrites the singly-linked free list's next pointer -- the subsequent allocation then returns an attacker-chosen address.

More Binary Exploitation