708 lines
20 KiB
Ruby
708 lines
20 KiB
Ruby
# -*- coding: binary -*-
|
|
require 'rex/service_manager'
|
|
require 'rex/exploitation/obfuscatejs'
|
|
require 'rex/exploitation/encryptjs'
|
|
require 'rex/exploitation/heaplib'
|
|
require 'rex/exploitation/js'
|
|
|
|
module Msf
|
|
|
|
###
|
|
#
|
|
# This module provides methods for exploiting an HTTP client by acting
|
|
# as an HTTP server.
|
|
#
|
|
###
|
|
module Exploit::Remote::HttpServer
|
|
|
|
autoload :HTML, 'msf/core/exploit/http/server/html'
|
|
autoload :PHPInclude, 'msf/core/exploit/http/server/php_include'
|
|
|
|
include Msf::Exploit::Remote::TcpServer
|
|
include Msf::Auxiliary::Report
|
|
|
|
def initialize(info = {})
|
|
super
|
|
|
|
register_options(
|
|
[
|
|
OptString.new('URIPATH', [ false, "The URI to use for this exploit (default is random)"]),
|
|
], Exploit::Remote::HttpServer
|
|
)
|
|
|
|
register_evasion_options(
|
|
[
|
|
OptBool.new('HTTP::no_cache', [false, 'Disallow the browser to cache HTTP content', false]),
|
|
OptBool.new('HTTP::chunked', [false, 'Enable chunking of HTTP responses via "Transfer-Encoding: chunked"', false]),
|
|
OptBool.new('HTTP::header_folding', [false, 'Enable folding of HTTP headers', false]),
|
|
OptBool.new('HTTP::junk_headers', [false, 'Enable insertion of random junk HTTP headers', false]),
|
|
OptEnum.new('HTTP::compression', [false, 'Enable compression of HTTP responses via content encoding', 'none', ['none','gzip','deflate']]),
|
|
OptString.new('HTTP::server_name', [true, 'Configures the Server header of all outgoing replies', 'Apache'])
|
|
], Exploit::Remote::HttpServer
|
|
)
|
|
|
|
register_advanced_options([
|
|
OptAddress.new('URIHOST', [false, 'Host to use in URI (useful for tunnels)']),
|
|
OptPort.new('URIPORT', [false, 'Port to use in URI (useful for tunnels)']),
|
|
OptBool.new('SendRobots', [false, 'Return a robots.txt file if asked for one', false])
|
|
])
|
|
|
|
# Used to keep track of resources added to the service manager by
|
|
# this module. see #add_resource and #cleanup
|
|
@my_resources = []
|
|
@service_path = nil
|
|
end
|
|
|
|
#
|
|
# By default, all HTTP servers are not subject to automatic exploitation
|
|
#
|
|
def autofilter
|
|
false
|
|
end
|
|
|
|
#
|
|
# Thread-local client accessor
|
|
#
|
|
def cli
|
|
Thread.current[:cli]
|
|
end
|
|
|
|
#
|
|
# Thread-local client accessor
|
|
#
|
|
def cli=(cli)
|
|
Thread.current[:cli] = cli
|
|
end
|
|
|
|
def print_prefix
|
|
if cli && self.respond_to?(:stance) &&
|
|
!(stance == Msf::Exploit::Stance::Aggressive || stance.include?(Msf::Exploit::Stance::Aggressive))
|
|
super + "#{cli.peerhost.ljust(16)} #{self.shortname} - "
|
|
else
|
|
super
|
|
end
|
|
end
|
|
|
|
#
|
|
# Ensures that gzip can be used. If not, an exception is generated. The
|
|
# exception is only raised if the DisableGzip advanced option has not been
|
|
# set.
|
|
#
|
|
def use_zlib
|
|
if !Rex::Text.zlib_present? && datastore['HTTP::compression']
|
|
raise RuntimeError, "zlib support was not detected, yet the HTTP::compression option was set. Don't do that!"
|
|
end
|
|
end
|
|
|
|
#
|
|
# This method gives a derived class the opportunity to ensure that all
|
|
# dependencies are present before initializing the service.
|
|
#
|
|
# By default, all HTTP server mixins will try to use zlib.
|
|
#
|
|
def check_dependencies
|
|
use_zlib
|
|
end
|
|
|
|
##
|
|
# :category: Exploit::Remote::TcpServer overrides
|
|
#
|
|
# This mixin starts the HTTP server listener. This routine takes a few
|
|
# different hash parameters:
|
|
#
|
|
# ServerHost => Override the server host to listen on (default to SRVHOST).
|
|
# ServerPort => Override the server port to listen on (default to SRVPORT).
|
|
# Uri => The URI to handle and the associated procedure to call.
|
|
#
|
|
#
|
|
# TODO: This must be able to take an SSL parameter and not rely
|
|
# completely on the datastore. (See dlink_upnp_exec_noauth)
|
|
def start_service(opts = {})
|
|
|
|
check_dependencies
|
|
|
|
comm = datastore['ListenerComm']
|
|
if (comm.to_s == "local")
|
|
comm = ::Rex::Socket::Comm::Local
|
|
else
|
|
comm = nil
|
|
end
|
|
|
|
# Default the server host and port to what is required by the mixin.
|
|
opts = {
|
|
'ServerHost' => datastore['SRVHOST'],
|
|
'ServerPort' => datastore['SRVPORT'],
|
|
'Comm' => comm
|
|
}.update(opts)
|
|
|
|
# Start a new HTTP server service.
|
|
self.service = Rex::ServiceManager.start(
|
|
Rex::Proto::Http::Server,
|
|
opts['ServerPort'].to_i,
|
|
opts['ServerHost'],
|
|
datastore['SSL'], # XXX: Should be in opts, need to test this
|
|
{
|
|
'Msf' => framework,
|
|
'MsfExploit' => self,
|
|
},
|
|
opts['Comm'],
|
|
datastore['SSLCert'],
|
|
datastore['SSLCompression'],
|
|
datastore['SSLCipher']
|
|
)
|
|
|
|
self.service.server_name = datastore['HTTP::server_name']
|
|
|
|
# Default the procedure of the URI to on_request_uri if one isn't
|
|
# provided.
|
|
uopts = {
|
|
'Proc' => Proc.new { |cli, req|
|
|
self.cli = cli
|
|
( self.respond_to?(:filter_request_uri) &&
|
|
filter_request_uri(cli, req)
|
|
) ? nil : on_request_uri(cli, req)
|
|
},
|
|
'Path' => opts['Path'] || resource_uri
|
|
}.update(opts['Uri'] || {})
|
|
|
|
proto = (datastore["SSL"] ? "https" : "http")
|
|
|
|
# SSLCompression may or may not actually be available. For example, on
|
|
# Ubuntu, it's disabled by default, unless the correct environment
|
|
# variable is set. See https://github.com/rapid7/metasploit-framework/pull/2666
|
|
if proto == "https" and datastore['SSLCompression']
|
|
print_status("Intentionally using insecure SSL compression. Your operating system might not respect this!")
|
|
end
|
|
|
|
|
|
print_status("Using URL: #{proto}://#{opts['ServerHost']}:#{opts['ServerPort']}#{uopts['Path']}")
|
|
|
|
if opts['ServerHost'] == '0.0.0.0'
|
|
print_status("Local IP: #{proto}://#{Rex::Socket.source_address('1.2.3.4')}:#{opts['ServerPort']}#{uopts['Path']}")
|
|
end
|
|
|
|
if datastore['SendRobots']
|
|
add_robots_resource
|
|
end
|
|
|
|
add_resource(uopts)
|
|
|
|
end
|
|
|
|
def add_robots_resource
|
|
proc = Proc.new do |cli, req|
|
|
self.cli = cli
|
|
send_robots(cli, req)
|
|
end
|
|
|
|
vprint_status('Adding hardcoded URI /robots.txt')
|
|
begin
|
|
add_resource('Path' => '/robots.txt', 'Proc' => proc)
|
|
rescue RuntimeError => e
|
|
print_warning(e.message)
|
|
end
|
|
end
|
|
|
|
# Set {#on_request_uri} to handle the given +uri+ in addition to the one
|
|
# specified by the user in URIPATH.
|
|
#
|
|
# @note This MUST be called from {#primer} so that the service has been set
|
|
# up but we have not yet entered the listen/accept loop.
|
|
#
|
|
# @param uri [String] The resource URI that should be handled by
|
|
# {#on_request_uri}.
|
|
# @return [void]
|
|
def hardcoded_uripath(uri)
|
|
proc = Proc.new do |cli, req|
|
|
on_request_uri(cli, req)
|
|
end
|
|
|
|
vprint_status("Adding hardcoded uri #{uri}")
|
|
begin
|
|
add_resource({'Path' => uri, 'Proc' => proc})
|
|
rescue RuntimeError => e
|
|
print_error("This module requires a hardcoded uri at #{uri}. Can't run while other modules are using it.")
|
|
raise e
|
|
end
|
|
end
|
|
|
|
# Take care of removing any resources that we created
|
|
def cleanup
|
|
# Must dup here because remove_resource modifies @my_resources
|
|
@my_resources.dup.each do |resource|
|
|
remove_resource(resource)
|
|
end
|
|
|
|
super
|
|
end
|
|
|
|
#
|
|
# Return a Hash containing a best guess at the actual browser and operating
|
|
# system versions, based on the User-Agent header.
|
|
#
|
|
# Keys in the returned hash are similar to those expected of
|
|
# Report#report_client, and Msf::DBManager#report_host namely:
|
|
# +:ua_name+:: a brief identifier for the client, e.g. "Firefox"
|
|
# +:ua_ver+:: the version number of the client, e.g. "3.0.11"
|
|
# +:os_name+:: something like "Windows XP", "Windows 7", or "Linux"
|
|
# +:os_flavor+:: something like "Enterprise", "Pro", or "Home"
|
|
# +:os_lang+:: something like "English", "French", or "en-US"
|
|
# +:arch+:: one of the ARCH_* constants
|
|
#
|
|
# Unknown values may be nil.
|
|
#
|
|
def fingerprint_user_agent(ua_str)
|
|
|
|
fp = { :ua_string => ua_str }
|
|
|
|
# Guess the browser type based on the user agent
|
|
# Check for IE last since its often impersonated
|
|
case (ua_str.downcase)
|
|
# Chrome tries to look like Safari, so check it first
|
|
when /chrome\/(\d+(:?\.\d+)*)/
|
|
# Matches, e.g.:
|
|
# Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.472.63 Safari/534.3
|
|
fp[:ua_name] = HttpClients::CHROME
|
|
fp[:ua_ver] = $1
|
|
when /version\/(\d+(:?\.\d+)*)\s*safari/
|
|
fp[:ua_name] = HttpClients::SAFARI
|
|
fp[:ua_ver] = $1
|
|
when /firefox\/((:?[0-9]+\.)+[0-9]+)/
|
|
fp[:ua_name] = HttpClients::FF
|
|
fp[:ua_ver] = $1
|
|
when /opera\/(\d+(:?\.\d+)*)/
|
|
fp[:ua_name] = HttpClients::OPERA
|
|
fp[:ua_ver] = $1
|
|
when /mozilla\/[0-9]+\.[0-9] \(compatible; msie ([0-9]+\.[0-9]+)/i, /mozilla\/[0-9]+\.[0-9] \(.+ rv:([0-9]+\.[0-9])\)/i
|
|
fp[:ua_name] = HttpClients::IE
|
|
fp[:ua_ver] = $1
|
|
else
|
|
fp[:ua_name] = HttpClients::UNKNOWN
|
|
end
|
|
|
|
# Guess the language
|
|
case (ua_str.downcase)
|
|
when /(en-us|en-gb)/
|
|
fp[:os_lang] = $1
|
|
end
|
|
|
|
# Guess the general OS type
|
|
case (ua_str.downcase)
|
|
when /windows|win32/
|
|
fp[:os_name] = OperatingSystems::WINDOWS
|
|
fp[:arch] = ARCH_X86
|
|
when /linux/
|
|
fp[:os_name] = OperatingSystems::LINUX
|
|
when /iphone|ipad/
|
|
fp[:os_name] = OperatingSystems::APPLE_IOS
|
|
fp[:arch] = 'armle'
|
|
when /mac os x/
|
|
fp[:os_name] = OperatingSystems::MAC_OSX
|
|
else
|
|
fp[:os_name] = OperatingSystems::UNKNOWN
|
|
end
|
|
|
|
# Determine the specific OS variant
|
|
|
|
# Note that we assume windows variants are the
|
|
# client version and mismatch server editions.
|
|
|
|
case (ua_str.downcase)
|
|
when /windows 95/
|
|
fp[:os_name] = 'Windows 95'
|
|
when /windows 98/
|
|
fp[:os_name] = 'Windows 98'
|
|
when /windows nt 4/
|
|
fp[:os_name] = 'Windows NT'
|
|
when /windows nt 5.0/
|
|
fp[:os_name] = 'Windows 2000'
|
|
when /windows nt 5.1/
|
|
fp[:os_name] = 'Windows XP'
|
|
when /windows nt 5.2/
|
|
fp[:os_name] = 'Windows 2003'
|
|
when /windows nt 6.0/
|
|
fp[:os_name] = 'Windows Vista'
|
|
when /windows nt 6.1/
|
|
fp[:os_name] = 'Windows 7'
|
|
when /windows nt 6.2/
|
|
fp[:os_name] = 'Windows 8'
|
|
when /windows nt 6.3/
|
|
fp[:os_name] = 'Windows 8.1'
|
|
when /gentoo/
|
|
fp[:os_vendor] = 'Gentoo'
|
|
when /debian/
|
|
fp[:os_vendor] = 'Debian'
|
|
when /ubuntu/
|
|
fp[:os_vendor] = 'Ubuntu'
|
|
when /fedora/
|
|
fp[:os_vendor] = 'Fedora'
|
|
when /red hat|rhel/
|
|
fp[:os_vendor] = 'RHEL'
|
|
when /android/
|
|
fp[:os_name] = OperatingSystems::ANDROID
|
|
end
|
|
|
|
# Guess the architecture
|
|
case (ua_str.downcase)
|
|
when /ppc/
|
|
fp[:arch] = ARCH_PPC
|
|
when /x64|x86_64/
|
|
fp[:arch] = ARCH_X64
|
|
when /i.86|wow64/
|
|
# WOW64 means "Windows on Windows64" and is present
|
|
# in the useragent of 32-bit IE running on 64-bit
|
|
# Windows
|
|
fp[:arch] = ARCH_X86
|
|
when /android|iphone|ipod|ipad/
|
|
fp[:arch] = ARCH_ARMLE
|
|
else
|
|
fp[:arch] = ARCH_X86
|
|
end
|
|
|
|
fp
|
|
end
|
|
|
|
#
|
|
# Store the results of server-side User-Agent fingerprinting in the DB.
|
|
#
|
|
# Returns a Hash containing host and client information.
|
|
#
|
|
def report_user_agent(address, request, client_opts={})
|
|
fp = fingerprint_user_agent(request["User-Agent"])
|
|
host = {
|
|
:address => address,
|
|
:host => address,
|
|
}
|
|
host[:os_name] = fp[:os_name] if fp[:os_name]
|
|
host[:os_flavor] = fp[:os_flavor] if fp[:os_flavor]
|
|
host[:arch] = fp[:arch] if fp[:arch]
|
|
host[:os_lang] = fp[:os_lang] if fp[:os_lang]
|
|
report_host(host)
|
|
client = {
|
|
:host => address,
|
|
:ua_string => request['User-Agent'],
|
|
}
|
|
client[:ua_name] = fp[:ua_name] if fp[:ua_name]
|
|
client[:ua_ver] = fp[:ua_ver] if fp[:ua_ver]
|
|
client.merge!(client_opts) if client_opts
|
|
report_client(client)
|
|
report_note(
|
|
:host => address,
|
|
:type => 'http.request',
|
|
:data => "#{address}: #{request.method} #{request.resource} #{client[:os_name]} #{client[:ua_name]} #{client[:ua_ver]}",
|
|
:update => :unique_data
|
|
)
|
|
return host.merge(client)
|
|
end
|
|
|
|
#
|
|
# Adds a URI resource using the supplied hash parameters.
|
|
#
|
|
# Path => The path to associate the procedure with.
|
|
# Proc => The procedure to call when the URI is requested.
|
|
# LongCall => Indicates that the request is a long call.
|
|
#
|
|
# NOTE: Calling #add_resource will change the results of subsequent calls
|
|
# to #get_resource!
|
|
#
|
|
# @return (see Rex::Service#add_resource)
|
|
def add_resource(opts)
|
|
@service_path = opts['Path']
|
|
res = service.add_resource(opts['Path'], opts)
|
|
|
|
# This has to go *after* the call to service.add_resource in case
|
|
# the service manager doesn't like it for some reason and raises.
|
|
@my_resources.push(opts['Path'])
|
|
|
|
res
|
|
end
|
|
|
|
#
|
|
# Returns the last-used resource path
|
|
#
|
|
def get_resource
|
|
# We don't want modules modifying their service_path inadvertently, so
|
|
# give them a dup. Can be nil during module setup.
|
|
@service_path ? @service_path.dup : nil
|
|
end
|
|
|
|
#
|
|
# Return a full url of the form <tt>http://1.1.1.1:8080/resource/</tt>
|
|
#
|
|
# The address portion should be something a client would be able to route,
|
|
# but see {#srvhost_addr} for caveats.
|
|
#
|
|
def get_uri(cli=self.cli)
|
|
ssl = !!(datastore["SSL"])
|
|
proto = (ssl ? "https://" : "http://")
|
|
if datastore['URIHOST']
|
|
host = datastore['URIHOST']
|
|
elsif (cli and cli.peerhost)
|
|
host = Rex::Socket.source_address(cli.peerhost)
|
|
else
|
|
host = srvhost_addr
|
|
end
|
|
|
|
if Rex::Socket.is_ipv6?(host)
|
|
host = "[#{host}]"
|
|
end
|
|
|
|
if datastore['URIPORT'] && datastore['URIPORT'] != 0
|
|
port = ':' + datastore['URIPORT'].to_s
|
|
elsif (ssl and datastore["SRVPORT"] == 443)
|
|
port = ''
|
|
elsif (!ssl and datastore["SRVPORT"] == 80)
|
|
port = ''
|
|
else
|
|
port = ":" + datastore["SRVPORT"].to_s
|
|
end
|
|
|
|
uri = proto + host + port + get_resource
|
|
|
|
uri
|
|
end
|
|
|
|
#
|
|
# An address to which the client can route.
|
|
#
|
|
# If available, return LHOST which should be the right thing since it
|
|
# already has to be an address the client can route to for the payload to
|
|
# work. However, LHOST will only be available if we're using a reverse_*
|
|
# payload, so if we don't have it, try to use the client's peerhost
|
|
# address. Failing that, fall back to the addr with the default gateway.
|
|
# All of this will be for naught in the case of a user behind NAT using a
|
|
# bind payload but there's nothing we can do about it.
|
|
#
|
|
# NOTE: The address will be *incorrect* in the following two situations:
|
|
# 1. LHOST is pointed at a exploit/multi/handler on some other box.
|
|
# 2. SRVHOST has a value of '0.0.0.0', the user is behind NAT, and we're
|
|
# using a bind payload. In that case, we don't have an LHOST and
|
|
# the source address will be internal.
|
|
#
|
|
# This can potentially be dealt with in a module by using the Host header
|
|
# from a request if such a header exists.
|
|
#
|
|
# @return [String]
|
|
def srvhost_addr
|
|
if datastore['URIHOST']
|
|
host = datastore['URIHOST']
|
|
elsif (datastore['LHOST'] and (!datastore['LHOST'].strip.empty?))
|
|
host = datastore["LHOST"]
|
|
else
|
|
if (datastore['SRVHOST'] == "0.0.0.0" or datastore['SRVHOST'] == "::")
|
|
if (respond_to?(:sock) and sock and sock.peerhost)
|
|
# Then this is a Passive-Aggressive module. It has a socket
|
|
# connected to the remote server from which we can deduce the
|
|
# appropriate source address.
|
|
host = Rex::Socket.source_address(sock.peerhost)
|
|
else
|
|
# Otherwise, this module is only a server, not a client, *and*
|
|
# the payload does not have an LHOST option. This can happen,
|
|
# for example, with a browser exploit using a download-exec
|
|
# payload. In that case, just use the address of the interface
|
|
# with the default gateway and hope for the best.
|
|
host = Rex::Socket.source_address
|
|
end
|
|
else
|
|
host = datastore['SRVHOST']
|
|
end
|
|
end
|
|
|
|
host
|
|
end
|
|
|
|
#
|
|
# Returns the local port that is being listened on.
|
|
#
|
|
def srvport
|
|
if datastore['URIPORT']
|
|
port = datastore['URIPORT']
|
|
else
|
|
port = datastore['SRVPORT']
|
|
end
|
|
|
|
port
|
|
end
|
|
|
|
#
|
|
# Removes a URI resource.
|
|
#
|
|
def remove_resource(name)
|
|
# Guard against removing resources added by other modules
|
|
if @my_resources.include?(name)
|
|
@my_resources.delete(name)
|
|
service.remove_resource(name) if service
|
|
end
|
|
end
|
|
|
|
#
|
|
# Closes a client connection.
|
|
#
|
|
def close_client(cli)
|
|
service.close_client(cli)
|
|
end
|
|
|
|
#
|
|
# Creates an HTTP response packet.
|
|
#
|
|
def create_response(code = 200, message = "OK", proto = Rex::Proto::Http::DefaultProtocol)
|
|
res = Rex::Proto::Http::Response.new(code, message, proto);
|
|
res['Content-Type'] = 'text/html'
|
|
res
|
|
end
|
|
|
|
#
|
|
# Transmits a response to the supplied client, default content-type is text/html
|
|
#
|
|
# Payload evasions are implemented here!
|
|
#
|
|
def send_response(cli, body, headers = {})
|
|
response = create_response
|
|
response['Content-Type'] = 'text/html'
|
|
response.body = body.to_s.unpack("C*").pack("C*")
|
|
|
|
if (datastore['HTTP::compression'])
|
|
self.use_zlib # make sure...
|
|
response.compress = datastore['HTTP::compression']
|
|
end
|
|
|
|
if datastore['HTTP::chunked']
|
|
response.auto_cl = false
|
|
response.transfer_chunked = true
|
|
end
|
|
|
|
if datastore['HTTP::header_folding']
|
|
response.headers.fold = 1
|
|
end
|
|
|
|
if datastore['HTTP::junk_headers']
|
|
response.headers.junk_headers = 1
|
|
end
|
|
|
|
if datastore['HTTP::no_cache']
|
|
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate'
|
|
end
|
|
|
|
headers.each_pair { |k,v| response[k] = v }
|
|
|
|
cli.send_response(response)
|
|
end
|
|
|
|
#
|
|
# Sends a 302 redirect to the client
|
|
#
|
|
def send_redirect(cli, location='/', body='', headers = {})
|
|
response = create_response(302, 'Moved')
|
|
response['Content-Type'] = 'text/html'
|
|
response['Location'] = location
|
|
response.body = body.to_s.unpack("C*").pack("C*")
|
|
headers.each_pair { |k,v| response[k] = v }
|
|
|
|
cli.send_response(response)
|
|
end
|
|
|
|
|
|
#
|
|
# Sends a 302 redirect relative to our base path
|
|
#
|
|
def send_local_redirect(cli, location)
|
|
send_redirect(cli, get_resource + location)
|
|
end
|
|
|
|
|
|
#
|
|
# Sends a 404
|
|
#
|
|
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
|
|
|
|
#
|
|
# Sends a canned robots.txt file
|
|
#
|
|
def send_robots(cli, request)
|
|
print_status('Sending robots.txt')
|
|
robots = create_response(200, 'Success')
|
|
robots['Content-Type'] = 'text/plain'
|
|
|
|
robots.body = %Q{\
|
|
User-agent: *
|
|
Disallow: /
|
|
}
|
|
|
|
cli.send_response(robots)
|
|
end
|
|
|
|
|
|
#
|
|
# Returns the configured (or random, if not configured) URI path
|
|
#
|
|
def resource_uri
|
|
path = datastore['URIPATH'] || random_uri
|
|
path = '/' + path if path !~ /^\//
|
|
return path
|
|
end
|
|
|
|
|
|
#
|
|
# Generates a random URI for use with making finger printing more
|
|
# challenging.
|
|
#
|
|
def random_uri
|
|
"/" + Rex::Text.rand_text_alphanumeric(rand(10) + 6)
|
|
end
|
|
|
|
#
|
|
# Re-generates the payload, substituting the current RHOST and RPORT with
|
|
# the supplied client host and port.
|
|
#
|
|
def regenerate_payload(cli, arch = nil, platform = nil, target = nil)
|
|
pcode = nil
|
|
|
|
# If the payload fails to generate for some reason, send a 403.
|
|
if ((pcode = super(cli, arch, platform, target)) == nil)
|
|
print_error("Failed to generate payload, sending 403.")
|
|
|
|
cli.send_response(
|
|
create_response(403, 'Forbidden'))
|
|
|
|
return nil
|
|
end
|
|
pcode
|
|
end
|
|
|
|
##
|
|
#
|
|
# Override methods
|
|
#
|
|
##
|
|
|
|
#
|
|
# Called when a request is made to a single URI registered during the
|
|
# start_service. Subsequent registrations will not result in a call to
|
|
# on_request_uri.
|
|
#
|
|
# Modules should override this method.
|
|
#
|
|
def on_request_uri(cli, request)
|
|
end
|
|
|
|
# allow this module to be patched at initialization-time
|
|
Metasploit::Concern.run(self)
|
|
end
|
|
|
|
end
|