I have been doing 32bit buffer overflows for some time and I decided to try some 64bit overflows, to explore some more realistic scenarios. I have compiled my code with gcc -fno-stack-protector -z execstack -no-pie overflow.c -o Overflow.

Here is the code:

#include <stdio.h>
#include <string.h>
void function(char *str)
    char buffer[32];

int main(int argc, char **argv)

Using gdb I determined how many bytes I need to write to control the return address. This is 40 bytes. So at first I tried to write 40bytes of "A" and then 6bytes of "B" to test the control of the return address.

Here is a screenshot: enter image description here

I found and tested a 23 byte shellcode that executes "/bin/sh", so I try to write a nop-sled of 13 bytes, the shellcode and the first 6 bytes of the return address that need to change. So I come up with this (in gdb):

r $(python -c'print "\x90"*13+"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"+"\x10\xe1\xff\xff\xff\x7f"')

I have set 2 breakpoints before and after the execution of strcpy and examine the memory.

This is the stack before the strcpy: enter image description here

where at address 0x00007fffffffe138 is the return address of function function enter image description here

And this is the stack right after the strcpy execution: enter image description here

So in my understanding, after I press c to continue the execution, I must "return" to the nopsled and then execute the shellcode in gdb.

Instead I get a SIGILL, for illegal instruction.

enter image description here

I cannot figure out why this is happening, any help/suggestions/pointer would be much appreciated.

1 Answer 1


First off (only because you mentioned "realistic"), this is not exactly a realistic scenario for a 64-bit system. The main reason is that the address space is much much larger, which makes it much more difficult to predict and land within your NOP sled. For a more detailed explanation, see this answer. Also, no-execute-stack (NX) is almost universally enabled these days.

Instead, you typically will want to use return-oriented programming (ROP).

That said, let's address your current scenario. I spent way too long trying to figure out what was wrong, but it looks like you may be doing everything correctly (assuming you have the correct address to return to).

Looks like that's actually a 27-byte shellcode, but you had the correct amount of padding anyway to equal 40 bytes to the return address, so that's fine.

Turns out, the way you get it to work is to try it from outside of GDB. You may notice, if you step through it more slowly, that the SIGILL is actually occurring past the syscall instruction, but GDB is somehow fudging it so it seems to happen prior. I scrolled back up while stepping through, and it appears the push rbx instruction was throwing off GDB; it was trying to dereference 0x68732f6e69622f (which is just /bin/sh in hex representation) and complaining about that, which maybe caused other things to go wrong (GDB was also inserting segfaults and ghost instructions for me as well). Maybe somebody else has a better explanation for why this occurs.

So, try running it outside of GDB. You will almost certainly need ASLR to be turned off, and you'll need a way to get the address of the buffer. You can add a print statement to the original source to print the address with %p.

  • I am sure I have disabled ASLR. I will ty again by finding the base address of the process and calculate the offset to make it work outside GDB. Thank you.
    – George Sp
    Jan 13, 2020 at 13:19

You must log in to answer this question.

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