Auditing puzzle
Monday, 28. May 2007, 22:13:21
#include <string.h>
#include <stdio.h>
#include <locale.h>
#include <ctype.h>
int main(int argc, char **argv)
{
char buf[128];
int len;
/* initialise the buffer */
memset(buf, '\0', sizeof(buf));
/* setup locale for toupper() */
setlocale(LC_ALL, "");
/* check an argument was specified */
if (argc >= 2) {
/* get the first 10 characters */
len = snprintf(buf, sizeof(buf), "you entered: %.10s", argv[1]);
/* check for non-printing characters */
while (len--)
buf[len] = isprint(buf[len]) ? toupper(buf[len]) : '?';
/* output string */
fprintf(stdout, "%s\n", buf);
}
return 0;
}
Scroll down for discussion.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
snprintf() wont overrun the `buf` buffer, so specifying too much data wont cause a crash
$ ./a.out `perl -e 'print "A"x"1024"'`; echo $? YOU ENTERED: AAAAAAAAAA 0
However, the return code from snprintf() isnt checked, and it can return -1 for a number of reasons, including malloc() failing, or invalid multibyte characters in the string. If any of the users of this application are using a utf8 locale, they could be vulnerable to a security issue.
$ LC_ALL=en_GB.utf8 ./a.out `printf "\x80foobar"`; echo $? Segmentation fault 139
Its worth remembering that a number of common libraries will call setlocale() for you in their constructors, so even if you didnt intend to, it could be called for you. Using the return code from snprintf() or sprintf() without testing for failure could result in multiple security vulnerabilities, so its always worth checking even if you dont modify the locale.