format string 0

Walkthrough of a format string exploit: stack layout, printf misuse, and secure coding lessons.

2 min read
CybersecurityBinary ExploitationFormat Specifiers

I solved this one by playing around with the program. I usually do this with all picoCTF executables, just to get a feel for the problem. I try various input vectors like buttons, text, and other available components.

But let's go through the main concept behind this CTF: format specifiers. A format specifier is used as a placeholder to define the format of an input (like a variable) and how the compiler should interpret it. Why use format specifiers? Well, it's so that we can dynamically display values by telling the compiler what types it should expect and providing that dynamic value.

Back to the challenge! Connecting to the instance, we're greeted with:

Welcome to our ...
Please choose from the following burgers: Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe

Now let's look at the corresponding code:

char choice1[BUFSIZE];
scanf("%s", choice1);

and later on:

int count = printf(choice1);
if (count > 2 * BUFSIZE) {
    serve_bob();
}

The program expects an input of size BUFSIZE (defined as 32 bytes) stored as choice1. choice1 is then directly fed into printf(), which returns the number of characters printed. The only issue is... we control choice1 (to a certain extent)! Looking at the options, the %114d in Gr%114d_Cheese requests a digit and pads it to be 114 characters wide. Hence, our count will far exceed the 2 * 32 character count, letting us enter the if statement and call serve_bob().

serve_bob() uses a similar approach. Looking deeper into the source code, we can find this:

void sigsegv_handler(int sig) {
    printf("\n%s\n", flag);
    fflush(stdout);
    exit(1);
}

This code seems to print our flag and is caused by a segmentation fault (segfault)—when a program tries to access a memory location that it's not allowed to access. The Cla%sic_Che%s%steak option seems to read strings off the stack (again, since we don't pass in anything to printf()). If %s continues reading off the stack, maybe one will read from an invalid pointer, causing the segfault.

After inputting the Cla%sic_Che%s%steak option, we indeed get a segfault, leading to our flag to be printed.

Thanks for reading! Found this useful? Share it or reach out with thoughts.

© 2025 Emir Durakovic. All rights reserved.