7

The code I'm referring to is found here: Link to code

I read that the buffer overflow exploit uses a buffer that looks something like this:

| NOP SLED | SHELLCODE | REPEATED RETURN ADDRESS |

From what I understand the exploit happens when the buffer is put onto the stack as a function parameter and overwrites the function's return address. I also understand that the repeated return address points to the NOP sled in the same buffer on the stack.

What I don't understand are the following:

  1. Why does the return address have to point to the shellcode in the same buffer? Someone told me that I can't have the return address point to the shellcode array (as opposed to an address in the NOP sled in the same buffer) because different processes can't access each other's memory or something of that sort. I'd love it if anyone can explain this to me.

  2. How is the return address on the buffer perfectly aligned with the original one so the ret command will read the correct address and not read it from the middle for example. What I'm referring to is that the repeated return command on the buffer overwrites the original return command on the stack which was pushed there with the call instruction. Why is the overwriting return address perfectly aligned with the original one?

  • You do realize in which direction the stack grows? Get The Shellcoder's Handbook from Wiley for in-depth explanations. – 0xC0000022L May 28 '13 at 11:52
  • I do. It grows up (toward lower memory addresses). – Shookie May 28 '13 at 12:16
  • 3
    you must read - Smashing the stack for fun and profit by Aleph1. It's a classic... – Mellowcandle May 28 '13 at 15:19
11

Why does the return address have to point to the shellcode in the same buffer?

It doesn't, but generally, both the shellcode and the return address are delivered at the same time, so they are stuck together for that reason. If your exploit allows you to deliver them separately, then they can be separated. However, they are by necessity both local to the exploited process, because the return address is local to the process. Once the shellcode gains control, it can jump across process boundaries, of course.

And the reason for putting the shellcode first is because that's where the exploited buffer is. The stack image looks like this: buffer variable, other variables, return address. The shellcode gets placed into the buffer, the other variables are overwritten with the nop sled, if needed, and then the return address is modified.

How is the return address on the buffer perfectly aligned with the original one so the ret command will read the correct address and not read it from the middle for example

Stacks are aligned to 4 bytes in 32-bit mode, variables are also placed on 4-byte aligned addresses, and their size is padded to align to a multiple of 4 bytes, so a one-byte char takes up 4 bytes on the stack, a buffer of 121 bytes will take up 124 bytes on the stack, etc. All the exploit writer has to do is to pad the shellcode+nop sled until it is aligned to a multiple of 4 bytes, and then place the return address.

4

If I'm understanding your first question correctly, I think there was a disconnect between you and whoever told you that. There is no restriction based on the buffer(s) being in the same process, at least not with respect to return values. You could absolutely have the return address point to the start of the shellcode. It's entirely up to you.

The better reason for returning to the NOP sled is both convention and the fact that it's a good habit. In examples where you don't know exactly where your code is going to end up the NOP sled helps "catch" your redirected EIP. Since NOPs don't do anything it gives you a larger buffer and larger probability to catch your code. As one of the comments in the discussion you linked to stated, this isn't a very robust form of exploitation.

The second question is a little more general. I don't have my copy of the book handy but it's essentially trial and error to figure out how far to write the return address into the buffer. Assuming that the crash is reliable, you would change your buffer from being 120 A's to something like AAAABBBBCCCCDDDDEEEE...etc. When the program crashes you'll see what junk is in the EIP and you can use that value to calculate the offset where the data is overwritten.

For example, if your EIP when the program dies contains 44444444, that means the RET instruction pulled the DDDD segment off of the stack. So when you craft your final exploit you'll know that it's 12 bytes until the saved EIP is overwritten on the stack.

It's worth mentioning that if you're going to be doing any examples that are less contrived than this one, Metasploit has a great pair of scripts to make this easier. pattern_create will create a unique pattern of your length and pattern_offset will take a length and some substring of the pattern and tell you how far into it is.

2

Regarding the first question, nothing is stopping you to put your shellcode wherever in that process' executable memory. For example, a common practice is(was, to be honest) to put shellcode in some environment variable, as (in absence of ASLR) their address can be perfectly caluclated. In that case you wouldn't have to guess the return address, but calculate the address where shellcode is in environment and use that address as return address.

This trick has the added benefit of not being limited by the buffer size. But, on the other hand, it obviously works only for local exploits.

The reason why shellcode is often in the same buffer that overwrites the original return address is that it's just convenient and easier to explain in the beginning.

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.