During my research into the Java Remote Method Invocation (RMI) protocol, the most common RMI service that I came across was Adobe ColdFusion’s Flex integration service which is used to support integration between Flash applications and ColdFusion components. A quick look at this service led to the discovery of two Java deserialization vulnerabilities, both leading to unauthenticated RCE in a service that runs under the local SYSTEM account by default.

Adobe released a security update on the 12th September 2017 for ColdFusion 11 and ColdFusion 2016 which can be installed through the ColdFusion Administrator application, however this update alone is not sufficient. Adobe ColdFusion comes bundled with its own Java runtime environment (JRE), which must be manually updated for the update to be effective.

The end-of-life ColdFusion 9 is also known to be affected, however no supported fix was available at the time of writing.

Update (13/10/2017): To clarify, this vulnerability affects the Java RMI service and does not affect HTTP(S) services exposed by ColdFusion.

Update (19/03/2018): It seems I made a typo in the blog title, this post is about CVE-2017-11283 and CVE-2017-11284 not 11238!

Update (18/06/2018): Adobe’s security update didn’t fully resolve this issue, more details can be found on my post about CVE-2018-4939.

The Vulnerability: RMI and java.lang.Object

The first thing I did when I started researching RMI was to write some code to enumerate RMI endpoints (which eventually became BaRMIe). The goal was to identify software that used RMI which I could investigate further.

I used Shodan to find targets for enumeration, then enumerated those targets using BaRMIe. The following class was the most commonly exposed:

coldfusion.flex.rmi.DataServicesCFProxy 1 coldfusion . flex . rmi . DataServicesCFProxy

The problem with RMI services is that we can’t interact with them without access to the relevant Java interface or stub class, so I downloaded a trial version of Adobe ColdFusion 2016 and installed it in a virtual machine. With ColdFusion installed I did a recursive grep over the installation directory for the above class name “DataServicesCFProxy” which guided me to the file “lib/cfusion.jar”. I opened this file up in JD-GUI to find the class (interface) listed above.

package coldfusion.flex.rmi; import java.rmi.Remote; import java.rmi.RemoteException; import java.util.List; import java.util.Map; public abstract interface DataServicesCFProxy extends Remote { public abstract List fill(String paramString, Object[] paramArrayOfObject, Map paramMap) throws RemoteException; public abstract List sync(String paramString, List paramList, Map paramMap) throws RemoteException; public abstract Object get(String paramString, Map paramMap1, Map paramMap2) throws RemoteException; public abstract Integer count(String paramString, Object[] paramArrayOfObject, Map paramMap) throws RemoteException; public abstract boolean fillContains(String paramString, Object[] paramArrayOfObject, Object paramObject, Boolean paramBoolean, Map paramMap) throws RemoteException; } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 package coldfusion . flex . rmi ; import java . rmi . Remote ; import java . rmi . RemoteException ; import java . util . List ; import java . util . Map ; public abstract interface DataServicesCFProxy extends Remote { public abstract List fill ( String paramString , Object [ ] paramArrayOfObject , Map paramMap ) throws RemoteException ; public abstract List sync ( String paramString , List paramList , Map paramMap ) throws RemoteException ; public abstract Object get ( String paramString , Map paramMap1 , Map paramMap2 ) throws RemoteException ; public abstract Integer count ( String paramString , Object [ ] paramArrayOfObject , Map paramMap ) throws RemoteException ; public abstract boolean fillContains ( String paramString , Object [ ] paramArrayOfObject , Object paramObject , Boolean paramBoolean , Map paramMap ) throws RemoteException ; }

Each of the five methods of this interface accept arbitrary Java objects as parameters either directly or indirectly (List and Map can both contain arbitrary Java objects). The RMI protocol uses Java serialization for method parameters so each of these five methods can be used as an entry point for a Java deserialization attack by passing a specially crafted object to the method.

The Payload

For a complete Java deserialization exploit we need two key components – the entry point (detailed above) and a payload. The payload consists of one or more classes with properties configured in such a way that some useful code is executed when the object is deserialized. For those not familiar with Java deserialization attacks, there’s an awesome tool called ysoserial which generates Java deserialization payloads using classes found in common Java libraries. Unfortunately the version of ColdFusion I had installed was not affected by any of the ysoserial payloads, and in fact Adobe released a security update in May 2016 which updated the bundled Apache Commons Collections library from version 3.2.1 to version 3.2.2, protecting ColdFusion against what is probably the best known Java deserialization payload.

On further investigation I came across the file “libs/js.jar”, which is the Mozilla Rhino JavaScript library. There is a deserialization payload for this library available in ysoserial but it didn’t affect my lab environment. I also couldn’t find any information indicating that a deserialization issue had been fixed in this library (whereas details of the Apache Commons Collections vulnerability were published). Using Wireshark to look at the network traffic I spotted the following:

A “java.io.InvalidClassException” stating that the local class was incompatible and listing the “serialVersionUID” of both the local and remote classes. Helpful! The serialVersionUID field of a class is usually generated automatically by Java and is updated whenever certain “incompatible” changes are made to the class. Depending on usage, however, it is entirely possible for these changes to be made without introducing an incompatibility.

I fired up a hex editor, loaded up the Mozilla Rhino payload bytes that I had generated using ysoserial, and searched for the local serialVersionUID listed in the exception. I modified the value to match the remote serialVersionUID and fired the payload off again whilst monitoring the network traffic with Wireshark. I had to repeat this process several times to fix all of the serialVersionUID values, but eventually I got this:

Outdated JRE

The other of the two vulnerabilities is simply that ColdFusion comes bundled with an outdated version of Java. The bundled Java version does not attempt to validate the type of objects received in an RMI Registry.bind() request before deserializing them. It also fails to check that the bind request came from localhost prior to deserializing the object. This presents another entry point for Java deserialization attacks.

References