Search code examples
x86buffer-overflowexploit

Buffer overflow: How to do a relative jump from ESP?


I am trying to do an exercise in the area of a stack buffer overflow. I'm doing the classical example where the vuln allows you to overwrite EIP. My problem is that I can only use addresses starting with 00 which means I cannot overwrite addresses larger than what ESP is pointing to. So the classical approach of putting the shellcode after the address I'm overwriting EIP with won't work. Instead, I need to put the shellcode before the address into the buffer. See the simple drawing below.

<larger stack addresses>  ........... <smaller stack addresses>
    ESP                               Need to jump here somehow
     |                                  |     
     V                                  V
   XXXX|AAAA|AAAA|AAAA|AAAA|AAAA|....|AAAA|AAAA|AAAA|....
     A
     |
     |
    My buffer won't reach any  addresses
    larger than ESP because of the 0 in it...

Now the question is: What is the assembly instruction I need to search for that will jump to the address say 200 bytes smaller than ESP? I don't know x86 assembler well enough. I have tried everything like jmp [ESP-8], jmp [ESP-16], ... (also with larger offsets), then sub ESP,EBX + jmp ESP, xor ESP, EBX + jmp ESP and so on. I should add here that it looks like I can overwrite EBX as well. So if there was sub ESP,EBX + jmp ESP or sth like that, then I could fill EBX with the negative offset jump to the shellcode by subtracting the offset from ESP first. But whatever I try, I cannot find the instructions in the module. I think my main problem is that I don't understand x86 assembly language well enough. I have seen instructions like jmp DWORD PTR DS:[ESP+8] in the code and have been googling a bit and my limited understanding tells me that this is a relative jump in the data segment. So I would need to do something like this in the stack segment, ideally getting the offset from the EBX register... Does sth like this exist?


Solution

  • Indirect jumps to a value in a register can't take an offset. You have to do all the address math before running the jmp instruction. There is no way to encode jmp esp - 200 or anything like that.

    jmp [ESP-8] would load from [ESP-8], and jump to that address. You can tell it's doing a load because it has square brackets.

    So you should try looking for sequences like

    lea   eax, [esp-200]
    jmp   eax               # or call eax
    

    Or

    sub  esp, 200
    jmp  esp
    

    The AT&T syntax for register-indirect jumps is jmp *eax, BTW.

    Those instructions don't have to be adjacent; you might find what you need for a ret2reg attack separated by a few instructions, but this is harder to search for because you need to limit your search to cases where decoding starts at a sub, lea or whatever, and gets to a jmp after some number of valid instructions that won't fault with the register values expected at the ret you're attacking. You might try just starting disassembly from every every offset up to 20 bytes before a possible jmp reg or call reg instruction, and see if any offset produces valid instructions that do something interesting.

    You don't necessarily have to find a sequence that starts with esp; if a pointer to somewhere else in the buffer exists in another register, you could look for a jmp or call to that register.


    Doing sub esp, 200 / jmp esp leaves the stack pointing to the lowest address of your code, so pushing data onto the stack won't overwrite the end of your code before execution reaches it, which could be a problem with long code that comes close to or past the original esp.

    The stack grows down, but execution goes up towards increasing addresses, so if you start with EIP=ESP, you only get into trouble if you pop or otherwise increase ESP.