guest@websec: ~/websec/14-deserialization-and-xxe — zsh — 100×40 by SaKKo ENTH code:

guest@websec ~ % man 14-deserialization-and-xxe

14 · Deserialization and XXE

Some data formats can rebuild any object, read files, or balloon to gigabytes. Parse them from strangers and the input decides what your server does.

14.1 Insecure deserialization

JSON only rebuilds plain data. Ruby's Marshal and YAML with object tags can rebuild any class.

So the attacker picks which objects get built. Chain a few ordinary classes together and you get code execution from one request.

Rails got hit by this in 2013: one POST could take over any Rails app on the internet.
sim: loading a YAML documentpattern-based simulation of Psych's behavior

YAML.unsafe_load

YAML.load (Psych 4+, Ruby 3.1+)

JSON.parse

Defenses:

  • Use JSON for anything from outside.
  • Need YAML from users? YAML.safe_load.
  • Never Marshal.load untrusted bytes.
Modern Rails is safe by default: JSON cookies, no XML params, safe YAML. Check older apps for a :marshal cookie serializer and any Marshal.load.
# safe by default on Ruby 3.1+ (Psych 4)
YAML.load(user_yaml)                                        # plain types only
YAML.safe_load(user_yaml, permitted_classes: [Date, Symbol])
JSON.parse(user_json)

YAML.unsafe_load(user_yaml)        # arbitrary objects
Marshal.load(Base64.decode64(params[:state]))   # RCE

# config/initializers/cookies_serializer.rb (older apps: check this!)
Rails.application.config.action_dispatch.cookies_serializer = :json
// JS: JSON.parse is data-only. Danger comes from libraries that revive objects
JSON.parse(body);                                   // plain data
require("node-serialize").unserialize(body);        // has executed functions (CVE-2017-5941)
yaml.load(text)                                     // js-yaml 3.x: can build functions (4.x is safe)

14.2 XML External Entities (XXE)

XML can point to external files. A careless parser will read /etc/passwd and hand it back, or expand a 1 KB file into gigabytes.

XML hides in SAML, RSS, SVG and Office files.

sim: billion laughshow nested entities explode

Nokogiri is safe by default. Just never pass noent or dtdload.
doc = Nokogiri::XML(upload.read)                 # safe defaults
doc = Nokogiri::XML(upload.read) { |c| c.strict.nonet }

Nokogiri::XML(xml) { |c| c.noent.dtdload }        # enables XXE
Nokogiri::XML(xml, nil, nil, Nokogiri::XML::ParseOptions::NOENT)