#include #include void call_me(void) { system("/bin/sh"); } void print_proc_maps() { FILE *f = fopen("/proc/self/maps", "r"); char buf[4096]; size_t len; if (f == 0) { perror("Couldn't open /proc/self/maps!"); } while ((len = fread(buf, 1, 4096, f)) > 0) { fwrite(buf, 1, len, stdout); } fclose(f); } void secure_function() { char input[512]; unsigned long long your_number = 0; input[0] = 's'; puts("------------ Welcome to format string exploitation! ------------ \n" "Format strings are dangerous. Never call `printf` on untrusted input.\n" "Because `printf` is varargs, it cannot know how many arguments were \n" "passed to it. As a result, it relies purely on the format string and \n" "will happily read off as many arguments as are requested by the string"); puts("Here are some useful tools for developing your exploit:"); puts("1. $ operator: used to select which argument to print, e.g. `%10$c` \n" "will print the tenth argument as a char"); puts("2. `n` format specifier: writes the number of characters printed so \n" "far into the location specified by the current argument, i.e. the \n" "current argument must be a pointer to where to write"); puts("3. Field widths: Pads the value to a minimum of the specified size, \n" "e.g. %60c will print 59 spaces with a character at the end. (useful \n" "for adjusting printed character count in preparation for a %n)"); puts("4. Length modifiers: l and h. Modify the length of the current \n" "argument by prepending a 'long' or 'short' to the type, respectively.\n" "e.g. %hd will print a short (16-bit), %lld will print a long long int\n" "(64-bit). Can also be applied with %n to write more/fewer bytes.\n"); puts("By the way, here's my /proc/self/maps:"); print_proc_maps(); puts(""); printf("In this binary, you want to try to call `call_me` at %p\n", (void *)&call_me); puts("With that said, exploit me!"); while (input[0] != '\n') { printf("Give me a number: "); fgets(input, 512, stdin); your_number = strtoull(input, NULL, 0); printf("OK, I wrote 0x%llx to `your_number` at %p\n", your_number, &your_number); printf("Go ahead: "); fgets(input, 512, stdin); printf(input); } } void main() { secure_function(); }