What is Insecure Deserialization? Ways to Exploit, Examples and Impact

Discover how insecure deserialization leads to RCE. Explore technical examples in PHP and Python, and learn how to secure your infrastructure today.

What is Insecure Deserialization? Ways to Exploit, Examples and Impact

Insecure deserialization is a high-severity vulnerability that occurs when an application untrustingly processes data provided by a user to reconstruct an object. This flaw allows attackers to manipulate serialized objects to pass harmful data into the application code, often resulting in Remote Code Execution (RCE), privilege escalation, or data tampering. As one of the most critical entries in the OWASP Top 10, understanding how to identify and mitigate this vulnerability is essential for any modern security professional.

Understanding Serialization and Deserialization

Before diving into the vulnerability itself, we must define the two core processes at play: serialization and deserialization.

What is Serialization?

Serialization is the process of converting a complex data structure or an object (in memory) into a format that can be easily stored or transmitted. This format is typically a byte stream, a string, or a binary format. The goal is to preserve the state of the object so it can be recreated later. For example, if a web application needs to store a user's session data in a database or send it over a network to another microservice, it serializes the "User" object into a flat string.

What is Deserialization?

Deserialization is the exact opposite. It is the process of taking that stored byte stream or string and reconstructing it back into a live object in the application's memory. Once deserialized, the application can interact with the object's properties and methods as if it had never been stored.

In a perfect world, this process is seamless and safe. However, the danger arises when an application assumes that the incoming serialized data is benign. If an attacker can modify the serialized data before it reaches the deserialization function, they can force the application to instantiate objects with malicious attributes or trigger unintended logic flows.

What is Insecure Deserialization?

Insecure deserialization occurs when an application deserializes data from an untrusted source without sufficient validation. Because the deserialization process often involves calling "magic methods" or internal constructors to rebuild the object, an attacker can use this mechanism to execute code.

Think of it like this: if serialization is packing a suitcase for a trip, and deserialization is unpacking it at the hotel, insecure deserialization is like an attacker sneaking a bomb into your suitcase while it's in transit. If the hotel staff (the application) opens the suitcase without checking it, the results can be catastrophic.

How Insecure Deserialization Works: The Technical Mechanism

Most programming languages that support object-oriented programming (OOP) provide built-in mechanisms for serialization. These languages often use "magic methods"—special functions that are automatically triggered during certain events in an object's lifecycle, such as creation, destruction, or deserialization.

Common magic methods used in exploits include:

  • PHP: __wakeup(), __destruct(), __toString()
  • Python: __reduce__, __setstate__
  • Java: readObject(), readResolve(), finalize()

When an application calls a function like unserialize() in PHP or pickle.loads() in Python, the language's engine looks for these magic methods within the object being reconstructed. If an attacker provides a serialized string for a class that is already defined in the application's codebase, they can control the variables passed into these magic methods, leading to an exploit chain.

Exploiting Insecure Deserialization: Language Examples

To better understand the threat, let's look at how this vulnerability manifests across different programming environments.

1. PHP Object Injection

In PHP, the unserialize() function is the primary target. If an application takes a cookie or a POST parameter and passes it directly to unserialize(), it is vulnerable.

Consider a simple class used for logging:

class Logger {
    public $log_file = "access.log";
    public $data = "User logged in";

    public function __destruct() {
        file_put_contents($this->log_file, $this->data);
    }
}

Normally, this class writes logs to access.log. However, if an attacker sends a serialized version of this object, they can overwrite the $log_file and $data properties.

Malicious Payload:
O:6:"Logger":2:{s:8:"log_file";s:12:"shell.php";s:4:"data";s:30:"<?php system($_GET['cmd']); ?>";}

When the application deserializes this string, it creates a Logger object. When the script finishes and the object is destroyed, the __destruct() method runs, creating a file named shell.php containing a web shell. This is a classic example of Remote Code Execution via insecure deserialization.

2. Python Pickle Exploitation

Python's pickle module is notoriously insecure. The documentation itself warns against using it for untrusted data. The __reduce__ method in Python is used to define how an object should be reconstructed; it returns a tuple containing a callable and the arguments for that callable.

An attacker can craft a malicious pickle payload like this:

import pickle
import os
import base64

class MaliciousPayload(object):
    def __reduce__(self):
        # This will execute 'whoami' on the server
        return (os.system, ('whoami',))

# Serialize the malicious object
serialized_payload = pickle.dumps(MaliciousPayload())
print(base64.b64encode(serialized_payload))

If the target application runs pickle.loads(user_input), the os.system('whoami') command will execute immediately upon deserialization. Because pickle is so flexible, it is one of the easiest languages to exploit if the developer is unaware of the risks.

3. Java Deserialization and Gadget Chains

Java exploitation is often more complex because it relies on "gadget chains." A gadget is a piece of code already present in the application's classpath (like in a library like Apache Commons Collections) that can be misused when its state is controlled by an attacker.

In Java, the java.io.Serializable interface allows objects to be converted to byte streams. Attackers look for specific signatures in traffic to identify Java serialization, such as the hex header AC ED 00 05 or the Base64 string rO0AB.

Tools like ysoserial allow researchers to generate payloads that chain together multiple library calls to eventually reach a "sink"—a function that executes a system command. For example, a chain might move from a Map object to a Transformer object, eventually calling Runtime.exec().

The Impact of Insecure Deserialization

The impact of this vulnerability is almost always critical. Because the attacker is essentially controlling the state of the application's memory, the consequences include:

  • Remote Code Execution (RCE): As shown in the examples above, the most common goal is to run arbitrary commands on the underlying server.
  • Privilege Escalation: An attacker might deserialize an "User" object but change the isAdmin flag from false to true to gain administrative access.
  • Denial of Service (DoS): By sending a "Billion Laughs" style payload or an object that initiates an infinite loop during deserialization, an attacker can crash the application.
  • Data Exfiltration: Attackers can manipulate objects to read sensitive files or query databases and send the results back to an attacker-controlled server.

How to Identify Insecure Deserialization

Identifying this flaw requires looking for where the application handles serialized data.

  1. Analyze Traffic: Look for serialized formats in HTTP headers, cookies, and hidden form fields. Look for the signatures mentioned earlier (e.g., O:6:"Class" in PHP or rO0 in Java).
  2. Code Review: Search the codebase for dangerous functions like unserialize(), pickle.loads(), Marshal.load(), or readObject().
  3. Black-box Testing: Try to modify serialized values. If you see a Base64 encoded string that looks like an object, decode it, change a value, re-encode it, and send it back. If the application's behavior changes (e.g., you become a different user), it is likely vulnerable.
  4. DNS Interaction: Use a tool to generate a payload that performs a DNS lookup (like ping or nslookup) to a collaborator server. If you receive a DNS hit, you have confirmed RCE.

Prevention and Mitigation Strategies

The best way to prevent insecure deserialization is to avoid it entirely. However, if you must use it, follow these best practices:

  • Use Safer Data Formats: Whenever possible, use purely data-centric formats like JSON or XML. These formats do not inherently include logic or magic methods, making them significantly safer than language-specific serialization.
  • Never Trust User Input: Do not pass data from cookies, URL parameters, or API requests directly into a deserialization function.
  • Integrity Checks: If you must send serialized data to the client, sign it using a Message Authentication Code (MAC) like HMAC. When the data returns, verify the signature before deserializing. If the data was tampered with, the signature will be invalid.
  • Whitelisting/Look-ahead Deserialization: In Java and .NET, you can implement custom deserialization logic that checks the class type before the object is actually instantiated. Only allow a strict whitelist of safe classes.
  • Run with Low Privileges: Ensure the application process runs with the minimum necessary permissions to limit the damage an attacker can do if they achieve RCE.

Conclusion

Insecure deserialization remains a formidable threat because it turns a standard programming feature into a powerful exploit vector. By understanding the underlying mechanics of how objects are reconstructed and the dangers of magic methods, developers and security researchers can better protect their infrastructure. Whether it is a simple PHP object injection or a complex Java gadget chain, the principle remains the same: never trust data that you didn't create yourself.

To proactively monitor your organization's external attack surface and catch exposures like insecure deserialization before attackers do, try Jsmon.