squid pivot scanning module

This commit is contained in:
Willis Vandevanter
2012-03-06 00:30:30 -05:00
parent 7f9880a1fc
commit 0f17bbdfdd
@@ -0,0 +1,130 @@
##
# $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
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.
},
'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", '']),
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])
], self.class)
end
def run_host(target_host)
begin
iplist = Rex::Socket::RangeWalker.new(datastore['RANGE'])
dead = false
vprint_status("#{iplist.length} total IPs")
portlist = Rex::Socket.portspec_crack(datastore['PORTS'])
iplist.each do |target|
portlist.each do |port|
next if dead
vprint_status("[#{rhost}] Running test check")
#request a non-existent page first to make sure the server doesn't respond with a 200 to everything.
res = send_request_cgi({
'uri' => "http://127.0.11.1:80",
'method' => 'GET',
'data' => '',
'version' => '1.0',
'vhost' => ''
}, 10)
if res and res.body and (res.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
next if manual and datastore['MANUAL_CHECK']
vprint_status("[#{rhost}] Checking #{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_bad("[#{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