3

I am trying to dig deeper into the nuts and bolts a stack buffer overflow using the classical NOP-sled technique.

Reading some articles and watching videos brought me to a confusion which can be demonstrated in these 2 pictures (which contradict each other unless I misunderstood something there).

enter image description here

This is a picture from Wikipedia's "Buffer_Overflow". What it basically shows is that the shellcode comes at the beginning of the input, followed by NOPs. Then comes a relative jump to another NOPs section which lead to a jump to the shellcode memory address location.

What I don't understand is this: We basically aim to overwrite the return address, that in turn will point to the shellcode location - But this is not what I am seeing in the picture, all I see is "relative jumps" to NOP areas which ultimately lead to the shellcode - But what about the return address? Seems like it is being skipped.

The next picture is this (taken for a slideshow):

enter image description here

In the slideshow it is said that the black area represents a NOPs area, which in turn leads ultimately to the shellcode, and only then do we see the return address. So if my shellcode begins with NOPs followed by the shellcode, how where and when exactly do I get to the return address (that should point to the NOPs>>>Shellcode)?

I tried not to make question overly clumsy and complicated (because of too much words) and I hope the question is clear.

Franko
  • 1,530
  • 5
  • 18
  • 30
  • 2
    I'm surprised this information is so spoon fed these days. Back in my day we had ascii art and had I to figure it out with gdb. If this doesn't make sense, its because you have never used a debugger. – rook Aug 08 '13 at 18:15

1 Answers1

13

There are two "unknowns" that the attacker has to contend with.

First, the attacker is overflowing a buffer, supposedly on the stack, and among the bytes which follow the buffer in RAM are the bytes which store the "return address" where execution jumps after the current function is finished. The attacker wants to overwrite these bytes with another address, making the CPU jump into code written by the attacker. The first unknown is then: "what is the distance between the buffer (that is overflown) and the return address slot ?". The attacker must guess that, so as to know at which point in the attacker-provided data the "return address replacement" must be set.

The second unknown is the actual address of his shell code. In a traditional buffer overflow on the stack, the shell code is part of the data which triggers the overflow, i.e. it is in the buffer. The return address is absolute so it is not sufficient for the attacker to know the code of the attacked function; the attacker must also know what is the stack depth at that moment, and this depends on previous application behaviour.

The NOP slide, or NOP sled, is a simple technique to cope with accuracy issue for the second unknown. When the attacker guesses the address of his shell code with some possible jitter, then the attacker puts a lot of nop opcodes (or similarly harmless opcodes) before his shell code; thus, it suffices that the CPU jumps somewhere in the sled in order to make it, ultimately, reach the shell code.

For the first unknown, the tool is not a NOP sled, but another kind of sled. Simply put, the complete overflow will look like this:

90 90 90 90 90... 90 shellcode addr addr addr... addr

where shellcode is the actual payload, 90 is the hexadecimal code for the nop opcode, and addr is the attacker's guess of the buffer start address in RAM. When the overflow occurs, one of the addr values will overwrite the return address slot, and make the CPU jump at address addr; which one of the addr does the trick is the "first unknown" described above. Usually, the "first unknown" is not that unknown, because it only depends on the layout of local variables in the function itself, which is known through reverse-engineering (disassembly).

The attacker has guessed that the byte at address addr will be one of the 90, so execution jumps there. Which one is not very important, because the CPU will proceed to execute all subsequent nop opcodes and then reach the shellcode.

The pictures you show are indeed quite confusing. They seem to relate to more complex cases where the attacker, for some reason, cannot put his shell code immediately after the NOP sled, but at some place before the NOP sled, so he must then arrange for an appropriate jump at the end of the sled (jump opcodes use relative addressing, so that jump is easy to get right).

Tom Leek
  • 168,808
  • 28
  • 337
  • 475