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)
buffer overflow that shouldnt happen (?)
-
21-09-2022 - |
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?
Solution
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.