Insecure Deserialization Exploitation: Java, .NET, PHP, Python
Cybersecurity
Gadget chains, ysoserial, phpggc, and serialization tricks. A cross-language tour of deserialization RCE techniques that still ship in 2024.
By Arjun Raghavan, Security & Systems Lead, BIPI · November 18, 2024 · 13 min read
Deserialization bugs convert a single tainted byte stream into remote code execution. Every major language has shipped a famous chain, and the bug class keeps returning whenever a developer reaches for serialize and deserialize as a shortcut.
Identifying Deserialization Sinks
- Java: ObjectInputStream.readObject on cookies, view state, or RMI
- .NET: BinaryFormatter, LosFormatter, NetDataContractSerializer, SoapFormatter
- PHP: unserialize on session data, cache values, or URL parameters
- Python: native binary load, yaml.load without SafeLoader, jsonpickle
- Ruby: Marshal.load and YAML.load on untrusted input
- Node: node-serialize, funcster, and unsafe JSON revivers
Java Gadget Chains With ysoserial
ysoserial ships chains for CommonsCollections, Spring, Hibernate, JRE8u20, and many more. Identify libraries in the classpath via error messages, jar listings, or Maven coordinates leaked in stack traces, then pick the matching payload.
- Fingerprint libraries via error messages and HTTP headers
- Generate payload using ysoserial with the right gadget chain
- Encode appropriately (base64 for cookies, raw for RMI)
- Confirm via OOB callback to Burp Collaborator
- Escalate to interactive shell once execution is proven
.NET Deserialization
ysoserial.net produces gadgets for ObjectDataProvider, TypeConfuseDelegate, and many WPF and WCF chains. ViewState without MAC validation is a classic entry point, especially on legacy ASP.NET WebForms apps.
PHP Object Injection
phpggc covers Laravel, Symfony, Magento, Drupal, WordPress, and dozens of frameworks. The bug surfaces wherever unserialize touches user input, including session handlers, cookies, and cache keys. PHAR deserialization extends the attack surface to file upload sinks via file_exists and similar functions.
Python Native and YAML Loaders
- Loading native binary objects from any attacker controlled blob is instant RCE
- yaml.load without SafeLoader executes python object apply tags
- jsonpickle has historically allowed class instantiation by design
- Celery and Redis-backed task queues frequently use unsafe loaders by default
- Always test cookies and cache values for the native magic byte prefix
If you see a native Python binary loader in a web app, the only safe answer is to remove it. There is no list of safe gadgets.
Detection Without Source
Send known-bad payloads with a Collaborator callback. Java payloads have recognizable magic bytes starting AC ED 00 05. PHP serialized data starts with O or a colon-prefixed token. Python native blobs start with 0x80. Burp Suite extensions like Java Deserialization Scanner automate the probing.
Remediation
- Replace native serialization with JSON or Protobuf
- If unavoidable, use allowlists via ObjectInputFilter in Java or SerializationBinder in .NET
- Sign serialized blobs with HMAC and verify before deserializing
- Run deserialization in a sandboxed worker with no network egress
- Keep gadget-bearing libraries patched: commons-collections, Spring, Newtonsoft.Json
Read more field notes, explore our services, or get in touch at info@bipi.in. Privacy Policy · Terms.