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: https://github.com/googleprojectzero/symboliclink-testing-tools/tree/master/SetOpLock 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

Richsploit: One tool to exploit all versions of RichFaces ever released

We are proud to release Richsploit, a tool we wrote to exploit multiple versions of RichFaces. This infamous Java library is included with many JSF web applications for providing advanced UI elements beyond the (very limited) set that is built-in with the framework. Therefore, many websites using JSF are vulnerable to exploitation.

How to detect RichFaces

When a website is using RichFaces, it will load resources from specific URLs which you can see when you monitor outgoing requests with tools like Burp or within the browser’s development tools.

  • Richfaces 3.x: http://example.com/app_name/a4j/g/..
  • Richfaces 4.x: http://example.com/app_name/rfRes/org.richfaces…

Tools like Wappalyzer can be used as well.

Vulnerable versions

All versions of RichFaces released since September 2007 (>= 3.1.0) are vulnerable to at least one exploit. See below an overview of which version is vulnerable to which exploit:

RichFaces 3
3.1.0 ≤ 3.3.3 CVE-2013-2165
3.1.0 ≤ 3.3.4 CVE-2018-12533
3.1.0 ≤ 3.3.4 CVE-2018-14667
RichFaces 4
4.0.0 ≤ 4.3.2 CVE-2013-2165
4.0.0 ≤ 4.5.4 CVE-2015-0279
4.5.3 ≤ 4.5.17 CVE-2018-12532


What follows is a brief overview of how each vulnerability works and can be exploited. For more background information, I will refer to some external articles which describe the technicalities in more details.


This vulnerability was the first one identified on RichFaces, and affects both version 3.x and 4.x. It’s a classic deserialization vulnerability, which allows deserialization of arbitrary Java serialized object streams. To exploit it, the application has to be linked with vulnerable libraries in the classpath, to be able to build a gadget chain.

Because there is no lookahead implemented, every class on the classpath is a potential candidate. One example would be the Apache Commons class, which is often linked with JSF applications.

You can prepare a payload with a tool like ysoserial, save it to a file, and fetch it to Richsploit via the “-p” parameter.

More information: https://codewhitesec.blogspot.com/2018/05/poor-richfaces.html


This second vulnerability is harder to exploit, but potentially more rewarding. It’s an EL injection vulnerability, that can lead to remote code execution. The idea is to send a proper serialized object this time, but inside the object we put malicious EL code.

EL stands for Expression Language, which is a limited form of Java, used to attach small pieces of logic to UI listeners (e.g. clicking a button would invoke a function call). Even though the capabilities are very limited, we can use a series of tricks to achieve remote code execution.

Richsploit will inject the following EL string when executed: #{"".getClass().forName("java.lang.ProcessBuilder").getConstructors()[1].newInstance("/bin/sh~-c~"+COMMAND+".split("~")).start()}

Let’s take a step-by-step look at how this works.

Expression Language restricts us to a one liner, and we can only start with a variable which is in EL scope:

  • Lambda parameters
  • Literals
  • Managed beans
  • Implicit objects
  • Variables defined in the xhtml

In our example, we start with an empty string, which is a literal

Now we need a way to transfer from a String class to a ProcessBuilder class. We do that by first transforming to the generic Class<> type. Class is an object in Java that represents a Java class. It has methods like getConstructor(), getMethod(), etc.

From there we transform our object to a ProcessBuilder type, using the forName() function from Class. We use ProcessBuilder instead of the more famous Runtime, because

  • ProcessBuilder allows to set the command via the constructor
  • Runtime needs a call to Runtime.getRuntime() but static calls are not allowed in EL (yet another restriction)

To use this class, we have to instantiate it. The getConstructors() function returns an array of all constructors of the class. Unfortunately the order of them appearing in the array changes each time the application is launched. Therefore, this method could require some trial and error, until it is at index 1.

Luckily, ProcessBuilder only has two constructors, so we have a 50% chance of success.

Java doesn’t allow you to create a static array, so we use the split function to transform the String to a String[].

Finally, the start() function is required by ProcessBuilder to invoke execution.

More information: https://issues.redhat.com/browse/RF-13977


This vulnerability is a response on the fix of the previous one (CVE-2015-0279). As the patch to CVE-2015-0279 (introduced in 4.5.4) disallowed the use of parenthesis in the EL method expression of the contentProducer, it seemed like a dead end.

But if you are fimilar with EL internals, you would know that they can have custom function mappers and variable mappers, which are used by the ELResolver to resolve functions (i. e., name in ${prefix:name()}) and variables (i. e., var in ${var.property}) to Method and ValueExpression instances respectively. Fortunately, various VariableMapper implementations were added to the whitelist (since version 4.5.3).

So to exploit this, all that is needed is to use a variable in the contentProducer method expression like ${dummy.toString} and add an appropriate VariableMapper to the method expression that maps dummy to a ValueExpression, containing the EL we want to inject (same as with CVE-2015-0279).


This CVE is similar to the CVE-2015-0279, but it uses a different class. Instead of org.resource.MediaResourceOutput, it is using org.richfaces.renderkit.html.Paint2DResource$ImageData.

The trick is that ImageData extends org.ajax4jsf.resource.SerializableResource, which is in the whitelist that was introduced in 3.3.4 to fix the Java deserialization vulnerability (CVE-2013-2165).

More information: https://codewhitesec.blogspot.com/2018/05/poor-richfaces.html


This final CVE is the most elaborate one and requires some extra detailed explanation because there are no other write-ups available on the internet except this slideshare.

It’s again an EL injection, similar to CVE-2015-0279. The general idea is as follows:

  1. Visit a page that contains <a4j:mediaOutput> tag. This will register UserResource for the session
  2. Prepare serialized payload, containing the EL injection string
  3. Visit UserResource URL and attach encoded serialized payload object in URL after /DATA/
  4. The UserResource class will be instantiated with data from the payload, leading to EL execution

To see this in more detail, this is the call chain from step 3:


When this URL is provided, the filter defined in web.xml sends it to BaseFilter, which will send it to:

The getResourceDataForKey() function reads the /DATA/ object and returns it as Java Object.
Object resourceDataForKey = getResourceBuilder().getResourceDataForKey(resourceKey);

It is then saved in resourceContext

The ResourceLifeCycle.send() method is called, which will call sendResource()
getLifecycle().send(resourceContext, resource);

Here, the send() method is called DIRECTLY ON THE RESOURCE. So this roughly translates to UserResource.send(context_containing_el)

This is the send function of the vulnerable class UserResource.java of which I provide the code here:

 public void send(ResourceContext context) throws IOException {
   UriData data = (UriData) restoreData(context);
   FacesContext facesContext = FacesContext.getCurrentInstance();
   if (null != data && null != facesContext ) {
     // Send headers
     ELContext elContext = facesContext.getELContext();
     // Send content
     OutputStream out = context.getOutputStream();
     MethodExpression send = (MethodExpression)       
     send.invoke(elContext,new Object[]{out,data.value});

The send.invoke() will execute the EL coming from the context.
So the only way to reach this vulnerable method is by supplying UserResource as the resource in the URL, otherwise resource.send() will never lead to the send() method of UserResource.

Now for the payload, the object we supply is in the ‘context’ variable. It will need to survive:

  • restoreData(context)
  • A cast to UriData
  • A dereference to .createContent, which has to contain a MethodExpression

This means the gadget chain looks as follows:

exp: "${Expression Language}"

See the source code of Richsploit for how this particular serialized object is created. Some tricks with reflection are required because UriData has private fields, and there would have been no way to set the value of createContent directly.


Richsploit can be found on our GitHub page. And remember to join us at Blackhat Las Vegas this year with our Practical Web Application Hacking Advanced Course on 1-2 August and 3-4 August!

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/ld.so.conf.

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
libnums.so => -L/lib64/libnums.so (0x00007f0fb2b92000)
libXm.so.3 => -L/lib64/libXm.so.3 (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.

OAMBuster – Multithreaded exploit for CVE-2018-2879

Oracle OAM is a widely used component that handles authentication for many web applications. Any request to a protected resource on the web application redirects to OAM, acting as middleware to perform user authentication.

Last year, a vulnerability was found in the login process which contains a serious cryptographic flaw. It can be exploited to:

  • Steal a session token
  • Create a session token for any user

Basically it allows to login to the website and impersonate any user. Bad stuff.

Technical Details

During login, Oracle OAM will send a value called encquery as part of the URL. This parameter contains some values like a salt and a timestamp, and is encrypted with AES-CBC. However:

  • There is no HMAC attached, to verify that the encrypted string wasn’t tampered with
  • The website responds with an error message when there is a padding error during decryption

This makes it vulnerable to a classic Padding Oracle Attack.

However, there is one extra challenge: We can not just add blocks of data to the end of the string because the decrypted value contains a validation hash at the end. When adding a block (that turns into gibberish when decrypted), the hash won’t be valid and we will not be able to use the oracle – it simply will always provide an error.

The fix to this problem is simple: we first have to search for the character that turns into a space (0x20) when decrypted. Now the hash will be untouched, and the gibberish we place behind it is interpreted as a new value.

For more in depth information, please read these excellent blog posts by SEC Consult:


There have been exploits in the wild for some time, but they are single threaded. Because this attack requires to guess byte values one by one, it can take about 4 hours to complete (without rate limiting).

With RedTimmy, we have developed a multithreaded version of the exploit called OAMBuster. Source code is available on GitHub.

OAMBuster is able to perform the following actions:

  • Verify if the target is vulnerable to the attack (<30 seconds)
  • Decrypt the encquery string, using POA
  • Decrypt any given string, using POA
  • Encrypt any given string, using POA

The final two functions can be used for example to decrypt the OAMAuthnCookie containing the session token, and then re-encrypt it.

Benefits of the multithreaded implementation

Because OAMBuster has multiple threads running, it can decrypt multiple blocks at the same time. So for example, when there are 16 blocks in total, the tool can run 16 threads on the last byte of each block. When a thread is finished, it continues to work on the second-to-last byte of the block, and so forth, working from back to front. Bytes within a block can not be parallelized, as they are dependent on each other.

Worthless to say, you can subscribe our blackhat course if you want to play with it more: