Buffer overflow flows backwards?

6

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?

c
debugging
gdb
asked on Stack Overflow Jul 22, 2019 by (unknown user)

1 Answer

0

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.

answered on Stack Overflow Jul 22, 2019 by Florian Weimer

User contributions licensed under CC BY-SA 3.0