I'd like to know why we have to put the shellcode before the return address in a buffer overflow. Logically the return address will point to the shellcode and will be executed, so the return address should be put before the shellcode. Can someone explain me?
2 Answers
The buffer overflow, by definition, needs to overflow the buffer. This is to overwrite the return address at the end.
This gives a convenient location in which to drop the shell code. If you tried to add it afterwards, you might overwrite another memory address and then the program would crash in a different way.
So adding the shell code before the return address enables the return address to be written to to trigger a jump to the previously written shell code. To sum up, the buffer you're overflowing is often the perfect location to write your shell code without overwriting another important bit of memory.
The reason why you put the shellcode before the return address in your buffer overflow exploit depend on a few factors:
- The size of the buffer
- The flow of the application
- Any tricks beyond a simple buffer + return address like having to do relative jumps will require some finesse
A common example of a buffer overflow may look like this:
"\x41"*1000 + "\xe7\x51\x78\xa2" + "\x90"*16 + "[shellcode]"
Here, I have overflowed the buffer with 1000 A's, landed in a place where I can control EIP to point to a location of my choosing, followed by some NOPs to give my shellcode room to unpack, and then ultimately the executable code. This is a relatively straightforward exploit. The return address would commonly be a JMP ESP instruction, which happens to be at the start of your NOP sled. The sled works until it hits the shellcode, and since the stack grows, it overwrites the NOP sled while it unpacks and you get execution.
However, it can be that sometimes you don't have that kind of exploit path and you have to do something different:
"\x90"*16 + [shellcode] + "\x90"*400 + [return address] + "\x90"*5
Here we have to put our shellcode at the beginning because a simple JMP ESP isn't possible. Instead, we have to find another instruction that allows us to jump to the beginning to get execution. Then we have some padding at both ends of the return address.
So the answer, without more details, is "it depends." It depends on the specific situation, what you have to work with in your exploit, the room you have, and the behavior of the application in question.