Article

Java Deserialization Bug – are you vulnerable?

In this blog I’d like to take a deeper look at the issue of the “Deserialisation of Untrusted Data” which has so far led to many similar vulnerabilities exploited in several applications by combining improper handling of deserialisation along with libraries that allow remote code execution. Such libraries are exploitable even when your application does not directly use them, just as long as they are on the classpath.

The core questions are:

  • How to know whether you are vulnerable to this?
  • If you are, how could you fix your bugs?

How to know whether you are vulnerable to this?

The most comprehensive list of indicators of this vulnerability is by Sijmen Ruwhof but it presents the following limitations:

  1. Search for the hexadecimal string AC ED 00 05 among your network traffic. This would not be enough, because those classes that allow the deserialisation may not be used (therefore may not be mentioned in any HTTP request/response on your network) but may still be on the classpath and therefore exploitable.
  2. Search for the commons-collections*.jar library in your classpath. This would not be enough, because Apache Commons is only the most famous exploitable library but it is not the only one. Examples of other classes that could allow remote code execution when combined with improper deserialisation are: Apache’s InstantiateFactory, InstantiateTransformer and PrototypeFactory; Java’s XMLDecoder; Apache Struts HTTP request parsing, and many others.
  3. Search for everywhere where Java objects are deserialised. This again would not be enough because there are too many places where deserialisation could occur.
  4. Search for calls in the code to readObject(), readExternal() and readResolve(). This again does not consider cases where the application is not directly using deserialisation (while third-party libraries on the classpath do allow it nonetheless).

This gives you an idea of how difficult it is to even determine whether or not you are at risk, in the first place. Especially considering the typical deployment environment of major organisations who often run a complex mixture of JVM versions with applications and libraries coming from several distinct sources.

If you are, how could you fix your bugs?

Of course the short-term remediation strategy is to patch and upgrade wherever possible and whenever a bug is found. However, a long-term remediation is much more difficult to apply and has not been practically deployed yet, within large organisations.

The most recommended long-term mitigation strategies so far are either

  1. Blocking the object serialisation everywhere;
  2. Blacklisting/whitelisting with respect to the deserialisable classes. Even the OWASP page for this class of vulnerabilities recommends open source tools that provide such blacklisting/whitelisting functionality.

However the solutions above are impractical, incomplete and limited. Given the broad amount of classes that could be used to load a serialised object, and given the complex enterprise settings, blocking serialisation everywhere is usually not feasible.

For the same reason, blacklisting would leave out exploitable libraries. Also whitelisting still leaves room for error and often is not easily possible as the code performing the deserialisation is buried in libraries or even the standard library (why whitelisting isn’t enough).

Moreover, when the classes allowing execution are core ones, like the RMI registry, these mitigation approaches would fail, while patching the JRE would be required. Fixing the deserialisation handling itself in the code would often be a very costly effort besides not covering all the code from third parties libraries.

Waratek: A Practical Solution for Large Organisations

The true core of the issue resides in the content of a serialised object. If the content tricks into calling libraries that can be used to execute code, then it should not get through the deserialisation step. Otherwise, the deserialisation should occur normally as to not break the application’s business logic.

The validation of serialised content is difficult in itself: “Need proof? If Joshua Bloch can’t get it right, and the (Oracle/Sun) Secure Coding Guidelines can’t get it right, and key core classes can’t get it right, what chances do the rest of us have?” as Sami Koivu effectively states.

However, this validation is the only solution that would allow not to break applications by blocking a functionality, as it may happen with the blocking/blacklisting/whitelisting -based strategies recommended so far.

100% Java CompatibleWaratek provides a RASP solution that besides allowing you to create any fine-grained whitelist/blacklist on any file, class, method and field, allows to monitor and block reflection-related actions. For achieving remote code execution, an attacker has to be able to load the code that executes the malicious command. This is achievable mainly by reflection and can be made hideous by recursive reflection.

In the particular case affecting the Apache Commons class, the ysoserial payloads rely on a gadget chain whose core consists in loading a method that takes a string and a class and returns a method, thus realising what is called “recursive reflection”. The InvokerTransformer constructor is guilty of accepting this as an argument. As specified above, other classes from other libraries could allow the same and be used in combination with improper deserialisation handling. However, by blocking the core of the recursive reflection, we block a much broader amount of improperly used libraries than by simply whitelisting the good ones or blacklisting the bad ones.

Waratek RASP allows a security administrator to apply a simple rule to prevent this type of recursive reflection. Notably:

  1. This rule is not likely to break any application since such a sequence of recursive reflection is only typical of interpreters, unlike the high majority of the Java applications.
  2. Moreover, the rule has to be applied only once for its effect to span across distinct applications running on distinct versions of the JRE. It doesn’t matter if this is a new or legacy Java application that runs in your data center or on the public or hybrid cloud.
  3. The rule can be applied at run-time, with no need to restart any of your applications and no need for code changes.

If you’d like to find out more, I’d be happy to go through this with you.


Author:

Apostolos Giannakidis drives the research and the design of the security features of Waratek’s RASP container. Before starting his journey in Waratek in 2014, Apostolos 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 has more than 10 years of experience in the software industry and holds an MSc in Computer Science from the University of Birmingham.

Related resources

Ready to scale Security with modern software development?

Work with us to accelerate your adoption of Security-as-Code to deliver application security at scale.