This is an extension of redirect execution via buffer overflow on x86.

Assuming that we have a valid stack buffer overflow payload:

  • If the program doesn’t contain any interesting code to redirect to, then we would need to add our own shellcode.
  • ESP typically points to right after where the stored return pointer is, which can also be overwritten. Remember, when the vulnerable routine runs ret, the ESP is already reset to the top of the caller’s stack frame.
  • We can make where ESP points to the location of our shellcode. Only a simple jmp esp (or rsp) gadget is needed to redirect execution to our shell—we can’t hardcode the address since that varies depending on a lot of factors (ASLR, environmental variables, etc which can change how the stack looks). We need to find the address of a jmp esp gadget in the program or in the loaded libraries. The following steps assume that ASLR is disabled.
  • Enter jmp esp in msf-nasm_shell to get the opcodes in hex (\xff\xe4 for x86). Crash the program with stack overflow and search the memory dump for the opcodes obtained earlier. Make sure the the gadget’s memory region does not have any mitigation enabled (e.g. ASLR).
    • For Immunity Debugger on Windows, use the script mona.py: See mona.py
    • For EDB on Linux, use Plugins > BinarySearcher, click ESP EIP and disable jump equivalents to prevent messing up the stack. Enable if necessary.
    • If the address used works locally but not remotely, the address might be affected by ASLR or some other environmental factor. Try using instructions from other images (other libraries, etc) or look for equivalent instructions (e.g. jmp esp = call esp = push esp; ret = …)
  • Find bad characters, i.e. characters that may mangle the payload when the application / network stack tries to (mis-)interpret them. If you have access to the binary, repeat sending the padding, a fake address (so that debugger stops the program and dumps its memory), and all bytes from 0x01 to 0xff. If everything after a certain byte get dropped, then the first missing byte is bad. Also pay attention to the case when a byte just disappears or gets replaced. None of these characters should be in the payload. They can be specified in msfvenom with -b.
# Set payloads to all bytes 0x01 to 0xff (excluding obvious badchar 0x00)
payload = b''
for i in range(1,256):
    payload += i.to_bytes(1, 'little')
  • Generate a shellcode payload using msfvenom (see msfvenom; use -b to specify bad characters) or use one found online. If Shikata Ga Nai or similar encoders are used, add a NOP slide between the jmp esp gadget address and the shellcode in the payload. This is necessary since Shikata Ga Nai modifies data where ESP points to for the decoder stub. With the NOP slide, the decoder stub would not overwrite the shellcode.
  • Your payload is padding + gadget address + NOP slide + shellcode