Unauthorized RCE in VMware vCenter

superior_hosting_service

Since the PoC for the VMware vCenter RCE (CVE-2021-21972) is now readily available, we’re publishing our article covering all of the technical details.

In fall of 2020, I discovered couple vulnerabilities in the vSphere Client component of VMware vCenter. These vulnerabilities allowed non-authorized clients to execute arbitrary commands and send requests on behalf of the targeted server via various protocols:

  • Unauthorized file upload leading to remote code execution (RCE) (CVE-2021- 21972)
  • An unauthorized server-side request forgery (SSRF) vulnerabilities (CVE-2021-21973)

In this article, I will cover how I discovered the VMware vSphere client RCE vulnerability, divulge the technical details, and explain how it can be exploited on various platforms.

What is VMware vCenter/vSphere?

vSphere and vCenter enable the virtualization of corporate infrastructure and provide means of control over it. While this software can be encountered on the perimeter, in most cases it is located on internal networks.

Discovering the vulnerability

During the analysis of the vSphere Client, I employed both a black-box and a white-box approach to testing, as usual, focusing on vulnerabilities that could be exploited without authorization. From the web panel I tried to send as many different requests as possible, all without cookie headers.

After sending an unauthorized request to /ui/vropspluginui/rest/services/*, I discovered that it did not in fact require any authentication.

brup

URL is accessible without authorization

The web application relies on plugins, usually located in separate .jar files, for some of its features. The vropspluginui plugin, for example, is implemented in the file vropsplugin-service.jar.

From what I understand, each plugin must specify which of its endpoints require authorization in the web panel to run and which do not. This plugin was configured to allow unauthorized users to access any URL it handled.

The uploadOvaFile function, responsible for the URL /ui/vropspluginui/rest/services/uploadova, piqued my interest.

req1

Vulnerable part of code

The handler for this path performed the following actions:

  1. Received a POST request with the uploadFile parameter.
  2. Read and wrote the content of this parameter to the inputStream variable.
  3. Opened the resulting data as a .tar archive.
  4. Retrieved all of the archive’s (non-directory) entries.
  5. While iterating over all of the entries, a copy of each current entry was created on disk using the file naming convention: /tmp/unicorn_ova_dir + entry_name.

This was where I noticed that the names of the .tar entries are not filtered. They are simply concatenated with the string “/tmp/unicorn_ova_dir”; a file is created at the resulting location. This meant we could create an archive entry containing the string “../”, which would allow us to upload an arbitrary file to an arbitrary directory on the server.

To make a .tar archive taking advantage of this quirk, I used the evilarc utility.

python evilarc.py -d 2 -p 'testFolder\' -o win -f winexpl.tar testUpload.txt

The resulting archive contained a file with the name ..\..\testFolder\testUpload.txt. I uploaded it to the URL /ui/vropspluginui/rest/services/uploadova and checked the server’s filesystem for the presence of the testFolder folder and its nested file in the C:\ root directory.

POST /ui/vropspluginui/rest/services/uploadova HTTP/1.1
 Host: vSphereClient.local
 Connection: close
 Accept: application/json
 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryH8GoragzRFVTw1VD
 Content-Length: 10425
 ------WebKitFormBoundaryH8GoragzRFVTw1VD
 Content-Disposition: form-data; name="uploadFile"; filename="a.ova"
 Content-Type: text/plain
 {craftedArchive}
 ------WebKitFormBoundaryH8GoragzRFVTw1VD--
fold

Test file was successfully uploaded

My .txt file had been successfully uploaded and was now accessible at C:\testFolder\testUpload.txt.

Getting RCE on Windows

In order to be able to execute arbitrary commands on a target system, we need to upload a .jsp shell that will be accessible without authorization. To discover such a location:

  • Find writeable paths on disk where file creation using the previously described vulnerability is possible
  • Map found file paths into the folder structure of accessible web-roots, able to run .jsp scripts and not requiring authorization.

First off, let’s check which privileges our uploaded files acquire by uploading the file testUpload.txt and looking at its properties menu. We can see that its owner is the user “vsphere-ui”.

detail

Properties of uploaded file

In our search for a candidate location the directory C:\ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport\ (in which .jsp files are present) looks promising. 

burp2

JSP script is accessible without authorization

The check for unauthorized access to jsp scripts yields success. Let’s check whether vsphere-ui has write privileges to this directory.

uplo

Security-specific properties of the target folder

And sure enough, it does. Great! Now we can upload a specially crafted .jsp file to execute commands on the system.

Let’s create an archive containing our crafted .jsp shell payload and send it to the URL that we’re studying.

python evilarc.py -d 5 -p 'ProgramData\VMware\vCenterServer\data\perfcharts\tc-instance\webapps\statsreport' -o win -f winexpl.tar testRCE.jsp
burp3

Vulnerability exploitation

Our .jsp script has been uploaded to the server, giving us the opportunity to execute arbitrary commands on the system with NT AUTHORITY\SYSTEM privileges.

Getting RCE on Linux

Things are a bit different for Linux instances. But they, too, are vulnerable and allow external users to upload arbitrary files.

On Linux I could not find a directory which allowed the simultaneous upload and execution of .jsp shells. Instead, there exists another method of achieving command execution on the server.

We know we can upload arbitrary files with the rights of the vsphere-ui user. What if we upload a public key to this user’s home directory and try connecting to the server via SSH using the private key?

Let’s check whether SSH is externally accessible:

nmap -p 22 vSphereLinux.local
nmap

Target port is open

The first step is to generate a key pair:

ssh-keygen -t rsa

Key-pair generation

A .tar archive is then created with the generated public key:

python evilarc.py -d 5 -p 'home/vsphere-ui/.ssh' -o unix -f linexpl.tar authorized_keys
expl

Generating a tar archive with evilarc

Next, we upload the file using the vulnerability and attempt to connect to the target host via SSH:

ssh -i /path/to/id_rsa vsphere-ui@vSphereLinux.local
list

Getting access to command line

Ta-da! We have access to the server with the rights of the vsphere-ui user.

Conclusion

In this article, I have demonstrated a method of achieving RCE in VMware vSphere Client as an unauthenticated user. In addition to getting access to the command line, an attacker can perform other malicious actions due to the lack of authentication in the vropspluginui plugin.

Updating to the latest version of VMware vSphere Client is highly recommended. Please see iVMSA-2021-0002 for more information.

I Hope I have helped to make the world a little bit safer!

Timeline

  • October 2, 2020 — Vulnerability reported to vendor
  • October 3, 2020 — First response from vendor
  • October 9, 2020 — Vulnerability successfully reproduced and vendor started working on the fix plan
  • February 23, 2021 — Vulnerability fixed and advisory published

Auhor

Mikhail Klyuchnikov : Web Application Security Expert