Insecure Deserialization: From Serialized Blob to Remote Code Execution
Identifying Insecure Deserialization
How to spot deserialization: format signatures for PHP, Java, .NET, and pickle, the carriers they ride in, and flipping a byte to confirm the server parses it.
Published
You can only exploit a deserializer you can find, and serialized blobs give themselves away by their format and by where they ride. This page covers recognizing the signatures, the carriers, and confirming the server parses your input. Practice on a free live target.
Step 1: recognize the format signature
Decode the suspicious value (usually base64 or URL-encoding) and match the result:
PHP O:4:"User":2:{...} text, length-prefixed; O:=object, a:=array, s:=string
Java base64 rO0AB... raw magic bytes AC ED 00 05
.NET base64 AAEAAAD... BinaryFormatter header; or a __VIEWSTATE field
Python pickle opcodes \x80 proto byte, \x93/c (global), R (reduce), . (stop)
Ruby base64 BAh... (commonly) Marshal version \x04\x08
Node {"x":"_$$ND_FUNC$$_..."} node-serialize function trick in JSONThe PHP format is human-readable and the easiest to start with. The binary formats you identify by their leading bytes.
Step 2: flip a byte to confirm parsing
Recognition is a guess until the server reacts. Tamper one byte of the blob and resend:
GET /account HTTP/1.1
Host: target.example
Cookie: session=Tzo0OiJVc2VyIjoyOntzOjQ6Im5hbWUiO- (one byte changed) -HTTP/1.1 500 Internal Server Error
Content-Type: text/html
PHP Notice: unserialize(): Error at offset 12 of 53 bytesA deserialization or parse error (or a new 500 the original did not cause) confirms the server is deserializing your input. That error message also leaks the format, here PHP unserialize().
Step 3: map the deserializer and escalate
Now pin down the exact stack, because the exploit depends on it:
PHP O: + unserialize() error -> PHP object injection, look for __wakeup/__destruct gadgets
Java rO0AB -> ysoserial, pick a chain for the classpath
.NET AAEAAAD / __VIEWSTATE -> ysoserial.net / viewgen, check the MAC and machine key
pickle opcodes -> pickle __reduce__ payloadCarriers worth checking
Serialized state hides in predictable places:
Cookies and session tokens Hidden form fields (__VIEWSTATE)
Query and body parameters Custom headers
API bodies Message-queue payloads, cache entriesEdge variants
double-encoded base64 of base64, or URL-encoded base64; decode twice
gzip+base64 deflate/gzip then base64 is common for Java/.NET blobs
truncation test cutting the blob short should also throw a parse error
tiny valid object for Java/.NET, send a minimal valid object before the gadgetFixing it
- Do not accept serialized objects from clients. If a cookie or field round-trips object state, that is the finding.
- Integrity-check before parsing so a tampered blob is rejected before deserialization runs.
- Return generic errors so a parse failure does not advertise the deserializer and offset.
Full guidance is in preventing insecure deserialization. Next, forge your first object in PHP object injection, or try it on a free lab.
← Back to Insecure Deserialization: From Serialized Blob to Remote Code Execution