fermat-strings picoMini by redpwn Solution

Published: April 2, 2026

Description

Fermat's last theorem meets format strings.

Connect to the challenge server with netcat.

Download the binary for local analysis.

bash
nc <challenge_host> <PORT_FROM_INSTANCE>
bash
wget <challenge_url>/fermat-strings  # binary for local analysis
  1. Step 1Confirm the format string vulnerability
    Connect and send %p.%p.%p.%p as input. If the server echoes back memory addresses instead of the literal string, you have a format string vulnerability - the input is passed directly to printf without a format string argument.
    bash
    echo '%p.%p.%p.%p' | nc <challenge_host> <PORT_FROM_INSTANCE>
    bash
    echo '%1$p.%2$p.%3$p' | nc <challenge_host> <PORT_FROM_INSTANCE>
    Learn more

    A format string vulnerability arises when user-controlled input is passed as the format string to printf, sprintf, or similar functions. Instead of safe code like printf("%s", user_input), the vulnerable code calls printf(user_input) directly. This lets the attacker control what printf interprets as format specifiers.

    %p causes printf to read a pointer-sized value from the stack and print it as a hex address. By sending many %p specifiers, you can dump the entire printf argument list - which corresponds to consecutive stack words. This leaks stack data including saved return addresses, canary values, and libc pointers.

    Direct parameter access (%N$p) lets you read the Nth argument directly without iterating: %7$p reads the 7th stack word. This is useful for targeting a specific known offset, such as the stack canary position.

  2. Step 2Leak the stack canary and libc address
    Use %N$p specifiers with increasing N to dump stack words. The canary is recognizable - it ends in \x00 and looks like 0x00007f...XXXXXXXX. A libc address will be in the 0x7f... range and offset from a known libc symbol.
    bash
    # Automate leak with pwntools
    python
    python3 -c "
    python
    from pwn import *
    bash
    p = remote('<host>', <PORT_FROM_INSTANCE>)
    bash
    p.sendline('%11$p.%15$p.%23$p')  # adjust indices
    python
    print(p.recvline())
    bash
    "
    Learn more

    Stack canaries are random values placed between local variables and the saved return address by GCC when compiled with -fstack-protector. Before the function returns, the canary is checked against its original value - if it changed (due to a stack overflow), the program aborts. Format string reads bypass this: you leak the canary value, then include the correct canary in your overflow payload so the check passes.

    To find which stack position holds the canary, look for a value that: (1) ends in a null byte (\x00), (2) is 8 bytes wide, and (3) changes every run. The null byte is intentional - it terminates C strings and prevents the canary from being leaked by %s, though %p still reads it.

  3. Step 3Write to a target address using %n
    Use the %n specifier to write the number of characters printed so far into a target address on the stack. Craft a payload that positions the target address on the stack, then uses %Nc%offset$n to write the desired value byte by byte.
    bash
    # pwntools fmtstr_payload helper
    python
    python3 -c "
    python
    from pwn import *
    bash
    # fmtstr_payload(offset, {target_addr: value_to_write})
    bash
    payload = fmtstr_payload(6, {0x404080: 0xdeadbeef})
    python
    print(payload)
    bash
    "
    Learn more

    %n is the most dangerous printf specifier - it writes the count of characters printed so far to the address stored in the corresponding argument. By controlling the character count (via padding like %100c) and the address on the stack, an attacker can write arbitrary values to arbitrary memory locations.

    pwntools' fmtstr_payload() automates this entirely. Given the offset (which stack position holds the first attacker-controlled word) and a dictionary of {address: value}, it generates the optimal format string. It uses %hhn (write 1 byte) to minimize the character count needed, writing one byte at a time.

    Common write targets: the GOT entry for printf itself (overwrite with system so the next printf(input) calls system(input)), or __free_hook, or the saved return address after leaking its position.

Flag

picoCTF{...}

Format string vulnerability - send %p specifiers to leak the stack canary and libc base, then use %n writes (or pwntools fmtstr_payload) to overwrite a GOT entry or function hook with system.

Want more picoMini by redpwn writeups?

Useful tools for Binary Exploitation

Related reading

What to try next