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

135 lines
4.9 KiB
Ruby

##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
require 'msf/core'
require 'rex/socket/range_walker'
class Metasploit3 < Msf::Auxiliary
# Exploit mixins should be called first
include Msf::Exploit::Remote::HttpClient
# Scanner mixin should be near last
include Msf::Auxiliary::Scanner
include Msf::Auxiliary::Report
def initialize
super(
'Name' => 'Squid Proxy Port Scanner',
'Description' => %q{
A misconfigured Squid proxy can allow an attacker to make requests on his behalf.
This may give the attacker information about devices that he cannot reach but the
Squid proxy can. For example, an attacker can make requests for internal IP addresses
against a misconfigurated open Squid proxy exposed to the Internet, therefore performing
an internal port scan. The error messages returned by the proxy are used to determine
if the port is open or not.
Many Squid proxies use custom error codes so your mileage may vary. The open_proxy
module can be used to test for open proxies, though a Squid proxy does not have to be
open in order to allow for pivoting (e.g. an Intranet Squid proxy which allows
the attack to pivot to another part of the network).
},
'Author' => ['willis'],
'References' =>
[
'URL','http://wiki.squid-cache.org/SquidFaq/SecurityPitfalls'
],
'License' => MSF_LICENSE
)
register_options(
[
OptString.new('RANGE', [true, "IPs to scan through Squid proxy", '']),
OptString.new('PORTS', [true, "Ports to scan; must be TCP", "21,80,139,443,445,1433,1521,1723,3389,8080,9100"]),
OptBool.new('MANUAL_CHECK',[true,"Stop the scan if server seems to answer positively to every request",true]),
OptString.new('CANARY_IP',[true,"The IP to check if the proxy always answers positively; the IP should not respond.","1.2.3.4"])
], self.class)
end
def run_host(target_host)
begin
iplist = Rex::Socket::RangeWalker.new(datastore['RANGE'])
dead = false
portlist = Rex::Socket.portspec_crack(datastore['PORTS'])
if portlist.empty?
raise Msf::OptionValidateError.new(['PORTS'])
end
vprint_status("[#{rhost}] Verifying manual testing is not required...")
manual = false
#request a non-existent page first to make sure the server doesn't respond with a 200 to everything.
res_test = send_request_cgi({
'uri' => "http://{datastore['CANARY_IP']}:80",
'method' => 'GET',
'data' => '',
'version' => '1.0',
'vhost' => ''
}, 10)
if res_test and res_test.body and (res_test.code == 200)
print_error("#{rhost} likely answers positively to every request, check it manually.")
print_error("\t\t Proceeding with the scan may increase false positives.")
manual = true
end
iplist.each do |target|
next if manual and datastore['MANUAL_CHECK']
portlist.each do |port|
next if dead
vprint_status("[#{rhost}] Requesting #{target}:#{port}")
if port==443
res = send_request_cgi({
'uri' => "https://#{target}:#{port}",
'method' => 'GET',
'data' => '',
'version' => '1.0',
'vhost' => ''
}, 10)
else
res = send_request_cgi({
'uri' => "http://#{target}:#{port}",
'method' => 'GET',
'data' => '',
'version' => '1.0',
'vhost' => ''
}, 10)
end
if res and res.body
if res.code == 200 or res.body =~ /Zero/ or res.code == 404 or res.code == 401
print_good("[#{rhost}] #{target}:#{port} seems OPEN")
report_service(:host => target, :port => port, :name => "unknown", :info => res.body )
end
if res.body =~ /No route to host/
dead = true
print_error("[#{rhost}] #{target} is DEAD")
end
print_status("[#{rhost}] #{target}:#{port} blocked by ACL") if res.body =~ /Access control/
if res.body =~ /Connection refused/ or res.body =~ /service not listening/
report_host(:host => target)
print_good("[#{rhost}] #{target} is alive but #{port} is CLOSED")
end
end
end
dead = false
end
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
rescue ::Timeout::Error, ::Errno::EPIPE
end
end
end