rht rht - 3 months ago 11
C Question

No error message when using system() to execute program with buffer overflow vulnerability

Consider the following program (

vul.c
) with buffer overflow vulnerability.

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

int main(int argc, char **argv)
{
char buf[10];
strcpy(buf, argv[1]);
printf("%s\n", buf);
return 0;
}


Above program compiled using
gcc -o vul vul.c
and executed on
arch linux - linux 4.4.16-1-lts x86-64
gave following output when executed in terminal with
./vul $(perl -e 'print "A"x100')
command:

AAAAAAAAAAA...A
Segmentation fault (core dumped)


Then checking the program status using
echo $?
command gave
139
output.

Following program (
exp.c
) (for crashing the above program)

#include <stdlib.h>

int main(void)
{
printf("%d\n", system("./vul $(perl -e 'print \"A\"x100')"));
return 0;
}


compiled using
gcc -o exp exp.c
when executed with
./exp
command on same system gave following output:

AAAAAAAAAAAA...A
139


I have two questions:


  1. Why no error message was generated by 2nd program? and,

  2. I need to compile the program with
    -fstack-protector
    flag to enable the
    *** stack smashing detected ***
    error messages in
    arch linux
    but not in
    Ubuntu
    . In
    Ubuntu
    , it might be that this flag is include by default in
    gcc
    or is there any other reason?


Answer

As I pointed out in my comment,system returns an int with the programs's return value, which is normally it's error code (0 if successful).

If you want to print the error as a nice looking message, you can probably use strerror.

According to @rht's comment (see my next edit) and the answers to the question referenced in that comment, the returned value will be 0 on success and on error it will be error | 0x80. To get the original error code, use 128 - err_code.

try this:

#include <stdlib.h>
#include <errno.h>

int main(void)
{
    int tmp = system("./vul $(perl -e 'print \"A\"x100)");
    if(tmp < 0)
       error("Couldn't run system command");
    else if(tmp >0)
       printf(stderr, "System command returned error: %s", strerror(128 - tmp));
    else
       ; // nothing
    return 0;
}

The fact that vul.c does (or does not) print an error message should be irrelevant for your exp.c program, since it depends on vul.c's compile flags values and any default compiler flags - things exp.c can't control.

EDIT(2) - in answer to the comment.

It could be that the error message returned isn't an errno value, but a signal trap value.

These are sometimes hard to differentiate and I have no good advice about how you can tell which one it is without using memcmp against the answer.

In this case you know vul.c will never return it's errno value, which leaves you only with signal trap errors, so you can use strsignal to print the error message.

As pointed out in @rht's comment, which references this question:

Passing tmp to strsignal generates the same error message: "unknown signal 139". The reason is that there is no signal with this signal number. /usr/include/bits/s‌​ignum.h contains all the signals with their signal numbers. Passing tmp-128 to strsignal works.

i.e.

#include <stdlib.h>
#include <string>

int main(void)
{
    int tmp = system("./vul $(perl -e 'print \"A\"x100)");
    if(tmp < 0)
       error("Couldn't run system command");
    else if(tmp >0)
       printf(stderr, "System command returned error: %s", strsignal(tmp - 128));
    else
       ; // nothing
    return 0;
}

EDIT

The question was edited because it's code was mis-copied. I altered the answer to reflect that change.