Java deserialization vulnerabilities were discovered and disclosed in January 2015 by Gabriel Lawrence and Chris Frohoff. These serious vulnerabilities arise from the way in which Java deserializes serialized objects (see the presentation of Gabriel Lawrence and Chris Frohoff). The underlying flaw in Java has not been fixed by Oracle, most likely due to the impact a fix would have on various frameworks and libraries. However, many workarounds can be applied to prevent exploitation.
The original disclosure of the vulnerability did not attract much attention. Until November 2016, when Stephen Breen, a researcher at Foxglove Security, demonstrated practical exploitation on the most popular Java application servers (see the article published on Foxglove Security blog).
In this article, we will not focus on how serialization vulnerabilities work and how to fix them, because there already are plenty of articles on this subject. Instead, today we will focus on how to reliably detect and exploit these issues. For this task, all we need to know is that the vulnerability depends on how Java deserializes serialized objects. Default Java classes responsible for the deserialization task first deserialize each serialized object and then try to cast the object to the expected Java class. So, all the received objects are deserialized, even if they are not instances of the expected types; in this case, after deserialization an exception arises when trying to cast the object to the expected type. What makes the issue so critical is the fact that the Java language offers the possibility to add custom code to the class definition that is executed upon deserialization.
For this reason, to be able to achieve Remote Command Execution (RCE) it is necessary to find a “chain” to an object that, once deserialized, allows the attacker to execute arbitrary Java code. Obviously, the class of the chosen object must be loaded in the ClassLoader of the target system. For this reason, usually some “vulnerable” libraries are needed to exploit this issue. These libraries expose the objects used for the exploitation, but the vulnerability itself lies in how Java deserializes the objects, and not in the libraries used for the exploitation. Removing only the “vulnerable” libraries does not protect completely against this issue, because new chains could be discovered and the vulnerability could be triggered anyway.
Once a deserialization issue is discovered, the ysoserial tool can be used for exploitation. This tool generates custom exploitation vectors, based on the “vulnerable” libraries loaded in the target system. In this article we will analyze how to discover and exploit Java deserialization vulnerabilities using a Burp Suite plugin we developed based on ysoserial: the Java Deserialization Scanner.
The Java Deserialization Scanner plugin can be installed in two ways:
- Download it directly in Burp Suite from the BApp Store (Extender -> BApp Store). This is the easiest way to get the plugin, but the downloaded version may not be the latest one. At the moment, for example, the latest version (0.5 pre-release) is available only from GitHub (see next method). When the release version will be published, we will submit it to the BApp Store.
- Download the latest release from GitHub and manually install the JAR from the Burp Suite Extender tab (Extender -> Extensions -> Add)
The detection of deserialization vulnerabilities is not always a simple task. By generating a payload with ysoserial and sending it to the target application, usually we may either get a Java Stack Trace (and if we are lucky we can discover the presence of the issue, but only with a knowledge of the vulnerable library targeted) or no verbose output at all.
Therefore, in order to reliably detect the presence of the vulnerability, we modified ysoserial to generate Java native sleep payloads instead of RCE payloads and we added these payloads to the Java Deserialization Scanner. For this task it is necessary to use Java native sleep payloads, because the Java sleep call is synchronous; executing a system sleep using the default RCE payloads generated by ysoserial would be useless, because they are asynchronous and we would get the response from the server before the end of the sleep command, regardless of the presence or the absence of the issue.
In the latest version of the plugin, we added two new methods to further improve detection: one based on DNS and one on CPU.
In order to generate payloads that execute native Java DNS resolution, we modified ysoserial again. Usually, DNS resolution requests are the ones that are most likely to bypass corporate firewalls and consequently are a quite good detection method. In general, the timing method is more reliable and preferable, but the DNS method can be useful on unstable systems or highly delayed networks. Thanks to Burp Suite Collaborator, it is not necessary to have authority on a DNS zone, and everything can be done within the Burp Suite tool.
The CPU detection method is based on Wouter Coekaerts’ SerialDOS work: it is able to detect deserialization issues without the presence of any vulnerable library. The payload is based on a system object (java.util.HashSet) that employs many CPU cycles for the deserialization task. SerialDOS was created as a PoC of a Denial of Service (DoS) attack, but by decreasing the CPU cycles necessary for deserialization it can also be used as a detection method. This payload is very useful to detect if the application endpoint actually performs Java deserialization and if it implements a strict whitelist approach. If this check gives a positive result there is also the possibility that the target application implements a whitelist approach that permits HashSet class of java.util package. In this case the application is still vulnerable to DoS attacks (using full-power SerialDOS payloads).
Now, let’s demonstrate how to use our plugin for detection. The detection is integrated in Burp Suite Active and Passive Scanner. By default, Time and DNS checks are added to Burp Suite scanner, but they can be disabled from the Configurations panel of the plugin, in the section “Automatic scanner configurations”:
In order to reduce the number of requests executed by the Active Scanner, the checks added by the plugin are executed only if a serialized object is present in the original request. The payload is encoded with the same encoding found in the original request (for instance, if the serialized object is encoded in BASE64, the exploit vector will be encoded in BASE64 and so on). The currently supported encoding formats are:
- ASCII HEX
- BASE64 GZIP
The CPU detection method is not included by default in the active scan checks, because it must be used with caution: sending a huge number of “light” SerialDOS payloads may still cause problems on old or highly-loaded systems. In order to execute checks with custom insertion points or use the CPU payload, the plugin provides the “Manual Testing” tab, in which the user can select the insertion point (currently only one at a time is supported) like in the Burp Suite Intruder, choose the check type (DNS, Time, or CPU), choose the preferred encoding and test the parameter. By selecting Sleep or DNS checks, the plugin tests all the supported vulnerable libraries, while with the CPU check the plugin will use a library-independent CPU payload. By default, detected issues are automatically added to the global issues of the host, but this behavior can be disabled in the “Configurations” tab. In the same tab it is possible to enable verbose mode, in order to inspect the requests and their responses in the results pane.
The requests to test can be manually inserted in the Manual Testing tab or can be sent from other Burp Suite tabs using the contextual menu that opens with the right button of the mouse:
The configuration of the Manual Testing tool is explained in the following picture:
The “Exploiting” tab offers a comfortable interface to exploit deserialization vulnerabilities. This tab uses the ysoserial tool to generate exploitation vectors and includes the generated payload in a HTTP request. ysoserial takes as argument a vulnerable library and a command and generates a serialized object in binary form that can be sent to the vulnerable application to execute the command on the target system (obviously if the target application is vulnerable). The Exploiting tab supports the same encoding formats as the detection sections of the plugin.
Now, let’s demonstrate how to use our plugin for exploitation. First, we need to open the “Configuration” tab and insert the path where we have a copy of the ysoserial tool (ysoserial is necessary only for exploitation; detection payloads are already included in the plugin):
Then, as we saw for manual testing, it is possible to insert the request manually or to send it from other Burp Suite tabs using the contextual menu that opens with the right button of the mouse. The user can then select the insertion point (currently only one at a time is supported) like in the Burp Suite Intruder, insert the ysoserial command (refer to the ysoserial manual for syntax) and click the correct “Attack” button, based on the desired encoding. The configuration of the “Exploiting” tool is explained in the following picture:
The interface provided by the plugin makes the exploitation process faster and more comfortable.
And that’s all! The last version of the plugin (currently the 0.5 pre-release) can be downloaded from the release page of GitHub. If you find any bug or if you have ideas for enhancements please open a new issue on GitHub.
Thank you and happy testing!