Skip to content

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Schwachstellenklassen Glossary

Insecure Deserialization - Unsichere Deserialisierung

Insecure deserialization (OWASP A08:2021) occurs when an application processes serialized objects from untrusted sources without sufficient validation. Attackers manipulate serialized data to call arbitrary methods during deserialization (gadget chains). Affected are Java (readObject), PHP (unserialize), Python (native serialization formats), .NET (BinaryFormatter), and Ruby (Marshal.load). Result: Remote Code Execution, Privilege Escalation, or Denial of Service.

Insecure deserialization is one of the most complex classes of vulnerabilities—and at the same time, one with enormous potential for impact. The core problem: Serialization is a powerful mechanism that converts objects into a format that can be transmitted or stored. If deserialization processes this data without suspicion, the entire object structure becomes an attack vector.

Basic Principle

Serialization vs. Deserialization:

Serialization: Object → Bytes/Text (for transmission/storage)
Deserialization: Bytes/Text → Object (reconstruction)

Problem with insecure deserialization:
  → An attacker controls the serialized bytes/data
  → They can inject a specially crafted object
  → During deserialization, "magic" methods are called
  → Under normal program logic, these methods execute arbitrary code!

Where does serialized data occur?
  → HTTP cookies (Base64-encoded serialized session objects!)
  → HTTP body in POST requests
  → Database fields (BLOBs containing serialized objects)
  → Cache systems (Redis, Memcached)
  → Message queues (RabbitMQ, Kafka with Java objects)
  → API parameters and hidden form fields

Attack types by language

1. PHP deserialization:

   PHP serialization format (recognizable):
   O:4:"User":2:{s:4:"name";s:5:"Alice";s:4:"role";s:4:"user";}
   → Object (O) of the "User" class with 2 properties

   Magic PHP methods called during deserialization:
   __wakeup()    → called automatically during deserialization
   __destruct()  → when the object is deleted after the script ends
   __toString()  → when the object is used as a string

   Attack principle:
   → Identify a class with a dangerous __wakeup()/__destruct() method
   → Create your own serialized object of this class
   → Set a dangerous value → code execution during deserialization!

   Typical use cases for PHP unserialize():
   → Cookie value, hidden form field, API parameter
   → Detection in code: grep -r "unserialize(" /var/www/

   Protection:
   → Never use unserialize() on external data (without HMAC signature)
   → Use the allowed_classes parameter (PHP 7.0+):
     unserialize($data, ["allowed_classes" => ["SafeClass"]])
   → Use JSON instead of PHP serialization for external data

2. Java deserialization:

   Java Serialization: ObjectInputStream.readObject()
   Identification characteristic in HTTP traffic:
   → "rO0AB" at the beginning (Base64) or "\xAC\xED\x00\x05" (bytes)

   Gadget chains:
   → Gadget = class that performs actions useful to attackers during deserialization
   → In popular libraries: Commons Collections, Spring, Groovy, Hibernate
   → Chain: Gadget A calls B → B calls C → C executes code

   Penetration testing tool ysoserial:
   → Generates crafted Java serialization objects for authorized testing
   → Supported chains: CommonsCollections1-7, Spring1, Groovy1
   → Payload → during deserialization: command execution on server

   Java protection:
   → ObjectInputFilter (Java 9+): allowlist of permitted classes
   → Jackson/GSON/Protocol Buffers instead of Java native serialization
   → serialkiller filter: blocklist of known gadget classes
   → Deserialization in sandbox (isolated process)

3. Python native serialization formats:

   Native Python serialization allows the __reduce__ method:
   → Class can call any function during deserialization
   → NEVER use for external/untrusted data!

   Secure alternatives for Python:
   → json.dumps/json.loads: JSON without code execution risk
   → Pydantic, marshmallow: schema-based secure deserialization
   → Protocol Buffers, MessagePack: type-safe, no code execution

4. .NET BinaryFormatter (completely deprecated!):

   BinaryFormatter: completely removed by Microsoft in .NET 7+
   → Was insecure by design: no class filtering
   → Migration: System.Text.Json, MessagePack, Protobuf

5. Ruby Marshal:

   Marshal.load on external data: Ruby object gadget chains possible
   Protection: Use JSON, MessagePack for all external data

Detection in Penetration Testing

Detecting deserialization in HTTP traffic:

Detection characteristics:
  PHP serialized:   O:4:"User":0:{} or a:2:{i:0;s:5:"hello";}
  Java serialized:  rO0ABVN... (Base64) or %AC%ED%00%05 (URL-encoded)
  .NET:            AAEAAAD/////...
  Ruby Marshal:    BAh... (Base64)

Burp Suite Procedure:
  1. Analyze HTTP traffic with Burp: Cookies, body parameters, headers
  2. Base64 value with "rO0AB" prefix → Java deserialization!
  3. Install the Burp Extension "Java Deserialization Scanner"
  4. Insert the prepared payload from ysoserial → into Burp Repeater
  5. Out-of-Band verification: Burp Collaborator (DNS callback)

Automated scanning:
  Nuclei: Templates for known deserialization vulnerabilities
  Burp Pro Active Scan: automatically detects Java deserialization

Mitigation Measures

Secure Design Decisions:

Recommended Formats (NO code execution possible):
  JSON:              Simplest and safest option
  MessagePack:       Binary + compact + type-safe
  Protocol Buffers:  Schema-defined, Google standard
  CBOR:              Compact Binary Object Representation
  Apache Avro:       Schema-versioned, for big data

If deserialization is unavoidable:
  1. HMAC signature over serialized data:
     → Only deserialize HMAC-signed data
     → Key on the server side (attacker cannot sign validly)
     → Verify signature before deserialization – failure → reject

  2. Class allowlist:
     Java:   ObjectInputFilter → deserialize only allowed classes
     PHP:    allowed_classes parameter for unserialize()
     .NET:   System.Text.Json with known types

  3. Sandbox isolation:
     → Deserialization in an isolated process (separate JVM/Python environment)
     → No network access, no filesystem access in the sandbox process
     → On exception: Kill process → no damage

  4. Monitoring:
     → Log deserialization exceptions + SIEM alert
     → Unknown class names in payloads: Alert!

Developer checklist:
  □ Never deserialize external data directly (without signature + allowlist)
  □ Native serialization for external data? → Migrate to JSON/Protobuf immediately
  □ Session data: Store on the server in the DB (no session object in the cookie)
  □ If using cookie-based sessions: JWT with RS256 (stateless, no deserialization)
  □ Keep libraries up to date: Gadget chains only in old versions!
  □ SAST scan: Semgrep finds insecure deserialization calls in code