Im reading the book "Hacking: The Art of Exploitation" and I came across a part of the book where it shows a supposed protection against buffer overflow vulnerabilities by rearranging variables in memory. I tried this and the program is still vulnerable to buffer overflows. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int check_authentication(char *password) {
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
char password_buffer[16];
int auth_flag = 0;
//*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
strcpy(password_buffer, password);
if (strcmp(password_buffer, "password1") == 0)
auth_flag = 1;
if (strcmp(password_buffer, "password2") == 0)
auth_flag = 0;
return auth_flag;
}
int main(int argc, char *argv[]) {
if (check_authentication(argv[1])) {
printf("ACCESS GRANTED");
} else {
printf("ACCESS DENIED");
}
}
This program, in short, checks an authentication key provided by the second command line argument and tells the user whether or not access was granted. The main point of focus is on the variables outlined by the comments with the asterisks. Theoredically, this arrangement of variables should prevent a buffer overflow attack as a result of the FILO data structure, meaning the password buffer should be located AFTER the auth_flag variable and therefore should prevent the password buffer from being an execution point for a buffer overflow. Here is an examination of the execution flow in GDB:
(gdb) break 9
Breakpoint 1 at 0x1188: file auth_overflow2.c, line 9.
(gdb) break 16
Breakpoint 2 at 0x11d7: file auth_overflow2.c, line 16.
The first step in examining the program is to set breakpoints at line 9 (where the strcpy function is executed, before password authentication) and at line 16 (where the auth_flag is returned and the password authentication has then occurred). Then, we can run the program and examine the memory at breakpoint 1.
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Starting program: /home/user/Hacking/a.out aaaaaaaaaaaaaaaaaaaaaaaaaaaa
Breakpoint 1, check_authentication (password=0x7fffffffe484 'a' <repeats 29 times>) at auth_overflow2.c:9
9 strcpy(password_buffer, password);
(gdb) x/s password_buffer
0x7fffffffe060: ""
(gdb) x/x &auth_flag
0x7fffffffe07c: 0x00
(gdb)x/16xw &auth_flag
0x7fffffffe07c: 0x00000000 0xffffe0a0 0x00007fff 0x55555229
0x7fffffffe08c: 0x00005555 0xffffe188 0x00007fff 0x00000000
0x7fffffffe09c: 0x00000002 0x55555270 0x00005555 0xf7e0609b
0x7fffffffe0ac: 0x00007fff 0x00000000 0x00000000 0xffffe188
As we can see from the output above, the auth_flag is at a proper 0 and the password buffer is empty. The last command in the output above also demonstrates that the auth_flag variable is properly located BEFORE the password buffer, so in theory a buffer overflow shouldn't effect the auth_flag variable in any way. Now lets continue the program and examine the memory after the authentication check.
(gdb) cont
Continuing.
Breakpoint 2, check_authentication (password=0x7fffffffe484 'a' <repeats 29 times>) at auth_overflow2.c:16
16 return auth_flag;
(gdb) x/s password_buffer
0x7fffffffe060: 'a' <repeats 29 times>
(gdb) x/x &auth_flag
0x7fffffffe07c: 0x61
(gdb) x/16xw &auth_flag
0x7fffffffe07c: 0x00000061 0xffffe0a0 0x00007fff 0x55555229
0x7fffffffe08c: 0x00005555 0xffffe188 0x00007fff 0x00000000
0x7fffffffe09c: 0x00000002 0x55555270 0x00005555 0xf7e0609b
0x7fffffffe0ac: 0x00007fff 0x00000000 0x00000000 0xffffe188
As you can see from the output above, the auth_flag variable was somehow changed to a non-zero value even though the password buffer is located after the auth_flag variable.
So, with all of this information in mind, how is it possible that a buffer overflow flows BACKWARD in memory instead of forward?
Some compilers rearrange on-stack arrays so that they are not adjacent to the return address if there are other variables or spill slots in the stack frame, in the hope that limited overflows of a few bytes will no longer be able to reach the return address and thus redirect execution. If these variables are equally critical for security as the return address, this heuristics goes wrong, and in your hypothetical example, this appears to be the case.
User contributions licensed under CC BY-SA 3.0