CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/msf/core/auxiliary/vyos.rb
Views: 1904
1
# -*- coding: binary -*-
2
3
module Msf
4
###
5
#
6
# This module provides methods for working with VyOS equipment
7
#
8
###
9
module Auxiliary::VYOS
10
include Msf::Auxiliary::Report
11
12
def vyos_config_eater(thost, tport, config, store = true)
13
14
credential_data = {
15
address: thost,
16
port: tport,
17
protocol: 'tcp',
18
workspace_id: myworkspace_id,
19
origin_type: :service,
20
private_type: :nonreplayable_hash,
21
# jtr_format: 'sha512,crypt', # default on the devices 11.4.0+
22
service_name: '',
23
module_fullname: fullname,
24
status: Metasploit::Model::Login::Status::UNTRIED
25
}
26
27
# Default SNMP to UDP
28
if tport == 161
29
credential_data[:protocol] = 'udp'
30
end
31
32
if store && !config.include?('such file or directory') && !config.include?('ermission denied')
33
l = store_loot('vyos.config', 'text/plain', thost, config.strip, 'config.txt', 'VyOS Configuration')
34
vprint_good("#{thost}:#{tport} Config saved to: #{l}")
35
end
36
37
host_info = {
38
host: thost,
39
os_name: 'VyOS'
40
}
41
report_host(host_info)
42
43
# generated by: cat /config/config.boot
44
# https://github.com/rapid7/metasploit-framework/issues/14124
45
46
# login {
47
# user jsmith {
48
# authentication {
49
# encrypted-password $6$ELBrDuW7c/8$nN7MwUST8s8O0R6HMNu/iPoTQ1s..y8HTnXraJ7Hh4bHefRmjt/2U08ZckEw4FU034wbWaeCaB5hq7mC6fNXl/
50
# plaintext-password ""
51
# }
52
# full-name "John Smith"
53
# level operator
54
# }
55
# user vyos {
56
# authentication {
57
# encrypted-password $1$5HsQse2v$VQLh5eeEp4ZzGmCG/PRBA1
58
# plaintext-password ""
59
# }
60
# level admin
61
# }
62
# }
63
64
# sometimes the hash is masked
65
66
# login {
67
# user vyos {
68
# authentication {
69
# encrypted-password ****************
70
# plaintext-password ""
71
# }
72
# level admin
73
# }
74
# }
75
76
# plaintext-password can also be missing: https://github.com/rapid7/metasploit-framework/pull/14161#discussion_r492884039
77
78
# in >= 1.3 'level' is no longer included and defaults to admin.
79
80
r = 'user ([^ ]+) {\s*authentication {\s*'
81
r << 'encrypted-password (\$?[\w$\./\*]*)\s*' # leading $ is optional in case the password is all stars
82
r << '(?:plaintext-password "([^"]*)")?\s*' # optional
83
r << '}'
84
r << '(?:\s*full-name "([^"]*)")?\s*' # optional
85
r << '(?:level (operator|admin))?' # 1.3+ seems to have removed operator
86
config.scan(/#{Regexp.new(r)}/mi).each do |result|
87
username = result[0].strip
88
hash = result[1].strip
89
# full-name is an optional field
90
# we label it, but dont actually use it. Maybe future expansion?
91
unless result[3].nil?
92
name = result[3].strip
93
end
94
if result[4].nil?
95
level = 'admin'
96
else
97
level = result[4].strip
98
end
99
cred = credential_data.dup
100
cred[:username] = username
101
unless hash.start_with?('********') # if not in config mode these are masked
102
cred[:jtr_format] = Metasploit::Framework::Hashes.identify_hash(hash)
103
cred[:private_data] = hash
104
print_hash = " with hash #{hash}"
105
end
106
cred[:access_level] = level
107
create_credential_and_login(cred) if framework.db.active
108
unless result[2].to_s.strip.empty?
109
plaintext = result[2].strip
110
cred[:jtr_format] = ''
111
cred[:private_type] = :password
112
cred[:private_data] = plaintext
113
create_credential_and_login(cred) if framework.db.active
114
print_hash = "with password #{plaintext}"
115
end
116
print_good("#{thost}:#{tport} Username '#{username}' with level '#{level}'#{print_hash}")
117
end
118
119
# generated by: cat /config/config.boot
120
121
# service {
122
# snmp {
123
# community ro {
124
# authorization ro
125
# }
126
# community write {
127
# authorization rw
128
# }
129
# }
130
# }
131
132
config.scan(/community (\w+) {\n\s+authorization (ro|rw)/).each do |result|
133
cred = credential_data.dup
134
cred[:port] = 161
135
cred[:protocol] = 'udp'
136
cred[:service_name] = 'snmp'
137
cred[:jtr_format] = ''
138
cred[:private_data] = result[0].strip
139
cred[:private_type] = :password
140
cred[:access_level] = result[1].strip
141
create_credential_and_login(cred) if framework.db.active
142
print_good("#{thost}:#{tport} SNMP Community '#{result[0].strip}' with #{result[1].strip} access")
143
end
144
145
# generated by: cat /config/config
146
147
# host-name vyos
148
149
# interfaces {
150
# ethernet eth0 {
151
# duplex auto
152
# hw-id 00:0c:29:c7:af:bc
153
# smp_affinity auto
154
# speed auto
155
# }
156
# ethernet eth0 {
157
# address 1.1.1.1/8
158
# hw-id 00:0c:29:c7:af:cc
159
# }
160
# loopback lo {
161
# }
162
# }
163
164
# /* Release version: VyOS 1.1.8 */
165
# // Release version: VyOS 1.3-rolling-202008270118
166
167
if /host-name (.+)\n/ =~ config
168
print_good("#{thost}:#{tport} Hostname: #{$1.strip}")
169
host_info[:name] = $1.strip
170
report_host(host_info) if framework.db.active
171
end
172
173
if %r{^/[/\*]\s?Release version: ([\w \.-]+)} =~ config
174
print_good("#{thost}:#{tport} OS Version: #{$1.strip}")
175
host_info[:os_flavor] = $1.strip
176
report_host(host_info) if framework.db.active
177
end
178
179
#config.scan(%r{ethernet (eth\d{1,3}) {[\w\s":-]+(?:address ([\d\.]{6,16}/\d{1,2})[\w\s:-]+)?(?:description "?([\w\.\_\s]+)"?[\w\s:-]+)?hw-id (\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})[\w\s:-]+}}).each do |result|
180
r = 'ethernet (eth\d{1,3}) {[\w\s":-]+'
181
r << '(?:address ([\d\.]{6,16}/\d{1,2})[\w\s:-]+)?'
182
r << '(?:description ["\']?([\w\.\_\s]+)["\']?[\w\s:-]+)?'
183
r << 'hw-id (\w{2}:\w{2}:\w{2}:\w{2}:\w{2}:\w{2})[\w\s:-]+'
184
r << '}'
185
config.scan(/#{Regexp.new(r)}/i).each do |result|
186
name = result[0].strip
187
mac = result[3].strip
188
host_info[:mac] = mac
189
output = "#{thost}:#{tport} Interface #{name} (#{mac})"
190
191
# static IP address
192
unless result[1].nil?
193
ip = result[1].split('/')[0].strip
194
host_info[:host] = ip
195
output << " - #{ip}"
196
end
197
198
# description
199
unless result[2].nil?
200
output << " with description: #{result[2].strip}"
201
end
202
report_host(host_info) if framework.db.active
203
print_good(output)
204
end
205
206
# https://docs.vyos.io/en/crux/interfaces/wireless.html
207
208
# server has type 'access-point', client is 'station'
209
210
# interfaces {
211
# wireless wlan0 {
212
# address 192.168.2.1/24
213
# channel 1
214
# mode n
215
# security {
216
# wpa {
217
# cipher CCMP
218
# mode wpa2
219
# passphrase "12345678"
220
# }
221
# }
222
# ssid "TEST"
223
# type access-point
224
# }
225
#}
226
227
config.scan(/wireless (wlan\d{1,3}) {\s+.+passphrase "([^\n"]+)"\s+.+ssid ["']?([^\n"]+)["']?\s+type (access-point|station)/mi).each do |result|
228
device = result[0].strip
229
password = result[1].strip
230
ssid = result[2].strip
231
type = result[3].strip
232
cred = credential_data.dup
233
cred[:port] = 1
234
cred[:protocol] = 'tcp'
235
type == 'access-point' ? cred[:service_name] ='wireless AP' : cred[:service_name] ='wireless'
236
cred[:jtr_format] = ''
237
cred[:private_data] = password
238
cred[:username] = ssid
239
cred[:private_type] = :password
240
create_credential_and_login(cred) if framework.db.active
241
print_good("#{thost}:#{tport} Wireless #{type} '#{ssid}' with password: #{password}")
242
end
243
244
# wireless (server) with radius
245
246
# interfaces {
247
# wireless wlan0 {
248
# address 192.168.2.1/24
249
# channel 1
250
# mode n
251
# security {
252
# wpa {
253
# cipher CCMP
254
# mode wpa2
255
# radius {
256
# server 192.168.3.10 {
257
# key 'VyOSPassword'
258
# port 1812
259
# }
260
# }
261
# }
262
# }
263
# ssid "Enterprise-TEST"
264
# type access-point
265
# }
266
# }
267
268
r = 'wireless (wlan\d{1,3}) {\s*'
269
r << '.+radius {\s+'
270
r << 'server ([^\s]+) {\s*'
271
r << 'key [\'"]?([^\n"]+)[\'"]?\s*'
272
r << 'port (\d{1,5})\s*'
273
r << '.+ssid [\'"]?([^\n"\']+)[\'"]?\s*'
274
r << 'type (access-point|station)'
275
276
#config.scan(/#{Regexp.new(r)}/mi).each do |result|
277
config.scan(/wireless (wlan\d{1,3}) {\s*.+radius {\s+server ([^\s]+) {\s*key ['"]?([^\n"']+)['"]?\s*port (\d{1,5})\s*.+ssid ['"]?([^\n"']+)['"]?\s*type (access-point|station)/mi).each do |result|
278
device = result[0].strip
279
server = result[1].strip
280
password = result[2].strip
281
server_port = result[3].strip
282
ssid = result[4].strip
283
type = result[5].strip
284
cred = credential_data.dup
285
cred[:port] = 1
286
cred[:protocol] = 'tcp'
287
type == 'access-point' ? cred[:service_name] ='wireless AP' : cred[:service_name] ='wireless'
288
cred[:jtr_format] = ''
289
cred[:private_data] = password
290
cred[:username] = ssid
291
cred[:private_type] = :password
292
create_credential_and_login(cred) if framework.db.active
293
print_good("#{thost}:#{tport} Wireless #{type} '#{ssid}' with radius password: #{password} to #{server}#{server_port}")
294
end
295
296
# https://docs.vyos.io/en/crux/services/ipoe-server.html#radius-setup
297
298
# https://docs.vyos.io/en/crux/services/webproxy.html#authentication
299
300
# https://docs.vyos.io/en/crux/vpn/pptp.html#server-example
301
302
# https://docs.vyos.io/en/crux/interfaces/l2tpv3.html#l2tpv3-over-ipsec-l2-vpn-bridge
303
304
# https://docs.vyos.io/en/crux/interfaces/pppoe.html#pppoe
305
306
# /config/auth/ldap-auth.config
307
308
end
309
end
310
end
311
312