Insecure Deserialization: From Serialized Blob to Remote Code Execution

Serialization Basics for Hackers

What serialization is, why apps use it, how a serialized blob differs from JSON, and why serialized data can carry behavior and not just values.

Published

Before you can exploit deserialization you need the model, because the risk comes from a property most developers never think about: serialized data can carry behavior. This page covers what serialization is, why it is everywhere, and why the bytes are dangerous. Practice on a free live target.

In-memory object versus byte stream

A running program holds objects in memory: a User with a name and a role, a shopping cart, a session. To store an object on disk, send it over a network, or put it on a queue, the program turns it into a flat sequence of bytes. That is serialization. Deserialization is the reverse: take the bytes and rebuild the object in memory.

The key point is what gets recorded. A native serializer stores the object's class along with its property values, so rebuilding it instantiates that exact class. That is different from encoding plain data.

Why serialized data can encode behavior

Because the deserializer instantiates a class, it also runs that class's lifecycle code: constructors, and special lifecycle hooks that fire automatically during or after reconstruction. So feeding bytes to a deserializer is not passive parsing, it is "build me an object of this type and run its setup." If an attacker controls the bytes, they control which type is built and with what properties, and the lifecycle code does whatever it does.

That is the entire vulnerability class in one sentence: the rebuild step is code execution, and it happens before your application validates anything.

Why apps use it

Serialization shows up wherever an object needs to leave memory:

Sessions        store the user's session object between requests
Caches          save a computed object to reuse later
Message queues  put a job object on a queue for a worker (Celery, Sidekiq, JMS)
APIs / RPC      send an object to another service
Hidden state    stash object state in a cookie, hidden field, or ViewState

Developers reach for the native serializer because it is one line and preserves types perfectly. The cost is that the rebuild is dangerous on untrusted input.

Per-language formats at a glance

Each ecosystem has its own native format, and you will learn to recognize them on the wire:

PHP      serialize()/unserialize()        text: O:4:"User":2:{...}
Java     ObjectOutputStream               binary, base64 starts rO0AB
.NET     BinaryFormatter / ViewState      base64 starts AAEAAAD, or __VIEWSTATE
Python   pickle                           binary opcodes, often base64
Ruby     Marshal                          base64 commonly starts BAh
Node     node-serialize (library, rare)   JSON with a function trick

JSON and Protobuf are the safe contrast: they encode values into fixed structures and do not instantiate attacker-named classes, unless a library is configured for polymorphic type handling, which reintroduces the danger.

Where you find serialized blobs in traffic

Look in the places apps stash state they expect to get back unchanged:

Cookies and session tokens        Hidden form fields (ASP.NET __VIEWSTATE)
Query and body parameters         Custom headers
API request/response bodies       Message-queue payloads, cache entries

A base64 string that decodes to one of the signatures above is your starting point. The next spoke turns recognition into a confirmed finding.

Where to go next

Learn to spot and confirm these blobs in identifying deserialization, then forge your first object in PHP object injection. Or jump straight to a free live target.

← Back to Insecure Deserialization: From Serialized Blob to Remote Code Execution