Case Study – New way to Exploit Java Deserialization Vulnerability
In this case study, we will not focus on how serialization vulnerabilities and how they work because there are plenty of articles on this subject. Instead, 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)
Serialization is the process of converting a complex object into a representation that can more easily be transmitted.
- To transfer over a network or write to a persistent store
- AKA “marshalling” or “pickling”
Deserialization is the process of recreating the object from that representation.
- As when receiving data over a network
- AKA “unmarshalling” or “unpickling”
Several Java technologies are layered over serialization:
- Remote Method Invocation (RMI)
- Java Management Extensions (JMX)
PoC: Serialization Process
Web Application often contains multiple components & libraries each component may operate in one or more trusted domains.
- Details of trusted domains driven by architecture, security policy, required resources, functionality, etc.
- Component A can access file system, but lacks any network access.
- Component B has general network access, but lacks access to the file system and the secure network.
- Component C can access a secure network, but lacks access to the file system and the general network.
Deserialization of Untrusted Data
In Java, reading a Data object from a serialized stream is as simple as:
ObjectInputStream in = new ObjectInputStream( inputStream );
The problem is that there’s no way to know what object Deserializing before it gets decoded. So an attacker can serialize a bunch of malicious objects and send them to web application. Hence, the call of readObject (), it gets too late. The attacker’s malicious objects have already been instantiated, and have taken over entire server.
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:
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 pro 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 desearlization 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:
PoC: Menu for exploitation
The configuration of the Manual Testing tool is explained in the following PoC:
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 the 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):
PoC: Configuration Tab
Step: 1 – 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 PoC:
PoC: Steps to Perform Manual Exploitation
Step: 2 – As shown in above PoC, we have used burp collaborator to check whether it is exploitable with the help of ping command. Burp Suite Collaborator is an external server added to Burp Suite in order to discover out-of-band vulnerabilities and issues that can be found only from external service interaction. It is a great tool and increases the power of Burp Suite Scanner a lot. However, a simple ping payload that does a DNS query confirmed that the system is indeed vulnerable.
PoC: DNS Query to Burp Collaborator Server
Step: 3 – For further exploitation, we can use windows commands like nslookup to check if any DNS query is received, so that we can confirm the vulnerability as shown in following PoC.
Step: 4 – As we know that, it is vulnerable for serialization attack so that we can craft our payload as harmful as possible and we have clue about that it is using windows server. Hence, we can craft the payload accordingly like we will send the command restart to server. Payload as motioned in the following PoC.
PoC: Restart Command sent to Windows Server
Step: 5 – After the command execution server will get restart and it will show service unavailable error. Our exploitation part will get successful. Attacker can do remote code execution (RCE) by using serialization vulnerability.
PoC: Server gets restart and it will display “Service Unavailable”
Once the vulnerability is confirmed, the PenTester may need to do some trial and error of commands to execute in order to get a shell. Here are a few useful tips getting that working:
- Make sure to test various reverse shell commands (see Reverse Shell Cheat-Sheet)
- Common collection payload may fail on certain JVM (IBM J9 for example). Mathias Kaiser made a payload specifically to support less common JVM: see CommonsCollections6.
- If a security manager is enforced, may need to craft a custom payloads. One prevalent approach is to find the path to the web root directory and write a web shell that could be later executed.
Attack & PenTest Team