How Java Deserialization Vulnerabilities Enable Remote Code Execution
This article explains Java's reflection mechanism, details how deserialization flaws in libraries like Apache Commons Collections and Fastjson allow attackers to craft malicious objects that trigger arbitrary command execution, and provides practical proof‑of‑concept steps and mitigation recommendations.
Java Reflection Mechanism
In Java, reflection allows determining an object's class, accessing all its fields and methods, and invoking any method on any object at runtime.
Deserialization Vulnerability Overview
Many services expose Java deserialization interfaces (e.g., RMI, web endpoints). An attacker can craft a malicious serialized object that, when deserialized, triggers arbitrary code execution, command execution, or obtains a web shell.
Apache Commons Collections provides the InvokerTransformer class, which can invoke arbitrary methods via reflection. Its widespread use has made it a common gadget chain for Java deserialization attacks.
Key Points Summary
1. Java deserialization can execute remote commands.
2. Commands are typically run with Runtime.getRuntime().exec("whoami").
3. InvokerTransformer in Commons Collections creates a reflection chain.
4. ConstantTransformer returns constant values.
5. ChainedTransformer executes a series of transformers in order.
6. AnnotationInvocationHandler can trigger code execution during readObject().POC Idea
The proof‑of‑concept builds a Map containing a ChainedTransformer that executes code, wraps it in a TransformedMap, and serializes an AnnotationInvocationHandler. When the object is deserialized, the readObject() method triggers the chain and runs the command.
Execution flow:
TransformedMap → AnnotationInvocationHandler.readObject() → setValue() → command execution.
Fastjson ≤ 1.2.24 Exploit
Fastjson can deserialize the class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl, which contains a _bytecodes field. When this field is populated with base64‑encoded bytecode, the class is instantiated and its constructor runs, achieving code execution.
Key steps:
Pass a crafted JSON object to JSON.parseObject(data, Feature.SupportNonPublicField) with the SupportNonPublicField flag enabled.
The parser eventually reaches DefaultJSONParser, then JavaBeanDeserializer, and finally FieldDeserializer.setValue, which invokes reflection.
The reflected call reaches TemplatesImpl.getOutputProperties(), leading to newTransformer(), getTransletInstance(), and the decoding of _bytecodes into a class that executes the payload.
Overall Recommendations
Deserialization is commonly used in template loading, network communication, data storage, logging, and database persistence. During security reviews, focus on these areas and locate deserialization entry points such as ObjectInputStream.readObject, XMLDecoder.read, ObjectYaml.load, XStream.from, XMLObjectMapper.read, and ValueJSON.parseObject. Verify whether dangerous libraries like Apache Commons Collections are present, and audit any code that may invoke commands or execute arbitrary code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
OPPO Amber Lab
Centered on user data security and privacy, we conduct research and open our tech capabilities to developers, building an information‑security fortress for partners and users and safeguarding OPPO device security.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
