format string 0
- Description: Can you use your knowledge of format strings to make the customers happy?
- Difficulty: Easy
🔎 Solution
This challenge focuses on exploiting a format string vulnerability through the use of the printf
function.
The goal is to trigger a segmentation fault in the program, which leads to the flag being printed via a custom signal handler:
void sigsegv_handler(int sig) {
printf("\n%s\n", flag);
fflush(stdout);
exit(1);
}
Method 1: Bypassing Patrick and crashing Bob
Upon connecting to the server, you're first asked to recommend burgers for a customer named Patrick. The valid options are: Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe
Looking at the function serve_patrick()
, the program only proceeds to the next step (serving Bob) if the following condition is met:
int count = printf(choice1);
if (count > 2 * BUFSIZE) {
serve_bob();
}
Here, BUFSIZE
is defined as 32, so count
must be greater than 64 to reach serve_bob()
.
Let's take a closer look at the input Gr%114d_Cheese.
This includes a valid format specifier %114d
, which tells printf
to print an integer with a minimum field width of 114 characters.
printf
will fetch an integer from the stack (or register depending on architecture), and output it padded to 114 characters.
The actual length of the printed string becomes:
- "Gr" → 2 characters
- %114d → 114 characters
- "Cheese" → 6 characters
→ Total: 122 characters, well over the 64-character threshold.
This allows us to bypass Patrick successfully:
Enter your recommendation: Gr%114d_Cheese
Gr 4202954_Cheese
Good job! Patrick is happy! Now can you serve the second customer?
Now we must serve Bob, who accepts 3 burger names: Pe%to_Portobello, $outhwest_Burger, Cla%sic_Che%s%steak
Examining the input Cla%sic_Che%s%steak, it contains 3 %s
specifiers.
When printf()
encounters %s
, it attempts to read a char*
from the stack and then prints the string at that memory address.
If these addresses are invalid or uninitialized, the result is a segmentation fault (SIGSEGV
).
And since there's a signal handler in place for SIGSEGV
, this crash reveals the flag:
Enter your recommendation: Cla%sic_Che%s%steak
ClaCla%sic_Che%s%steakic_Che(null)
picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_c8362f05}
Method 2: Triggering a crash directly in Patrick's handler
Alternatively, the vulnerability can be exploited earlier during Patrick's stage by overflowing the buffer directly.
In serve_patrick()
, user input is stored using:
char choice1[BUFSIZE];
scanf("%s", choice1);
Since there is no bounds checking, inputting a string longer than 32 characters will overflow the buffer and potentially corrupt adjacent memory, causing a segmentation fault. This again triggers the signal handler and prints the flag:
Enter your recommendation: abcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefghabcdefgh
There is no such burger yet!
picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_c8362f05}
🚩Flag
picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_c8362f05}