5

I am trying to learn about format string bugs and I found the gcc option -Wformat-security to raise a warning when a potential format string bug is found. I would like to know if there is a way to evade this check and still have a format bug problem. For example:

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char * argv[])
{
  char outbuf[32];
  char buffer[32];

  if (argc < 2)
  {
     fprintf (stderr, "Error missing argument!\n");
     exit (EXIT_FAILURE);
  }

  snprintf (buffer, 28, "ERR Wrong command: %8s", argv[1]);
  sprintf (outbuf, buffer);

  perror(outbuf);

  return EXIT_SUCCESS;
}

When compiled in 32bits, it will crash on %21d input (not on %20d, but on any number higher than 20). But, the -Wformat-security will detect it and raise a warning as follow:

$> gcc -m32 -Wall -Wextra -Wformat-security -std=c99 -o fstring fstring.c 
fstring.c: In function ‘main’:
fstring.c:19:3: warning: format not a string literal and no format arguments [-Wformat-security]
   sprintf (outbuf, buffer);
   ^

So, is there a way to hide the bug from the warning and still have a possible exploitation ?

Edit: My point is not to correct the bug, but to understand what kind of format string bugs are not captured by this warning. It helps to understand where to look if no warning is raised but potential format string bugs are present.

perror
  • 853
  • 2
  • 10
  • 27

2 Answers2

6

You must keep secure format of the function and with using to junk arguments bypass format-security.
for example printf(var); is 100% unsafe format ! and compiler able to detect it, but printf(var1,var2) (it can be safe and also dangerous) ! the compiler is not smart enough to detect .
You can use a code like it printf(argv[1],"junk");

For Example

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char * argv[])
{
  printf (argv[1],argc);
  //              ^^^^---------> Junk :)
  return EXIT_SUCCESS;
}
/*
sajjad@xxx:~$ gcc -m32 -Wall -Wextra -Wformat-security -std=c99 a.c 
sajjad@xxx:~$ ./a.out %n%n%n
Bus error: 10
sajjad@xxx:~$ ./a.out %s%s%s
Bus error: 10
sajjad@xxx:~$ ./a.out %x%x%x
bffcfb242bffcfb88sajjad@xxx:~$ ./a.out %d%d%d
-10747629722-1074762872sajjad@xxx:~$ ./a.out %s
???|???sajjad@xxx:~$
/*

/*

#include <stdio.h>
#include <stdlib.h>

int main (int argc, char * argv[])
{
  char outbuf[32];
  char buffer[32];

  if (argc < 2)
  {
     fprintf (stderr, "Error missing argument!\n");
     exit (EXIT_FAILURE);
  }

  snprintf (buffer, 28, "ERR Wrong command: %8s", argv[1]);
  sprintf (outbuf,buffer, "junk");
  //                      ^^^^^^---------> Junk :)
  perror(outbuf);

  return EXIT_SUCCESS;
}

*/
Sajjad Pourali
  • 944
  • 1
  • 10
  • 22
  • If I understand it well, even only one argument to the format string function will allow to disable the check even if the vulnerability is still here. Thanks for this example code ! – perror Nov 12 '13 at 00:12
1

Invoking through a function pointer is another way to evade -Werror=format-security

The first example below triggers the format-security error while the second does not, but I am not sure why this works.

1st example (format-security error triggered):

char * format = "Hello World\n";
printf(format);

2nd example (format-security error bypassed):

char * format = "Hello World\n";
int (*alias)(const char *, ...) = printf;
alias(format);
textral
  • 111
  • 3