====== BBC Ch 14: Insecure Deserialization ======
//Source: Bug Bounty Bootcamp by Vickie Li//
===== Mechanisms =====
Serialization converts a program object into a format (byte stream or string) suitable for storage or network transfer. Deserialization reconstructs the object. Many languages support this: Java, PHP, Python, Ruby.
Developers often trust serialized data because it looks opaque or unreadable. Insecure deserialization occurs when user-supplied serialized data is deserialized without verification, letting attackers manipulate object properties or trigger dangerous magic methods.
===== PHP Object Injection =====
PHP serialize format example:
O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:9:"not admin";}
Format: ''O:CLASS_NAME_LENGTH:"CLASS_NAME":PROPERTY_COUNT:{PROPERTIES}''
**Manipulating variables:** if a serialized object is used for authentication and isn't signed or encrypted, modify the status field:
O:4:"User":2:{s:8:"username";s:6:"vickie";s:6:"status";s:5:"admin";}
Note: update the string length marker (''s:9'' -> ''s:5'') when changing values.
**Magic methods:** PHP auto-invokes certain methods during object lifecycle:
* ''__wakeup()'' -- called when an object is deserialized (via ''unserialize()'')
* ''__destruct()'' -- called when no references to the object remain
* ''__toString()'' -- called when the object is treated as a string
* ''__call()'' -- called when an undefined method is invoked
If a magic method passes object properties into dangerous functions like ''eval()'', an attacker can achieve RCE by controlling those properties in the serialized payload.
**Classic PHP RCE via __wakeup:**
class Example2 {
private $hook;
function __wakeup() {
if (isset($this->hook)) eval($this->hook);
}
}
$user_data = unserialize($_COOKIE['data']);
Set ''$hook = "phpinfo();"'' in a crafted serialized object, URL-encode it, and pass it as the ''data'' cookie. The server calls ''eval("phpinfo();")'' on deserialization.
Generate the payload:
class Example2 { private $hook = "phpinfo();"; }
print urlencode(serialize(new Example2));
===== POP Chains =====
When magic methods don't directly contain exploitable code, chain method calls across multiple classes (property-oriented programming). Each "gadget" is a code snippet from the existing codebase. Magic methods serve as the entry point; they call methods on other classes that eventually reach dangerous code like ''eval()'' or ''exec()''.
Example flow: ''__wakeup()'' calls ''$obj->evaluate()'' -> ''CodeSnippet::evaluate()'' calls ''eval($this->code)'' -> attacker controls ''$code''.
===== Java Deserialization =====
Java serialized objects implement ''java.io.Serializable''. Signatures that identify them:
* Hex: ''AC ED 00 05'' at the start
* Base64: starts with ''rO0''
* Content-Type header: ''application/x-java-serialized-object''
Java deserialization exploits use gadget chains from libraries (Apache Commons-Collections, Spring Framework, Apache Groovy, Apache Commons FileUpload) to reach code execution.
**Ysoserial** automates gadget chain generation:
java -jar ysoserial.jar CommonsCollections1 'id'
Feed the output as a serialized object in the vulnerable parameter.
===== Prevention =====
* Never deserialize data tainted by user input without verification
* Use an allowlist to restrict which classes can be deserialized
* Prefer simple data types (strings, arrays) over serialized objects for transport
* Keep session state server-side instead of in serialized cookies
* Keep dependencies patched; many deserialization vulns come from third-party libraries
===== Hunting for Insecure Deserialization =====
**With source code:** search for dangerous deserialization functions:
* PHP: ''unserialize()''
* Java: ''readObject()''
* Python: ''pickle.loads()''
* Ruby: ''Marshal.load()''
Confirm that user-supplied data flows into these calls.
**Without source code:**
* Find large blobs of data in HTTP requests (cookies, POST body, headers) -- these may be serialized objects
* Decode them: base64 blocks starting with ''Tzo'' or ''rO0'' are likely PHP or Java objects
* Look for ''Content-Type: application/x-java-serialized-object''
* Tamper with the object: change usernames, status flags, or role names; re-serialize and replay
* Try to achieve RCE using known gadget chains for the detected language
===== 6-Step Checklist =====
- Find entry points where user-supplied data is deserialized (cookies, POST params, headers).
- Identify the serialization format (PHP, Java, Python, Ruby) from signatures or Content-Type.
- Tamper with variable values in the serialized object (status, role, username) and check for privilege changes.
- If variable tampering achieves authentication bypass, document and report.
- See if magic methods or POP chains can escalate to RCE (use Ysoserial for Java).
- Draft report; be careful not to cause damage when testing RCE payloads.