Information Security 27 min read

Insecure Deserialization

This article explains what insecure deserialization is, why it leads to high‑severity attacks, demonstrates typical PHP, Ruby, and Java examples, and provides practical techniques for identifying, exploiting, and mitigating unsafe deserialization vulnerabilities.

System Architect Go
System Architect Go
System Architect Go
Insecure Deserialization

Insecure Deserialization

In this section we introduce insecure deserialization, describe how it enables high‑impact attacks, present typical scenarios, and demonstrate concrete examples in PHP, Ruby, and Java, followed by methods to avoid such vulnerabilities.

Exploiting insecure deserialization can be difficult, but sometimes it is simpler than expected. If you are unfamiliar with deserialization, this section provides essential background; otherwise you can jump directly to exploitation techniques.

What Is Serialization

Serialization converts complex data structures (objects and their fields) into a flatter format that can be transmitted as a byte stream. It simplifies writing data to inter‑process memory, files, or databases, and sending data over networks or APIs.

Write complex data to memory, files, or databases

Transmit complex data between application components via network or API calls

When an object is serialized, its state—including property names and values—is preserved.

Serialization vs. Deserialization

Deserialization restores a byte stream to an exact copy of the original object, allowing application logic to interact with it as if it were a normal object.

Many languages provide native support for serialization, either as binary or as readable strings. All object fields, including private ones, are stored unless marked as transient . In Ruby this is called marshalling , in Python pickling .

What Is Insecure Deserialization

Insecure deserialization occurs when attacker‑controlled data is deserialized by the application, allowing manipulation of the serialized object to inject malicious data into the code path.

Attackers may even replace the object with an instance of a completely different class, a situation often referred to as "object injection".

Although an unexpected class may cause exceptions, damage can already be done because many attacks complete before the deserialization finishes, targeting the deserialization process itself.

How Insecure Deserialization Vulnerabilities Appear

These vulnerabilities usually arise from a general lack of awareness that deserializing user‑controlled data is dangerous; ideally such data should never be deserialized.

Some developers add post‑deserialization checks, but these are ineffective because it is often too late to validate after the object has been instantiated.

Another cause is the assumption that deserialized objects are trustworthy, especially when binary formats are used, leading developers to underestimate the risk.

Modern applications depend on many libraries, each exposing numerous classes and methods, creating a large pool of potential gadget chains that attackers can abuse.

In short, safely deserializing untrusted input is practically impossible.

Impact of Insecure Deserialization

The impact can be severe, providing an entry point that dramatically expands the attack surface, allowing reuse of existing code for remote code execution, privilege escalation, arbitrary file access, or denial‑of‑service.

How to Exploit Insecure Deserialization Vulnerabilities

Details are provided in the following sections.

How to Prevent Insecure Deserialization Vulnerabilities

Generally, avoid deserializing user input unless absolutely necessary. When required, verify data integrity before deserialization, for example by using digital signatures.

If possible, avoid generic deserialization functions and implement custom serialization for specific classes to control exposed fields.

Remember that the vulnerability stems from deserializing user input, not from the toolchain itself; relying on toolchain hardening alone is insufficient.

Exploiting Insecure Deserialization

This section teaches how to exploit common deserialization flaws in PHP, Ruby, and Java, showing that exploitation is often easier than expected, especially with pre‑built toolchains.

Identify insecure deserialization

Modify serialized objects

Pass malicious data to dangerous functions

Inject arbitrary object types

Chain method calls to control data flow

Manually craft advanced exploits

PHAR deserialization

Note: Although many examples use PHP, the techniques apply to other languages as well.

Identifying Insecure Deserialization

Look for any incoming data that appears to be serialized; recognizing language‑specific formats makes this easier.

PHP Serialization Format

PHP uses a readable string format where letters denote types and numbers denote lengths. For example, a User object with two properties might be serialized as:

$user->name = "carlos";
$user->isLoggedIn = true;
O:4:"User":2:{s:4:"name":s:6:"carlos";s:10:"isLoggedIn":b:1;}

The components mean:

O:4:"User" – an object of class User

2 – two properties

s:4:"name" – property name "name" (4 characters)

s:6:"carlos" – value "carlos" (6 characters)

s:10:"isLoggedIn" – property name "isLoggedIn" (10 characters)

b:1 – boolean true

PHP’s native functions are serialize() and unserialize() . Search the codebase for unserialize() when you have source access.

Java Serialization Format

Java typically uses a binary format that begins with the magic bytes ac ed or the Base64 prefix rO0 . Any class implementing java.io.Serializable can be serialized, and the method readObject() is used during deserialization.

Manipulating Serialized Objects

Exploiting deserialization often starts by editing serialized data to change property values or types, then feeding the modified payload back to the application.

Modifying Object Properties

Consider a cookie that stores a serialized User object:

O:4:"User":2:{s:8:"username";s:6:"carlos";s:7:"isAdmin";b:0;}

Changing isAdmin from b:0 to b:1 and re‑encoding the cookie can grant administrative privileges if the application trusts the cookie directly:

$user = unserialize($_COOKIE);
if ($user->isAdmin === true) {
    // allow admin access
}

Modifying Data Types

PHP’s loose comparison ( == ) can be abused when attacker‑controlled data is compared to expected values, e.g., 0 == "Example string" evaluates to true.

$login = unserialize($_COOKIE);
if ($login['password'] == $password) {
    // login succeeds
}

Changing the password field to integer 0 can bypass authentication if the stored password does not start with a digit.

Using Application Functionality

Beyond simple property changes, some application functions may act on deserialized data in dangerous ways, such as deleting files based on an image_location property.

Magic Methods

Magic methods (e.g., __construct() , __wakeup() , __destruct() ) are automatically invoked during object lifecycle events. If these methods process attacker‑controlled data, they become exploitable.

Injecting Arbitrary Objects

Because deserialization often does not validate the class of the incoming object, an attacker can supply any serializable class, potentially triggering dangerous code paths.

Gadget Chains

A "gadget" is a piece of existing code that can be chained together to achieve a malicious goal. Attackers combine multiple gadgets to form a "gadget chain" that ultimately executes a payload.

Using Pre‑Built Gadget Chains

Tools like ysoserial (Java) and PHPGGC (PHP) can generate serialized objects for known gadget chains, simplifying exploitation.

Using Documented Gadget Chains

Researchers can look for publicly disclosed gadget chains for popular frameworks and adapt them to the target application.

Creating Your Own Exploit

When existing chains fail, you must analyze source code, locate magic methods, and construct a custom chain, possibly writing code to generate the required serialized payload.

PHAR Deserialization

PHP’s phar:// stream can cause implicit deserialization of PHAR metadata. By uploading a malicious PHAR disguised as an image and forcing the application to access it, attackers can trigger __wakeup() or __destruct() methods.

Exploiting Deserialization via Memory Corruption

Even without gadget chains, memory‑corruption bugs can be leveraged through insecure deserialization, often leading to remote code execution.

JavasecurityPHPdeserializationexploitgadget chainobject injection
System Architect Go
Written by

System Architect Go

Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.