Ojs
Ojs

Reputation: 954

In buffer overflow return address is overwritten with incorrect address but it still works

I'm trying to make buffer overflow and here is my 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, "brillig") == 0)
     auth_flag = 1;
   if(strcmp(password_buffer, "outgrabe") == 0)
     auth_flag = 1;

   return auth_flag; 

}




int main(int argc, char *argv[]) {

   if(argc < 2) {
      printf("Usage: %s <password>\n", argv[0]);
      exit(0);
    }
    if(check_authentication(argv[1])) {
      printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
      printf(" Access Granted.\n");
      printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
    } 

    else {
      printf("\nAccess Denied.\n");
    }
}

The provided password from command line will be compared to "brilling" and "outgrabe" if user input matches any of these, access will be granted, if not it will be denied. As I know if provided password will be greater than 16 return address will be overwritten but when I input "A" 17 it is not overwritten. Instead of that auth_flag is overwritten and is 65(0x41 in hex which is A). I can't figure out why the variable is overwritten instead of return address. I'm compiling with this

gcc -fno-stack-protector -z execstack -g -o test test.c

Hope you guys can help. Thanks.

Upvotes: 4

Views: 886

Answers (2)

dureuill
dureuill

Reputation: 2576

As Sourav Ghosh said, your program invokes undefined behavior.

In practice, this means you need to dive into the generated code to see how the stack is used.

As this relies heavily on your environment (machine, OS, compiler version, etc.), there is little we can do to debug it for you. In my environment, the authenticated flag is stored at ebp-12, while the buffer is stored at ebp-28. ebp-28 is passed to strcmp, meaning that overflow will result in authenticated being overwritten. A longer string will eventually smash the return address : "1234567890123456000000000000" triggers a segfault in my place.

A recommended starting point could be compiling to assembly:

gcc -fno-stack-protector -z execstack -g -S test.c 

generates test.s which will show you how your stack look. You can also look at the binary using de-assemblers (objdump and ida pro come to mind), if compiling from source is not a facility you can afford ;-).

EDIT: From your pastebin, here is what I gather:

There clearly appears to be some form of stack protection:

 movl    %gs:20, %eax
 [...]
 movl    -12(%ebp), %edx
 xorl    %gs:20, %edx
 je      .L5
 call    __stack_chk_fail

The __stack_chk_fail is called if the place at -12(%ebp) is not %gs:20 anymore (eg your stack has been corrupted).

As a side note, if a real attacker who wants to bypass authentication can control the value of your "authenticated" flag, they won't even bother to try and erase the return address for the beauty of it.

Upvotes: 3

Sourav Ghosh
Sourav Ghosh

Reputation: 134286

Once the input (password) string contains more than 15 (not 16, need terminating null) charcater, using strcpy() will invoke undefined behaviour.

  • Before that (unless that happens), your program is fine.
  • After that happens, you cannot predict anything.

So, after your program shows UB, you cannot expect it to behave in a desired way. It can do anything and everyting expected or unexpected. Whether it overwrites auth_flag or not, cannot be determined.

Maybe, it's worthy to mention that the allocation of memory for variables does not necessarily take place in any particular order (of appearance). Your compiler is free to allocate memory in any order it sees fit.

Upvotes: 0

Related Questions