Insecure Deserialization in Java and PHP for Bug Bounty
Insecure deserialization means the app turns untrusted bytes into objects — and those objects run code during reconstruction. OWASP ranks it harshly for a reason: one gadget chain can mean RCE.
Bug bounty reality is messier. You need a reachable sink, a usable gadget graph, and a PoC that proves danger without toasting the host.
Fingerprints by ecosystem
Java: acED hex magic in cookies or parameters (Java native serialization), XMLDecoder, common libraries with known gadget histories (think ysoserial territory), ViewState-like blobs on older stacks, RMI/JMX edges (often out of scope).
PHP: unserialize( on user input, Laravel/Phar tricks, object injection via cookies labeled as “session” but actually serialized PHP objects. Magic methods (__wakeup, __destruct) are the usual pop chains.
Also watch JSON “serializers” that invoke type fields (@type in some Java JSON libraries historically) — different format, same trust mistake.
Hunter workflow
- Locate base64 blobs the server echoes or stores. Decode. Look for Java serial signatures or PHP object syntax
O:4:"Evil". - Confirm the server deserializes by mutating a byte and watching for stack traces or state changes.
- On authorized labs or local replicas, test gadget availability. On production, prefer benign detection payloads that prove type control without launching reverse shells.
- If RCE is in scope and you must prove it, use the program’s preferred safe pattern (sleep, DNS callback, writing a unique file under an allowed path) — never a destructive payload.
Impact framing
“Untrusted deserialize present” is half a report. Triagers want:
- Where the blob is accepted
- Evidence the server instantiates attacker-influenced types
- A controlled effect (callback, time delay, file canary)
- Notes on authentication requirements and blast radius
What gets you in trouble
Dropping public exploit blobs against production banks and hospitals. Blindly running ysoserial until something pages. Ignoring scope that excludes RCE testing.
If gadgets fail, still report the sink with clear limits: “deserialization of attacker-controlled data without a demonstrated gadget on this classpath.” Some programs pay for that; others wait for a full chain.
Remediation blurb
Do not deserialize untrusted data. Use allowlisted formats (JSON without polymorphic type gadgets), HMAC-protect any serialized state you must keep, and run apps with minimal privileges.
Java and PHP serialization bugs still clear payouts when you treat them as controlled experiments: find the blob, prove the sink, demonstrate one safe side effect, then stop.