This is the second blog in a two-part series covering the exploitation of the Palo Alto Networks GlobalProtect VPN client running on Linux and macOS. The first blog covered this exploitation on Windows.
To recap, the CrowdStrike® Intelligence Advanced Research Team discovered two distinct vulnerabilities in the Windows, Linux and macOS versions of the Palo Alto Networks GlobalProtect VPN client (CVE-2019-17435, CVE-2019-17436). The vulnerabilities allowed unprivileged users to reliably escalate to Overwriting
During our testing, we used the portal
Targeting
Unlike on Linux, the dynamic linker on macOS does not interpret /
root
or SYSTEM
on machines where the GlobalProtect software is used. Fixed versions were released on October 15, 2019, by Palo Alto Networks. We would like to thank Palo Alto Networks for handling and addressing the reported issues in a timely and professional manner.
Quick Facts
Affected Vendor: Palo Alto Networks Affected Software: GlobalProtect for Linux (verified on Ubuntu 18.04.2 LTS)
GlobalProtect for macOS (verified on Mojave version 10.14.5) Affected Version: 5.0.4 (and earlier), 4.1.12 (and earlier) Fixed Version: 5.0.5, 4.1.13 Vulnerability Type: Arbitrary Privileged File Write Estimated Risk: High (Local Privilege Escalation to UID 0) Identifiers: CVE-2019-17436 / GPC-8945 / PAN-SA-2019-0037 Vendor Reference: https://security.paloaltonetworks.com/CVE-2019-17436
The CVE-2019-17436 Vulnerability
The Linux GlobalProtect client consists of three executable files:PanGPS
: The PanGPS daemon is started once at boot time. PanGPS is responsible for negotiating VPN connections, and it configures network devices, routes, etc. It is started as the userroot
. The daemon listens for TCP connections on127.0.0.1:4767
.PanGPA
: The PanGPA daemon is automatically started once per log-in session and runs with the privileges of the logged-in user. It relays commands and responses between globalprotect and PanGPS via a TCP connection to127.0.0.1:4767
.globalprotect
: This executable implements a command-line interface (CLI). It is used by unprivileged users to interface with the other services (e.g., to trigger connecting to or disconnecting from the VPN, retrieve VPN status, etc.).
Configuration Files
It was observed that, under certain conditions, PanGPS for Linux createsroot
-owned files in the .GlobalProtect
directory that resides inside the home directory of the logged-in user:
These files are created on at least two occasions:
- If the configuration retrieval step during VPN connection negotiation fails, PanGPS tries to restore the file
PanPortalCfg_<hash>.dat
from the default configuration filePanPortalCfg.dat
. - If the configuration retrieval is successful, the configuration is written to
PanPortalCfg_<hash>.dat
. Furthermore, the files{PanPCD,PanPUAC}_<hash>.dat
are written as well.
<hash>
token represents the hexadecimal MD5 digest computed from the ASCII-encoded string <portal>_<username>
and that the *.dat
files are all encrypted with AES-256-CBC, using a fixed key and initialization vector:
During our testing, PanPCD_*
contained a single AES-encrypted null byte. PanPUAC_*
contained an AES-encrypted authentication cookie received during negotiation. PanPortalCfg_*
contained an AES-encrypted XML document that resembles a portal configuration file. Further analysis of PanGPS confirmed that the *.dat
files are accessed in such a way that symbolic links are resolved, and the files pointed to are truncated before they are overwritten.It is therefore possible to create and/or overwrite arbitrary files with root
permissions by replacing the *.dat
files with symbolic links and causing PanGPS to attempt to write to them. However, in order to leverage the full potential of this vulnerability, one also needs to be able to control the data that gets written into these *.dat
files.
Exploiting GlobalProtect on Linux
To exploit this behavior for local privilege escalation (LPE), we focused on the restoration ofPanPortalCfg_<hash>.dat
after a failed VPN connection attempt. We found that this route would be most effective as it does not require any network connectivity or interacting with a VPN server. After evaluating potential targets that could be overwritten, the file /etc/ld.so.preload
, which is interpreted by the dynamic linker, was chosen. This file contains a newline-separated list of paths to shared objects that will be preloaded into any newly created process of a dynamically linked executable. This includes processes that are created from executable files with the SUID bit set. Furthermore, the dynamic linker is rather forgiving when parsing ld.so.preload
files that contain only a single valid path that is embedded within seemingly invalid binary data.
Overwriting ld.so.preload
During our testing, we used the portal 127.0.0.1
and the username johndoe
. Thus, the <hash> that is part of the configuration file names can be computed as follows:
$ echo -n "127.0.0.1_johndoe" | md5sum
1662c17069ca30beb328f3ccdffe14fe
-
When triggering a failing VPN connection to 127.0.0.1
as user johndoe
, PanGPS will attempt to restore the portal configuration file PanPortalCfg_1662c17069ca30beb328f3ccdffe14fe.dat
from the default file PanPortalCfg.dat
. Therefore, we created a symlink named PanPortalCfg_1662c17069ca30beb328f3ccdffe14fe.dat
that points to /etc/ld.so.preload
in advance, which detours this write operation, and also created a file PanPortalCfg.dat
containing the data that we would like to be written:
$ ln -s /etc/ld.so.preload .GlobalProtect/PanPortalCfg_1662c17069ca30beb328f3ccdffe14fe.dat
$ echo "hello world!" > .GlobalProtect/PanPortalCfg.dat
$ ls -la ~/.GlobalProtect/
total 240
drwxrwxr-x
2 x
x
4096 Jul 15 04:19 .
drwxr-xr-x 25 x
x
4096 Jul 15 03:32 ..
-rw-rw-r--
1 x
x
196869 Jul 15 03:32 PanGPA.log
-rw-rw-r--
1 x
x
12850 Jul 15 03:05 PanGPI.log
<...>
lrwxrwxrwx
1 x
x
18 Jul 15 04:19 PanPortalCfg_1662c17069ca30beb328f3ccdffe14fe.dat -> /etc/ld.so.preload
-rw-rw-r--
1 x
x
13 Jul 15 04:19 PanPortalCfg.dat
<...>
Next, a VPN connection attempt is triggered using the aforementioned portal address and username:
$ globalprotect connect -p 127.0.0.1 -u johndoe
However, this did not yet yield the desired result — in other words, the file /etc/ld.so.preload
was not created. The log file PanGPS.log
shows that there was a problem with decrypting the default configuration file:
$ tail -n 30 /opt/paloaltonetworks/globalprotect/PanGPS.log
<...>
pan_read_text_from_file(): Failed to decrypt file /home/user/.GlobalProtect/PanPortalCfg.dat
cannot restore last portal config from file /home/user/.GlobalProtect/PanPortalCfg.dat.
<...>
Further analysis revealed that the PanGPS daemon verifies that the decrypted content of PanPortalCfg.dat
is indeed a semi-valid XML-based portal configuration file before overwriting the destination file. Knowing the crypto scheme (see above) that is used for the *.dat
files, it is possible to write a valid, encrypted configuration into PanPortalCfg.dat
. Then, when trying to bring up a VPN connection again, the encrypted content from PanPortalCfg.dat
does get copied to /etc/ld.so.preload
:
$ ls -la /etc/ld.so.preload
ERROR: ld.so: object '-º0´MëöS' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
ERROR: ld.so: object '9¼IJ·m?窆' from /etc/ld.so.preload cannot be preloaded (cannot open shared object file): ignored.
-rw-r--r-- 1 root root 7728 Jul 15 04:50 /etc/ld.so.preload
As evident from the lines starting with “ERROR:” the dynamic linker now tries to interpret /etc/ld.so.preload
when the ls
command is executed. As the file only contains AES-encrypted data, no meaningful paths to shared objects can be extracted by the dynamic linker.
In summary, the following conditions must be fulfilled to write meaningful content to /etc/ld.so.preload
:
PanPortalCfg.dat
must be encrypted according to the crypto scheme described earlier.- The plaintext of
PanPortalCfg.dat
must be an XML document that is parsable by PanGPS as a portal configuration file. Our research shows that it does not necessarily have to contain valid XML, but it must at least contain a minimal amount of configuration-specific tags. - The ciphertext of
PanPortalCfg.dat
gets copied to/etc/ld.so.preload
. Therefore, the ciphertext must be parsable by the dynamic linker, and it must contain the path to an attacker-controlled shared object. Of course, any crafted ciphertext must decrypt to a plaintext XML document that PanGPS can successfully parse.
Crafting Configuration Files
In order to fulfill these requirements, we first focused on crafting an XML document, and then we determined how to insert a ciphertext block that contains the path to a shared object file without breaking any of the requirements. The initial test used a real portal configuration file, which was approximately 8 KB in size. By successively removing tags, encrypting the resulting XML and letting PanGPS decide whether the presented configuration is still acceptable, it was determined that the simplest XML configuration that PanGPS would still accept as valid is the following:<?xml version="1.0" encoding="UTF-8" ?>
<policy>
<gateways></gateways>
<agent-ui></agent-ui>
</policy>
For encryption, PanGPS uses the AES block cipher. The AES algorithm has a block size of 16 bytes, meaning that any attempts to influence the ciphertext are limited to changing one or more full 16-byte blocks. The XML declaration in the first line of the above XML document is already 39 bytes in size (encoded as ASCII, not counting the newline character) — in other words, it is contained within the first three ciphertext blocks. As the XML declaration is absolutely mandatory for PanGPS, the earliest 16-byte block boundary on which a tampered block could be inserted is at the next block that follows the XML declaration, at position 3*16 = 48. If a user-controlled shared object is created as /tmp/ldp.so
, a single tampered 16-byte ciphertext block like the following would be sufficient:
Since the dynamic linker parses /etc/ld.so.preload
line by line, this block contains the path /tmp/ldp.so
, delimited by newline characters and followed by three space characters as padding. The dynamic linker will parse the file and successfully interpret the line, even if it is embedded into seemingly invalid binary data. As any plaintext that would result in the aforementioned human-readable ciphertext after encryption would very likely not be meaningful in the XML document, we therefore tested and verified that it is possible to insert a bogus <f>
element with arbitrary binary data as a second root element into the document, just after the XML declaration, even if the resulting document is technically no longer valid XML. This made it possible to craft an XML document with an <f>
tag at the end of Block 3 (just after the XML declaration), a manipulated Block 4, and a closing </f>
tag at the beginning of Block 5. The rest of Block 5 as well as the following blocks are used for the <policy>
tag.As PanGPS uses the AES block cipher in a Cipher Block Chaining (CBC) mode of operation, it is not possible to simply encrypt Blocks 1 through 3 and Blocks 5 through 8 individually and insert a manipulated block into position 4. Instead, Block 1 through 3 must be encrypted in sequence using the null byte initialization vector, as described earlier. Next, the ciphertext of Block 3 (CBC feedback) is used as an initialization vector for CBC decrypting the block that is to be inserted into the ciphertext (highlighted in red). The result of this decryption (highlighted in green) is inserted into the plaintext as Block 4. Then, the CBC encryption can continue normally until Block 8. The plaintext XML file as seen by PanGPS is shown below (every line corresponds to a single plaintext block of 16 bytes): CBC encryption of that plaintext yields the following ciphertext (in which every line corresponds to a single ciphertext block of 16 bytes): If the above content is written to
PanPortalCfg.dat
, and the symbolic link from PanPortalCfg_1662c17069ca30beb328f3ccdffe14fe.dat to /etc/ld.so.preload
is in place, a VPN connection attempt to 127.0.0.1
with the username johndoe
will result in the desired write operation to /etc/ld.so.preload
. From the subsequent execution of the ls
command, it is evident that the dynamic linker is now trying to load /tmp/ldp.so
when a dynamically linked program is executed (highlighted in red):
The Payload
Since the dynamic linker will now attempt to preload/tmp/ldp.so
for all dynamically linked executables, even those that have the SUID bit set (like umount
), an unprivileged user can now create /tmp/ldp.so
to implement and execute any privileged operation. As a proof of concept, we wrote a simple shared library in C:
When loaded into a root
-owned process, the library creates a copy of the /bin/bash
executable and sets the SUID bit on that copy (highlighted in red). To prevent this from being executed by all processes (since the effect of /etc/ld.so.preload
is global), the code verifies that it is being called from the umount
executable (highlighted in green). As the umount
binary is owned by root
and has the SUID set by default, it is always executed with the privileges of the root
user and is therefore an ideal target for injecting the shared library. The library can be compiled using GCC as follows:
$ gcc -shared -fPIC -o /tmp/ldp.so ldp.c
In the following listing, it can be seen that the root
-owned bash2
SUID binary has been created after invoking umount
:
Finally, the bash2 SUID binary can be invoked with the parameter -p, which prevents it from dropping its privileges, and the newly gained effective user ID 0 can be verified (highlighted in red):
In total, this vulnerability allows local, unprivileged users to escalate their privileges to UID 0 (root
). The whole process has been automated in a Python script. Instead of using the globalprotect
binary to initiate the VPN connection attempt, the Python script interfaces directly with the PanGPS process via a socket that PanGPS opens on 127.0.0.1:4767
. Its execution is shown below:
Exploiting GlobalProtect on macOS
Analyzing the macOS implementation of the GlobalProtect client showed that it is affected by the same vulnerability. However, the exploit must be adapted to address some specifics of the macOS client. Similar to the Linux version, PanGPS for macOS creates the same kind ofroot
-owned *.dat
files in the following directory:
${HOME}/Library/Application Support/PaloAltoNetworks/GlobalProtect
Encryption Password
In contrast to the Linux version, the macOS client uses an AES key that is derived from a randomly generated application password (GP_PASS
) to encrypt the *.dat
files. That password is stored in the user’s keychain. It is individually generated for each user when the GlobalProtect client is started for the first time. The password of the current user can be retrieved with the following command:
$ security find-generic-password -ws GlobalProtectService
485db861598a87071d0b86ba232aa9bd
Retrieving the application password in this way requires entering the user’s log-in password twice. Key derivation in the GlobalProtect VPN client on macOS works as follows:
The same AES key is used to encrypt the communication between the PanGPA GUI application and PanGPS.
Targeting root
’s Crontab
Unlike on Linux, the dynamic linker on macOS does not interpret /etc/ld.so.preload
, so a different approach must be used to escalate privileges on that operating system. One such possibility is to create a cron job for the root
user by writing to /private/var/at/tabs/root
. That cron job can invoke an attacker-controlled shell script to create a root
-owned SUID bash executable. Before PanGPS overwrites the root
crontab file, a popup message prompting the user for confirmation is shown. Like the dynamic linker on Linux, cron is very forgiving when interpreting crontabs. Any line in the correct format will be interpreted, even if it is surrounded by invalid binary data.
The following listing shows the job that will be placed in Blocks 4 and 5 of the ciphertext (highlighted in red):
The corresponding plaintext XML file, as seen by PanGPS, is shown below (every line corresponds to a single plaintext block of 16 bytes, and the actual bytes depend on the user-specific AES key):
CBC encryption of this XML file results in the following ciphertext, which is accepted by the cron daemon as a valid crontab:
It should be noted that the injected plaintext blocks representing the crontab entry must not contain XML syntax elements (such as angular brackets) to avoid parsing failures by PanGPS. Depending on the user-specific AES key, the injected blocks may therefore have to be adapted by changing them to an equivalent form, e.g., by specifying a different file name for the shell script to be invoked. The exploitation procedure for macOS has been automated as well and the execution of the exploit is shown below:
Conclusion
In this blog, we explained the issues we had to overcome to successfully exploit an otherwise fairly standard vulnerability within GlobalProtect for Linux and macOS. To recap:- The GlobalProtect agent consists of several components, among which PanGPS runs with elevated privileges so that it can perform privileged operations.
- Most notably, PanGPS creates files in a user’s home directory under some circumstances, e.g., when user-initiated VPN connection attempts fail.
- These files are created with
root
privileges, and PanGPS will follow symbolic links when creating them, potentially allowing an unprivileged user to overwrite or create files in arbitrary filesystem locations. - The files are copied from a source file that can be manipulated by the unprivileged user, but the files are encrypted, and PanGPS validates some aspects of the plaintext before copying them.
- Knowing the encryption scheme, it is possible to craft files whose plaintext passes that validation, but whose ciphertext can be sufficiently controlled to allow for escalation of privilege when creating the right file:
- On Linux, we demonstrated overwriting
/etc/ld.so.preload
to preload a user-controlled shared object when any dynamically linked executable is started. This allows for elevation of privilege when theroot
user starts such executables, but more conveniently, when the unprivileged user specifically starts an executable likeumount
that is owned byroot
and has the SUID bit set. - On macOS, we demonstrated overwriting a crontab for
root
to spawn a user-controlled shell script withroot
privileges.
- On Linux, we demonstrated overwriting
Additional Resources
- Read expert insights and analysis on today’s most complex threats, download the CrowdStrike 2020 Global Threat Report
- Learn more about comprehensive endpoint protection with the CrowdStrike Falcon® platform by visiting the product page.
- Test CrowdStrike next-gen AV for yourself. Start your free trial of Falcon Prevent™ today.