This is my first venture into overflowing buffers – reason why this is important in ‘hacking’ is that it can override memory addresses with unwanted consequences. It is a good idea to revise stack frames.

Here is some example of code that is vulnerable to a buffer overflow. You can find it here, or copy paste it below.

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

int check(char *password) {
    int auth = 0;
    char buffer[4];
    strcpy(buffer, password);

    if (strcmp(buffer, "abcd") == 0) {
        auth = 1;
    }

    return auth;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        printf("Usage: ./overflow <password>\n");
        exit(1);
    }

    if (check(argv[1])) {
        printf("Correct password.\n");
    } else {
        printf("Incorrect password.\n");
    }

    return 0;
}

Initial impressions should tell you that we are aiming to overflow the buffer declared in line 7, since there are no checks that our ‘*password’ has a length less than or equal to 4.

Remember to compile with -fno-stack-protector to disable inbuilt checks in gcc for overflows.

Perfect. Clearly ‘12345’ is not the same as ‘abcd’ yet we have obtained the ‘correct’ password. But what’s really happening? Let’s visualise the stack.

So what should be happening is that when we go over 4 chars, we start overriding the elements at the bottom of our stack; and we’ll get a segmentation fault once we override something important.

Segmentation fault when we start overwriting the saved ebp from our stack frame. ‘1234’ occupies our buffer, ‘5678’ occupies the 4 bytes of our int, and string terminator ‘\0’ intrudes on our ebp.

Let’s disassemble our function just to confirm that our stack is what we think it is. Compiling with -m32 as always as (rn) I’m an x86 person. Also make sure disassembly-flavor is set to intel.

Lets annotate the assembly.

0x000005ad <+0>:	push   ebp
      Save EBP from main()
0x000005ae <+1>:	mov    ebp,esp
      Move our stack pointer (esp) to where our base pointer is
0x000005b0 <+3>:	push   ebx
      'push' a variable to top of our stack - function input *password
0x000005b1 <+4>:	sub    esp,0x14
      Allocate 14 bytes to frame - remember frame grows downwards
0x000005b4 <+7>:	call   0x4b0 <__x86.get_pc_thunk.bx>
0x000005b9 <+12>:	add    ebx,0x1a13
      Function input *password
0x000005bf <+18>:	mov    DWORD PTR [ebp-0xc],0x0
      Allocate 4 bytes from ebp-0xc to ebp for our int auth
0x000005c6 <+25>:	sub    esp,0x8
0x000005c9 <+28>:	push   DWORD PTR [ebp+0x8]
0x000005cc <+31>:	lea    eax,[ebp-0x10]
      Set pointer of our buffer (ebp-0x10) to eax
0x000005cf <+34>:	push   eax
0x000005d0 <+35>:	call   0x420 <strcpy@plt>
      Copy to eax (which is set to our buffer)

Let’s check whether our assumptions were right.

As expected – our ‘buffer’ is located before ‘auth’ in memory and can thus overflow into ‘auth’. ‘12345’ thus fills the buffer with ‘1234’ and auth with ‘5’ which corresponds with an ascii value of 53. As 53 is a non-zero value, this causes our main function to print “Correct Password” despite our ‘password’ of ‘12345’ being definitely different from ‘abcd’.

Our stack with address values

Note how come our strcpy allocated space to our buffer in our stack – now what would happen if we declared our ‘auth’ after our buffer instead of before?

...

int check(char *password) {
    char buffer[4];
    strcpy(buffer, password);
    int auth = 0;

    if (strcmp(buffer, "abcd") == 0) {
 
....

Not surprisingly, we can no longer overflow our buffer to set our flag to a non-zero value. This is because our ‘auth’ flag is now in a lower memory address (higher in the stack) than our buffer.

Our ‘new’ stack

So while we probably won’t be using a buffer overflow in our exploiting endeavors anytime soon, due to reliance on the stack to be in a certain order, as well as inbuilt protection by compilers, learning about buffer overflows was hopefully useful for refreshing your knowledge about stack frames. But do we need the stack to be in a certain order? Let’s try to override the return address of the function instead.


0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *