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

136 lines
4.4 KiB
Ruby
Raw Normal View History

2012-03-06 05:30:30 +00:00
##
# $Id$
##
##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
# http://metasploit.com/
##
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 their behalf.
This may give the attacker information about devices that they 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
2012-03-06 05:30:30 +00:00
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).
2012-03-06 05:30:30 +00:00
},
'Author' => ['willis'],
'Version' => '$Revision$',
'References' =>
[
'URL','http://wiki.squid-cache.org/SquidFaq/SecurityPitfalls'
],
'License' => MSF_LICENSE
)
register_options(
[
OptString.new('RANGE', [true, "IPs to scan through Squid proxy", '']),
2012-03-06 05:30:30 +00:00
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"])
2012-03-06 05:30:30 +00:00
], 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'])
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
2012-03-06 05:30:30 +00:00
iplist.each do |target|
next if manual and datastore['MANUAL_CHECK']
2012-03-06 05:30:30 +00:00
portlist.each do |port|
next if dead
vprint_status("[#{rhost}] Requesting #{target}:#{port}")
2012-03-06 05:30:30 +00:00
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
2012-03-28 06:32:03 +00:00
print_error("[#{rhost}] #{target} is DEAD")
2012-03-06 05:30:30 +00:00
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