Category Privilege Escalation

Pulse Secure Client for Windows <9.1.6 TOCTOU Privilege Escalation (CVE-2020-13162)

In the midst of the coronavirus pandemic we have observed an incredible boost in the diffusion of configurations allowing people to work from home. Being able to quickly identify vulnerabilities in the components of these infrastructures has become, more than before, a priority for many businesses. So the lenient Red Timmy has thought: “it would be good to kill some 0day while we go through this hard time“.

After careful evaluation of the options available, we have decided to proceed with a deep inspection of the Pulse Secure VPN client. Why? Beyond the large installation base in the Fortune 500 market, there are plenty of medium-size companies out there adopting the Pulse Secure products. Try to imagine a business distributing laptops to its employees through which they can connect remotely, via VPN, to the employer’s infrastructure and comfortably work from home. Of course the operating system running on these laptops is hardened in order to disallow the installation of arbitrary software, disable the antivirus or the other monitoring/security agents and more in general to avoid the execution from employees of any actions that would normally require admin rights.

Now imagine an employee (might be a malicious insider) escalating to “NT_AUTHORITY\SYSTEM” in one of these laptops before or after having established a connection to the company VPN network, with security measures, configurations and software disabled or tampered, with the possibility to install any programs or hide hacking tools in the system without restrictions, with the aim to lower down the threat detection and identification capabilities of SOC. How bad would it be? This is what could have happened by exploiting the vulnerability on Pulse Secure client we are going to talk about today, before the vendor patched it. We have registered CVE-2020-13162 for that.

High-Level Overview and Impact

Pulse Secure Client for Windows suffers of a local privilege escalation vulnerability in the “PulseSecureService.exe” service. Exploiting this issue allows an attacker to trick “PulseSecureService.exe” into running an arbitrary Microsoft Installer executable (“.msi”) with SYSTEM privileges, granting them administrative rights.

The vulnerability lies in the “dsInstallerService” component, which provides non-administrative users the ability to install or update new components using installers provided by Pulse Secure. While “dsInstallerService” performs a signature verification on the content of the installer, it has been found that it’s possible to bypass the check providing the service with a legit Pulse Secure installer and swapping it with a malicious one after the verification (see Analysis paragraph below).

The vulnerability is a TOCTOU (time-of-check to time-of-use) and can be exploited reliably using an exclusive opportunistic lock.

This bug can be exploited in default configuration and the tester is not aware of any available configuration preventing exploitation. All the versions we have tested < 9.1R6 (including the branch 5.x as the version 5.3 R70 released on January 2017) have been successfully exploited during our tests. The checks were conducted both on a fresh install of Windows 10 1909 and Windows 8.1.

The bug was discovered by Giuseppe Calì (@gsepcali). A full exploit, which will be released in the near future, has been written by Marco Ortisi (more about the exploit in the notes below).


The server component of the Pulse Secure solution, Pulse Secure Connect, provides installers to deploy on client machines. Some of these, such as “Pulse Secure Installer Service (.exe)” and “Host Checker (.exe)“, can be installed without admin privileges (see Figure 1).

Figure 1: description of one of the observed installers provided in the PSC admin interface.

Despite stating that the packages “can be deployed with limited user privileges if a previous version of the Installer Service is running“, it has been found that a default install of Pulse Secure client allows to run the installers. The installers are available at “https://<pcs-host>/dana-admin/sysinfo/installers.cgi “.

Since these installers need to perform tasks requiring administrative right (such as creating files into the “Program Files (x86)” directory), we have decided to investigate how the corresponding non privileged processes are allowed to perform privileged tasks.

The installers are self-extracting executables (see Figure 2).

Figure 2: the extracted content of the “Pulse Secure Installer Service (.exe)” package.

Pulse Secure Installer Service (.exe)” works in the following way:

  1. Extracts its content to %TEMP%.
  1. Instructs “PulseSecureService.exe“, which runs as SYSTEM, to initiate the install process. This is done via a OLE interface exposed by the service.
  1. PulseSecureService.exe” verifies the signature of “VerifyAndInstall.exe” using the “CryptQueryObject()” WinAPI function.
  1. If the signature is valid, “PulseSecureService.exe” copies “VerifyAndInstall.exe” to “C:\Windows\Temp\PulseXXXXXXXX\“, where “XXXXXXXX” is a hex-encoded timestamp.
  1. PulseSecureService.exe” runs “VerifyAndInstall.exe“.
  1. VerifyAndInstall.exe” runs a verification routine on “%TEMP%\PulseSecureInstallerService.msi
  1. If the verification succeds, “PulseSecureInstallerService.msi” is copied to “C:\ProgramData\Pulse Secure\Installers\verified_PulseSecureInstallerService.msi“.
  2. PulseSecureInstallerService.msi” runs “C:\Windows\system32\msiexec.exe” as SYSTEM with “C:\ProgramData\Pulse Secure\Installers\verified_PulseSecureInstallerService.msi” as an argument and the installation starts.

The installation process can be observed using “Procmon” with the file names above as filters.

C:\ProgramData” is writable by non privileged users, that can create or modify files they own but not those created by other users.

In order to reproduce the issue and run code as SYSTEM, it is necessary to:

  1. Create an empty “C:\ProgramData\Pulse Secure\Installers\verified_PulseSecureInstallerService.msi
  1. Set an exclusive opportunistic lock on “C:\Windows\System32\msiexec.exe” (for example using this tool: with the command “SetOpLock.exe C:\Windows\System32\msiexec.exe x“).
  1. Start the legit installer downloaded from the “Pulse Secure Connect” appliance.
  1. When the oplock is triggered, swap “C:\ProgramData\Pulse Secure\Installers\verified_PulseSecureInstallerService.msi” with a malicious “.msi” file.
  1. Release the oplock.

As a result, the malicious “.msi” file is executed with SYSTEM privileges.

Detection guidance

In order to detect this issue, it is sufficient to look for a non-SYSTEM process creating or writing to “C:\ProgramData\Pulse Secure\Installers\“. As the original files are always created and written to by the PulseSecure service, non-privileged writes to this location are always non-standard behavior and a possible exploitation attempt.

Different installers install to different locations. Another file path to watch for non privileged writes is “C:\ Users\<user>\AppData\Roaming\Pulse Secure“.


We have developed two different exploits for this vulnerability. See one of them in action below.

However, we are not going to release the code immediately, but it will be published in our github soon. Why not now? Well, we have realized that is very difficult in practice, for Pulse Secure customers, to understand when the release of a new version of the VPN client provides a security bug fix or just a feature update. In fact, in the moment we write, both the release notes of the VPN client version 9.1R6 (the only one not affected) and the Security Advisories published in the PulseSecure website contain no mention to the fact that the previous versions of the product were affected by CVE-2020-13162.

The natural consequence of this reasoning is that there are very high chances that nobody has really updated the client with the latest version available because nobody is really aware of the fact that it provides a bug fix and not a feature update.

Update: 24 hours after we disclosed this vulnerability, Pulse Secure has released a security advisory related to it.

That’s all for today. Remember to follow us on twitter and while you are there connect to @gsepcali. More vulnerabilities and Red Team stories are coming…stay tuned!

Disclosure timeline

Vulnerability discovered: April 13th, 2020
Vendor contacted: April 15th, 2020
Vendor’s reply: April 17th, 2020
Patch released: May 22nd, 2020
Red Timmy Disclosure: June 16th, 2020
Security Advisory released by Pulse Secure: June 17th, 2020

Exploit release: date to be confirmed

Privilege Escalation via HP xglance using perf-exploiter

In one of our recent penetration tests we have abused a vulnerability affecting a suid binary called “xglance-bin“. Part of HP Performance Monitoring solution, it allowed us to escalate our local unprivileged sessions on some Linux RHEL 7.x/8.x systems to root. To be very honest, it was not the first time we leveraged that specific vulnerability as we abused it frequently on many HP servers with RHEL installed since 2014.

There has been indeed a CVE registered for the flaw (CVE-2014-2630) originally discovered by Tim Brown from Portcullis. However the description for it was a bit criptic (aka completely useless) -> “Unspecified vulnerability in HP Operations Agent 11.00, when Glance is used, allows local users to gain privileges via unknown vectors“. Unspecified vulnerability? Unknown vector? Well… up to today, there is no trace in the internet of a public exploit. Hence the idea to release our code.

Short description

Linux applications use shared libraries (.so extension) which are a bit like DLLs in Windows applications. An ELF binary needs to know where these .so libraries are stored, so it could load them when it is being executed.

There are several methods for specifying the location of dynamic libraries:

  1. Using “rpath” or “--rpath-link” options when compiling the application.
  2. Using the environment variable LD_RUN_PATH.
  3. Using the environment variable LD_LIBRARY_PATH.
  4. Using the value of DT_RUNPATH or DT_PATH, set with “rpath” option.
  5. Putting libraries into default /lib and /usr/lib directories.
  6. Specifying a directory containing libraries in /etc/

The objective of an attacker would be to control one of methods above in order to replace an existing dynamic library by a malicious one. This is the context of the vulnerability we exploited. Specifically we took advantage of case 1.

$ objdump -x xglance-bin | grep RPATH
RPATH -L/lib64:/usr/lib64:/usr/X11R6/lib64:/opt/perf/lib64

Indeed, as the “objdump” output clearly showed, the RPATH method was used to specify the location of dynamic libraries for the binary. Unfortunately one of those folders is pointing to a relative path. We can simply create the directory “-L/lib64”, put inside there a malicious library named as one of those xglance-bin loads…

$ ldd /opt/perf/bin/xglance-bin
[...] => -L/lib64/ (0x00007f0fb2b92000) => -L/lib64/ (0x00007f0fb2990000)

…and then launch the binary “/opt/perf/bin/xglance-bin” to escalate to root. The code can be downloaded from github and it is quite self-explanatory.  Just make the bash script executable, run it and it will perform all the exploitation steps for you. It needs the presence of a compiler in the target machine. Alternatively the library can be compiled in a compatible local system and then copied manually to the remote one.

Probably one word should be spent about symbols declared in the code itself that make it very big. This was due to some libraries that “xglance-bin” was trying to load but that were missing in the system we exploited. Instead of copying the absent libraries we just declared all the missing symbols in our code (nm, grep and cut are always your friends). Your environment could be different and not require that.