By My Apostolos Giannakidis, Security Architect, Waratek
Reducing the Insecure Deserialization Risk
Serializing and deserializing data is a common operation in many web application, mainly due to the speed and ease with which data can be moved between applications. However, what was thought to be an efficient process has turned into a vulnerability nightmare over the last few years, mainly for Java applications, but .NET, PHP, and Ruby have also seen headlines from insecure deserialization attacks. The deserialization problem occurs when applications deserialize data from untrusted sources and are one of the most widespread security vulnerabilities to occur over the last couple of years.
A brief background
Serialization, or marshaling, is the process of converting a memory object into a stream of bytes in order to store it into the filesystem or transfer it to another remote system. Deserialization, also known as unmarshalling, is the reverse process that converts the serialized stream of bytes back to an object in the memory of the machine. All main programming languages provide facilities to perform native serialization and deserialization and most of them are inherently unsafe.
The attack mechanism can be summarized in the following steps:
- A vulnerable application accepts user-supplied serialized objects.
- An attacker creates malicious code, serializes it into a stream of bytes and sends it to the application.
- The vulnerable application reads the received stream of bytes and tries to construct the object. This operation is called “deserialization”.
- During deserialization, the malicious code is executed, resulting in a compromised system.
What is the impact of such a system compromise?
Depending on the payload, a deserialization attack could perform Remote Code Injection, Remote Command Execution, Denial of Service, etc. In most cases, the exploit is possible without any authentication. Finally, note that an attack on a server like WebLogic could impact all its running web applications. For these reasons, Java deserialization vulnerabilities are considered to be critical vulnerabilities with a CVSS score from 7.5 up to 10, depending on the environment.
Variations of Java Deserialization attacks
At this point, it is important to introduce three variations of the Java deserialization attacks in order to better understand the impact of these attacks.
- Blind deserialization attacks that aim to extract data from the target system in environments where the system is behind a network firewall that blocks outgoing connections or when strict Security Manager policies are in place.
- Asynchronous (or stored) deserialization attacks that store the malicious code in a database or a message queue. The malicious code will be executed when the target system reads data from the database or the message queue and deserializes them.
- Deferred-execution deserialization attacks that do not execute the malicious code during deserialization, but rather after deserialization has completed. This is usually achieved via the finalize() method during garbage-collection.
What is the proper fix?
Is there a solution that solves the problem and stops all of the various types of deserialization attacks? According to CERT “Developers need to re-architect their applications.” Obviously, such a fix requires significant code changes, time, effort and money to achieve this. If changing the source code and the architecture of the application is an option then this is the preferred approach. However, bear in mind that even if an application does not perform any deserialization in its own components, most servers, frameworks and third-party components do. So, it is extremely difficult to be 100% certain that the whole stack does not and will never perform deserialization without breaking existing required functionality.
Especially for enterprise production environments with hundreds of deployed instances, making any source code changes is often not feasible to implement. Typically, for enterprise production environments, any security solution that requires code changes and more than a few minutes of deployment time is not acceptable, especially for critical vulnerabilities such as the deserialization vulnerability. Enterprise solutions need accurate protection, fast and without requiring source code changes.
CERT alternatively suggests that blocking the network port using a firewall might solve the problem in some cases. However, in most cases, this is not applicable. For example, the deserialization exploits in JBoss, WebLogic, WebSphere, etc run on the HTTP port of the webserver. Which means that blocking that port will render the server useless. Also, such a solution cannot protect against blind deserialization attacks. Therefore, blocking the network port is not a viable option.
How are vendors addressing the issue?
Without going into much detail of every affected software, the following list shows how some vendors handled the issue:
|Spring||Hardened the dangerous classes|
|Apache BatchEE||Blacklist + Whitelist|
|Apache JCS||Blacklist + Whitelist|
|Apache OpenJPA||Blacklist + Whitelist|
|Apache OWB||Blacklist + Whitelist|
|Apache TomEE||Blacklist + Whitelist|
|Atlassian Bamboo||Disabled deserialization|
|Jenkins||Disabled deserialization + upgraded ACC|
Also note that there were even cases where the vendors refused to create a fix for the issue either because they do not acknowledge the problem as their own problem or the affected system is an old version that is no longer supported.
Why blacklisting and whitelisting are bad solutions to the problem
Any security solution that depends on the blacklisting of dangerous classes requires profiling of the application in order to verify that these classes are not utilized by the application. Without first profiling the application, it is not possible to blacklist a class because the risk of breaking the functionality of the application is significant. Additionally, adopting a negative security model means that you will never be sure that you have blacklisted everything.
The list of blocked signatures has to be maintained constantly and frequently and by definition, it does not protect any unpublished, zero-day exploits. Any security solution that promotes a blacklisting strategy as a solution to deserialization attacks is doomed to fail since it plays the Whack-a-Mole game. Blacklisting is a poor strategy regardless if it occurs at the application layer, the JVM layer or the network layer.
Whitelisting is a better approach than blacklisting. However, to apply to whitelist, profiling of the application is again required. In this case, the whitelist will be a really big list of classes. Such big lists are difficult to manage, especially for enterprise environments. In addition, every time the application needs to upgrade to a newer release, the profiling needs to be performed again and a new white list needs to be created. This considerably complicates the deployment of new releases in production. This usually leads to whitelists that are not updated and, in turn, produces false positives. Finally, even if an enterprise decides to accept the effort to constantly profile their infrastructure and maintain whitelists, they are still vulnerable.
Another suggested mitigation is to blindly block (or whitelist) process forking and file/network IO. Even though this approach will reduce the impact of a deserialization attack, it does not protect against blind attacks for data exfiltration nor Denial of Service deserialization attacks.
Finally, some researchers suggest that using an ad-hoc Security Manager can help mitigate these attacks. However, the truth is that even though it is a good first mitigation step, it is insufficient because of its many limitations.
- Security Managers are known to be easily bypassed.
- It does not protect deferred attacks where the execution of the payload is executed after deserialization, for example via the finalize() method.
- Most DoS deserialization attacks cannot be mitigated by the Security Manager.
- To effectively utilize the Security Manager, another type of white list needs to be created and maintained; thus this approach suffers from the same limitations of the whitelisting.
How can customers with old or legacy versions of affected systems be protected against the Java deserialization attacks?
If the vendors cannot provide patches and the customers cannot make any source code changes, then how can such production systems be protected? The following are the currently available options.
- Web Application Firewalls – WAFs are not helpful here because they have no application context since they can only examine the input and the output of the application. Applying heuristics on the incoming requests is guaranteed to produce false positives and false negatives. Any security solution that has no application context and operates outside of the application cannot adequately mitigate deserialization attacks
- RASP vendors and Java agents that either disable deserialization completely or apply blacklisting / whitelisting on the classes that are getting deserialized.
It’s unlikely that we’ve seen the last of hackers using insecure deserialization to target enterprise systems. With the ubiquity of Java and other languages that rely on serialization for communication, it’s a good time to put safeguards in place to protect critical applications.
About the Author
Apostolos Giannakidis, Security Architect, Waratek Apostolos drives the research and the design of the security features of Waratek’s RASP container. Before starting his journey in Waratek in 2014, he worked in Oracle for 2 years focusing on Destructive Testing on the whole technology stack of Oracle and on Security Testing of the Solaris operating system. Apostolos is acknowledged by Oracle for submitting two Java Deserialization vulnerabilities that were fixed in the Oracle January 2019 CPU Apostolos can be reached at Twitter @cyberApostle and at our company website http://www.waratek.com