Skip to content

Local Privilege Escalation Discovered in VMware Fusion

Local Privilege Escalation Discovered in VMware Fusion

Local Privilege Escalation Discovered in VMware Fusion

Versions Tested:
VMware Fusion 11.5.3

Products:

Security Advisories:

CVE Number(s):
CVE-2020-3957

CVSS Score:
7.3

CWE:

  • CWE-367: Time-of-check Time-of-use (TOCTOU) Race Condition
  • CWE-424: Improper Protection of Alternate Path

NIST:
N/A

OWASP:
N/A

Summary:

VMware Fusion, VMRC and Horizon Client contain a local privilege escalation vulnerability due to a Time-of-check Time-of-use (TOCTOU) issue in the service opener.

A second local privilege escalation was discovered that is not a race condition. The application blindly executes files from an untrusted location. Both vulnerabilities result in arbitrary code execution as root. The following disclosure provides details of the second vulnerability using dynamic testing. A proof of concept exploit will be provided for both vulnerabilities.

Details:

VMware introduced a signature check in an attempt to resolve CVE-2020-3950, a local privilege escalation vulnerability in VMware Fusion prior to version 11.5.2. Jeff Ball discovered the fix was incomplete and introduced a race condition with code signature verification logic.

To illustrate the behavior when the code signature check fails, I created a hard link to the Open VMware Fusion Services binary, setting the trailing path to Contents/Library/services to mimic the expected path. A hard link is necessary to preserve the setuid bit. However, executing the binary results in a code signing error. The check verifies the signature of VMware Fusion Services prior to execution. To bypass this restriction, I created another hard link to VMware Fusion Services and executed it again. There is no longer a code signing error. This created several other opportunities for code injection because no additional signature checks were performed.

For the remainder of this blog, assume that the TOCTOU vulnerability does not exist. The goal is to elevate privileges to root. When dynamically testing a privileged binary, start by analyzing file interactions. For macOS Mojave systems, use dtruss(1m) and the Monitor utility from FireEye. For newer versions of macOS, use Crescendo to determine how the application uses files and look for interesting behavior such as the locations of files being read, written, or executed.

To initiate a simple test, create a copy or hard link of a binary and execute it from a location under your control. A hard link is necessary to preserve the setuid/setgid bits if set. macOS uses a single file system, which makes this attack practical. Important to note is that Apple has not implemented kernel restrictions on symbolic and hard links like Linux did many years ago. Some applications implicitly trust parts of the path. When the application is privileged this scenario could lead to code execution.

To begin, I usually copy and run the entire application to a location I control, and review how it interacts with files, sockets, pipes, etc. Below is an example using the Monitor utility, root executed a file named services.sh under the home directory of the low privileged test99 user. We achieved this by copying the entire /Applications/VMware Fusion.app directory and then executing the VMware Fusion from that location via the command line.

With the leading path under the control of the test99 user, I injected a single line at the top of the script to create a file in /tmp. If the update is successful, /tmp/test.123 will exist and be owned by root.

After updating services.sh, I manually executed VMware Fusion from the command line and the file was created as expected.

In some instances, privileges could be dropped by the application or bash before accessing a file. When reviewing a list of files accessed in the Monitor application, I always verify the value of Euid field. Below is an example where further investigation was needed. At first glance it appears the low privileged test99 user is executing the vmware-id binary. If a file is created when only the Euid is set to zero, the file will be owned by the low privileged user unless the application explicitly sets the ownership.

For further details, select the record to display a window with additional properties about the process. It shows the vmware-id binary was executed as the test99, under a location the test99 user controls, and the EUID is set to zero, which is the root user. This could be an opportunity to escalate privileges to root.

By default, bash will automatically drop privileges if uid != euid (effective uid). This behavior can be disabled by enabling privileged mode using the -p option. VMware uses privileged mode with several bash scripts, which is not common.  It is possible to successfully exploit a vulnerability only to have bash drop the privileges. Not all shells have this feature. For example, the Korn shell (ksh) retains the euid value.

It is important to showcase the behavior using a setuid root bash shell. As root, make a copy of /bin/bash and change the permissions to 4755. The 4000 octal number adds the setuid bit. As a low privileged user, execute the setuid root copy of bash. Notice that even though the shell is setuid root, no root privileges are gained due to the default behavior. Executing the shell with the -p option overrides the security feature and root privileges are retained(euid=0).

At this point, code execution as root has been confirmed by creating the root owned file in /tmp. The next step is to spawn an interactive root shell. For a proof of concept, creating a setuid root shell or a local netcat reverse shell is usually sufficient. Netcat was chosen for this blog to show the parent processes.

The proof of concept can be download at CVE-2020-3957.sh. The PoC will create a copy of /Applications/VMware Fusion.app using hard links, inject a netcat command into services.sh, and directly execute the application.

A local reverse shell running as root is received.

It is important to show the process tree in reverse from the netcat shell. Each ps command below displays the parent process. This shows services.sh executing as root under the test99 users home directory which contains the netcat command.

On a final note I want to thank my colleague Charles Dardaman for testing and verifying the proof of concept.

Credit:
Discovered by Rich Mirch, Senior Adversarial Engineer at TEAMARES
Signature check bypass (TOCTOU) discovered by Jeff Ball