metasploit-framework/modules/auxiliary/scanner/http/open_proxy.rb

159 lines
5.3 KiB
Ruby
Raw Normal View History

##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
2016-03-08 13:02:44 +00:00
class MetasploitModule < Msf::Auxiliary
2016-11-17 14:44:03 +00:00
include Msf::Exploit::Remote::HttpClient
2013-08-30 21:28:54 +00:00
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::WmapScanServer
include Msf::Auxiliary::Report
def initialize(info = {})
super(update_info(info,
'Name' => 'HTTP Open Proxy Detection',
'Description' => %q{
2016-11-17 14:44:03 +00:00
Checks if an HTTP proxy is open. False positive are avoided
2016-11-18 17:39:26 +00:00
verifying the HTTP return code and matching a pattern.
The CONNECT method is verified only the return code.
2016-11-17 14:44:03 +00:00
HTTP headers are shown regarding the use of proxy or load balancer.
2013-08-30 21:28:54 +00:00
},
'References' =>
[
['URL', 'http://en.wikipedia.org/wiki/Open_proxy'],
['URL', 'http://nmap.org/svn/scripts/http-open-proxy.nse'],
],
'Author' => 'Matteo Cantoni <goony[at]nothink.org>',
'License' => MSF_LICENSE
))
register_options(
[
Opt::RPORT(8080),
2016-11-17 14:44:03 +00:00
OptBool.new('MULTIPORTS', [ false, 'Multiple ports will be used: 80, 443, 1080, 3128, 8000, 8080, 8123', false ]),
OptBool.new('VERIFYCONNECT', [ false, 'Enable CONNECT HTTP method check', false ]),
OptString.new('CHECKURL', [ true, 'The web site to test via alleged web proxy', 'http://www.google.com' ]),
OptString.new('VALIDCODES', [ true, "Valid HTTP code for a successfully request", '200,302' ]),
OptString.new('VALIDPATTERN', [ true, "Valid pattern match (case-sensitive into the headers and HTML body) for a successfully request", '<TITLE>302 Moved</TITLE>' ]),
2013-08-30 21:28:54 +00:00
], self.class)
register_wmap_options({
2016-11-17 14:44:03 +00:00
'OrderID' => 1,
'Require' => {},
})
2013-08-30 21:28:54 +00:00
end
def run_host(target_host)
2016-11-17 14:44:03 +00:00
check_url = datastore['CHECKURL']
2013-08-30 21:28:54 +00:00
2016-11-17 14:44:03 +00:00
if datastore['VERIFYCONNECT']
target_method = 'CONNECT'
# CONNECT doesn't need <scheme> but need port
check_url = check_url.gsub(/[http:\/\/|https:\/\/]/, '')
if check_url !~ /:443$/
check_url = check_url + ":443"
end
else
target_method = 'GET'
# GET only http request
check_url = check_url.gsub(/https:\/\//, '')
if check_url !~ /^http:\/\//i
check_url = 'http://' + check_url
end
2013-08-30 21:28:54 +00:00
end
2016-11-17 14:44:03 +00:00
target_ports = []
2016-11-17 14:44:03 +00:00
if datastore['MULTIPORTS']
target_ports = [ 80, 443, 1080, 3128, 8000, 8080, 8123 ]
else
target_ports.push(datastore['RPORT'].to_i)
2013-08-30 21:28:54 +00:00
end
2016-11-17 14:44:03 +00:00
target_proxy_headers = [ 'Forwarded', 'Front-End-Https', 'Max-Forwards', 'Via', 'X-Cache', 'X-Cache-Lookup', 'X-Client-IP', 'X-Forwarded-For', 'X-Forwarded-Host' ]
2013-08-30 21:28:54 +00:00
target_ports.each do |target_port|
2016-11-17 14:44:03 +00:00
verify_target(target_host,target_port,target_method,check_url,target_proxy_headers)
2013-08-30 21:28:54 +00:00
end
end
2016-11-17 14:44:03 +00:00
def verify_target(target_host,target_port,target_method,check_url,target_proxy_headers)
2013-08-30 21:28:54 +00:00
2016-11-17 14:44:03 +00:00
vprint_status("#{peer} - Sending a web request... [#{target_method}][#{check_url}]")
2016-11-17 14:44:03 +00:00
datastore['RPORT'] = target_port
2013-08-30 21:28:54 +00:00
begin
2016-11-17 14:44:03 +00:00
res = send_request_cgi(
'uri' => check_url,
'method' => target_method,
'version' => '1.1'
)
2016-11-17 14:44:03 +00:00
return if not res
2016-11-17 14:44:03 +00:00
vprint_status("#{peer} - Returns with '#{res.code}' status code [#{target_method}][#{check_url}]")
2016-11-17 14:44:03 +00:00
valid_codes = datastore['VALIDCODES'].split(/,/)
2016-11-17 14:44:03 +00:00
target_proxy_headers_results = []
target_proxy_headers.each do |proxy_header|
if (res.headers.to_s.match(/#{proxy_header}: (.*)/))
proxy_header_value = $1
# Ok...I don't like it but works...
target_proxy_headers_results.push("\n |_ #{proxy_header}: #{proxy_header_value}")
2013-08-30 21:28:54 +00:00
end
end
2016-11-17 14:44:03 +00:00
if target_proxy_headers_results.any?
proxy_headers = target_proxy_headers_results.join()
2013-08-30 21:28:54 +00:00
end
2016-11-17 14:44:03 +00:00
if datastore['VERIFYCONNECT']
# Verifiying CONNECT we check only the return code
if valid_codes.include?(res.code.to_s)
2016-11-17 14:44:03 +00:00
print_good("#{peer} - Potentially open proxy [#{res.code}][#{target_method}]#{proxy_headers}")
2013-08-30 21:28:54 +00:00
report_note(
:host => target_host,
:port => target_port,
2016-11-17 14:44:03 +00:00
:method => target_method,
:proto => 'tcp',
:sname => (ssl ? 'https' : 'http'),
:type => 'OPEN HTTP PROXY',
:data => 'Open http proxy (CONNECT)'
2013-08-30 21:28:54 +00:00
)
2016-11-17 14:44:03 +00:00
end
else
# Verify return code && (headers.pattern or body.pattern)
2016-11-18 17:41:04 +00:00
if valid_codes.include?(res.code.to_s) && (res.headers.include?(datastore['VALIDPATTERN']) || res.body.include?(datastore['VALIDPATTERN']))
2016-11-17 14:44:03 +00:00
print_good("#{peer} - Potentially open proxy [#{res.code}][#{target_method}]#{proxy_headers}")
2013-08-30 21:28:54 +00:00
report_note(
:host => target_host,
:port => target_port,
2016-11-17 14:44:03 +00:00
:method => target_method,
:proto => 'tcp',
:sname => (ssl ? 'https' : 'http'),
:type => 'OPEN HTTP PROXY',
:data => 'Open http proxy (GET)'
2013-08-30 21:28:54 +00:00
)
2013-08-30 21:28:54 +00:00
end
end
2016-11-17 14:44:03 +00:00
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Timeout::Error, ::Errno::EPIPE => e
vprint_error("#{peer} - The port '#{target_port}' is unreachable!")
return nil
end
2013-08-30 21:28:54 +00:00
end
end