Input Injection 2

Published: April 2, 2026

Description

Two heap allocations sit adjacent in memory. Overflow the first to corrupt the second and redirect execution to print the flag.

Remote

Connect to the challenge server.

Analyze the binary to understand its heap allocation pattern.

nc <host> <PORT>

Solution

  1. Step 1Map the heap layout
    Use GDB with pwndbg to visualize the heap. Identify the two malloc'd chunks and their sizes. The distance between the start of the first buffer and the start of the second is the overflow offset.
    gdb ./binary
    heap chunks
    Learn more

    The heap is a region of process memory used for dynamic allocations via malloc() / free(). Unlike the stack, which grows and shrinks in a last-in-first-out order, the heap is managed by an allocator (glibc's ptmalloc on Linux) that tracks free and allocated regions using metadata structures called chunks.

    Each heap chunk has a header (16 bytes on 64-bit systems) that stores the chunk's size and status flags. The usable data starts immediately after this header. When two malloc() calls are made in sequence with no intervening frees, the resulting chunks are typically adjacent: the second chunk starts at chunk1_start + chunk1_size + header_size. Overflowing the first buffer's data region can thus reach into the second chunk's header or data.

    pwndbg is a GDB plugin that enhances heap inspection. The heap chunks command displays all allocated and free chunks with their addresses, sizes, and contents - making the layout immediately visible without manual memory arithmetic.

  2. Step 2Determine the target value
    The second allocation holds a function pointer or command string. Decide what value to write there - typically a win function address or the string '/bin/sh'.
    Learn more

    Function pointers stored in heap memory are attractive overflow targets because overwriting them with a different address redirects execution when the pointer is called. A common pattern in CTF challenges is a struct where one member is a character buffer and another is a function pointer - overflowing the buffer overwrites the pointer with the address of a win() function that prints the flag.

    To find the address of the target function, use GDB: p win or info functions win. If the binary has no PIE (Position Independent Executable), addresses are fixed and can be read directly from Ghidra or objdump -d binary | grep win. With PIE enabled, a leak of the binary base address is required first.

    Alternatively, the second buffer might hold a system command string (like ls or date) that is passed to system(). Overwriting it with /bin/sh\x00 turns the call into system("/bin/sh"), spawning an interactive shell. The null byte terminator is important - without it, the string may continue past the intended characters and confuse the shell.

  3. Step 3Send the heap overflow payload
    Send padding equal to the heap distance followed by the target value. The second allocation is overwritten, triggering the flag output.
    python3 -c "from pwn import *; p=remote('<host>',PORT); p.sendline(b'A'*<offset>+b'/bin/sh\x00'); p.interactive()"
    Learn more

    The heap overflow payload follows the same structure as a stack overflow: padding to reach the target, then the value to write there. The critical difference is that the offset is determined by the heap allocator's chunk layout rather than the stack frame layout. Chunk headers and alignment padding (the allocator rounds sizes up to multiples of 16) mean the actual distance can be slightly larger than the logical buffer size.

    Heap exploitation is a rich field with many advanced techniques beyond simple buffer overflows: use-after-free (UAF), double-free, tcache poisoning, house-of-force, and others. This challenge represents the simplest form - a linear overflow into an adjacent chunk - which builds intuition for the heap's memory layout before tackling those more complex primitives.

    In modern systems, heap metadata corruption is detected by allocator integrity checks (e.g., malloc_consolidate() verifies chunk sizes). Challenges that allow clean data overwrites without touching chunk headers bypass these checks, while more advanced exploitation requires careful manipulation of metadata to avoid triggering allocator assertions.

Flag

picoCTF{...}

Heap overflows differ from stack overflows in that the target is adjacent malloc&apos;d memory - chunk headers and allocator alignment determine the exact offset.

Want more picoMini by CMU-Africa writeups?

Useful tools for Binary Exploitation

More Binary Exploitation