A Java Serialization Vulnerability

Categories: Java

A significant security hole has recently been found in a range of widely-used Java-based applications, allowing (among other things) execution of arbitrary shell-commands on the host system. The basic problem is that:

  1. the applications were deserializing java objects provided by an untrusted client, and
  2. had the apache-commons-collections library in their classpath, and
  3. apache-commons-collections includes a class named InvokerTransformer which does lots of reflection during its readObject method, guided by properties from the input-stream.

The combination is nasty: a manipulated input-stream can cause the commons-collections InvokerTransformer to look up any arbitrary class (specified in the input stream), and invoke any arbitrary static method on that class (specified in the input stream) passing any arbitrary parameter (provided in the input stream). The obvious target is: class=java.lang.Runtime, method=exec(String). Game over.

The problems with deserializing from an untrusted stream are well known (see first reference below for example). The role of step 3 above could be filled by any vulnerable library that is in the classpath - but this commons-collections case is particularly serious as the library is in wide-spread use.

As noted by both Lawrence+Frohoff and FoxGlove, there are several common cases where untrusted Java objects are deserialized, including the standard RMI Registry class and some web-frameworks (eg JSF when encryption of ViewState is not enabled).

Programmers can best avoid introducing this kind of vulnerability by not deserializing objects from untrusted sources. If that isn’t an option then the commonly-recommended generic solution to this kind of problem is for the class initiating the deserializing to build a white-list of all classes that a valid serial-stream may contain. Sadly, for more complicated objects this is a far from trivial thing to determine and maintain. And in this particular case, “org.apache.commons.*” could well be on the “white-list”. I don’t have a better proposal though…

See:

Update: JEP290 (to be included in Java 1.9) defines some hooks into the serialization process that can at least makes “whitelisting classes that can be deserialized” easier to implement.

Update 2016-11-30: It appears that this vulnerability is still being actively exploited, eg to install ransomware on systems belonging to the San Fransisco Railway.