Question

I have the following program

 1  #include <stdio.h>
 2  #include <stdlib.h>
 3  #include <string.h>
 4  
 5  int check_authentication(char *password){
 6  char password_buffer[16];
 7  int auth_flag =0;
 8  
 9  
10  strcpy(password_buffer, password);
11  
12  if(strcmp(password_buffer, "brillig" ) == 0 )
13  auth_flag = 1;
14  if(strcmp(password_buffer, "outgrabe") == 0)
15  auth_flag = 1;
16  
17  return auth_flag;
18  }
19  
20  int main(int argc, char *argv[]){
21  if (argc<2){
22  printf("Usage: %s <password>\n", argv[0]);
23  exit(0);
24  }
25  
26  if(check_authentication(argv[1])){
27      printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n");
28      printf("    Access Granted.\n");
29      printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n");
30      }
31  else {
32  printf("\n Access Denied. \n");
33  }
34  }

I am running it supplying 30 bytes of As through gdb... and I am setting the following breakpoints

(gdb) break 9
Breakpoint 1 at 0x80484c1: file auth_overflow2.c, line 9.
(gdb) break 16
Breakpoint 2 at 0x804850f: file auth_overflow2.c, line 16.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

So far so good. Everything goes as it was supposed to go even till the next breakpoint

Breakpoint 1, check_authentication (password=0xbffff6d2 'A' <repeats 30 times>)
at auth_overflow2.c:10
10  strcpy(password_buffer, password);
(gdb) x/s password_buffer 
 0xbffff484:    "\364\237\374\267\240\205\004\b\250\364\377\277\245",            <incomplete      sequence \352\267>
 (gdb) x/x &auth_flag
 0xbffff494:    0x00

Now we see the following information:

variable auth_flag is in address 0xbffff494 and variable buffer is in the address 0xbffff484. Since address of var auth_flag is greater than the address of buffer and the stack grows towards lower addresses that means that additional (overrun of the buffer) bytes in the buffer variable WILL NOT OVERWRITE auth_flag. Right ?

But gdb has a different opinion...

(gdb) cont
Continuing.

Breakpoint 2, check_authentication (
password=0xbf004141 <Address 0xbf004141 out of bounds>)
at auth_overflow2.c:17
17  return auth_flag;
(gdb) x/s password_buffer 
0xbffff484: 'A' <repeats 30 times>
(gdb) x/x &auth_flag
0xbffff494: 0x41

and ...

(gdb) x/16xw &auth_flag
0xbffff494: 0x41414141  0x41414141  0x41414141  0xbf004141
0xbffff4a4: 0x00000000  0xbffff528  0xb7e8bbd6  0x00000002
0xbffff4b4: 0xbffff554  0xbffff560  0xb7fe1858  0xbffff510
0xbffff4c4: 0xffffffff  0xb7ffeff4  0x080482bc  0x00000001

We see that auth_flag was overwritten with these 0x41 (=A) although this variable was in a lower position in stack. Why this happened?

Was it helpful?

Solution

Stack growth direction has nothing to do with where the extra bytes go when you overrun a buffer. Overruns from strcpy are always going to be into higher addresses (unless overrun so far that you wrap around to address 0, which is pretty unlikely)

OTHER TIPS

Objects are stored in memory from lower udresses up to higher addresses. As you can not guarantee that the length of the string refered to by parameter password is less than 16 then your code is invalid. In fact there is no any need in the local buffer password_buffer. The function could be written the following way

_Bool check_authentication( const char *password )
{
    return ( strcmp( password, "brillig" ) == 0 || strcmp( password, "outgrabe" ) == 0 );
}

Instead of the return type _Bool you may use type int as in your function realization. In any case either 1 or 0 will be returned.

the compiler can freely reorder the stack of variables therefore in this case it's always char array before int variable. This makes the program vulnerable for stack-based buffer overflow.

In order to change the following:

(gdb) x/s password_buffer 
0xbffff484: 'A' <repeats 30 times>
(gdb) x/x &auth_flag
0xbffff494: 0x41

into expected answer as below:

(gdb) x/s password_buffer 
0xbffff494: 'A' <repeats 30 times>
(gdb) x/x &auth_flag
0xbffff484: 0x00

We simply add a -fstack-protector-all argument during compilation and the result will be as expected. To be vice-versa, perhaps you can use -O0 or -fno-stack-protector.

Answer from: https://stackoverflow.com/a/21215205/3205268

If you are reading in more then 15 bytes you will get that. strcpy will look for the end of the string. You could use something like strncpy to only copy a limited number of characters.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top