Slide 1

Slide 1 text

unrubby @rich0H

Slide 2

Slide 2 text

richö ‣ rich-oh! ‣ Computer Jerk at Stripe ‣ Duck Enthusiast ‣ Co-owner of plausibly the world's most ridiculous CVE ‣ WrongIslandCon jerk ‣ paraTROOPER ‣ github.com/richo ‣ twitter.com/rich0H

Slide 3

Slide 3 text

Please hold while richo takes a selfie

Slide 4

Slide 4 text

What this talk is ‣ Neat tricks with bytecode vms ‣ Some hilarity inside of the Rubby's VM ‣ Some reversing fu for people who don't like reversing ‣ Maybe a little opaque- please ask me questions

Slide 5

Slide 5 text

What this talk isn't ‣ Dropping 0day or bugs per se

Slide 6

Slide 6 text

The Problem ‣ Someone wants to give you a black box that does computer ‣ They don't want you to know how it computers

Slide 7

Slide 7 text

Some terminology ‣ VM: Virtual machine ‣ Opcode/Instruction: Used interchangably to refer to operations in the VM ‣ Bytecode: Internal representation of programs expressed as a series of opcodes

Slide 8

Slide 8 text

Their Solution ‣ Obfuscation!

Slide 9

Slide 9 text

Their Solution ‣ Obfuscation! ‣ Not novel: ‣ Malware authors are on this case ‣ Native code has been doing this for years ‣ Obfuscating bytecode isn't new

Slide 10

Slide 10 text

This kinda sucks in a bytecode VM ‣ Your options for detecting fuckery are pretty limited ‣ No performance counters ‣ Very limited sidechannels ‣ No weird instructions to poke

Slide 11

Slide 11 text

This *really* sucks in a dynamic VM ‣ Dynamic dispatch means you can't mangle classes and methods ‣ Lack of a JIT means you can't do anything egregious to method bodies

Slide 12

Slide 12 text

Code obfuscation ‣ Typically packs up either source or a build product ‣ Loaders tend to be really complex ‣ Messing with RE's is seemingly fun to these people

Slide 13

Slide 13 text

Some more terminology ‣ Rubby: An interpreted, dynamic language ‣ YARV: Yet Another Rubby VM ‣ MRI: Matz Rubby Interpreter

Slide 14

Slide 14 text

What if you're really lazy

Slide 15

Slide 15 text

The Rubby VM source_file.rb READ CODEGEN

Slide 16

Slide 16 text

The Rubby VM

Slide 17

Slide 17 text

The Rubby VM

Slide 18

Slide 18 text

inside an InstructionSequence

Slide 19

Slide 19 text

The Rubby VM source_file.rb READ CODEGEN EVAL

Slide 20

Slide 20 text

The Obfuscated Rubby VM source_file.rb READ CODEGEN OBFUSCATION obfuscated_source_file.rb obfuscated_source_file.rb UNPACK EVAL

Slide 21

Slide 21 text

Packed code

Slide 22

Slide 22 text

Dynamic VM is Dynamic ‣ We can trivially insert instrumentation ‣ This.. sort of works. ‣ Tack binding.pry calls everywhere ‣ Attach a debugger, do a lot of `call rb_f_eval` ‣ Defeats for this are fairly plausible and costly to bypass ‣ Dynamism is a double edged sword

Slide 23

Slide 23 text

Rubby ‣ Open Source! ‣ We can just slam our own debug interfaces in ‣ Worked entirely with the reference implementation ‣ All mainstream loaders target it anyway ‣ Typically see a loader for each of the more recent rubbies

Slide 24

Slide 24 text

The Rubby VM ‣ Interesting symbols to start with: ‣ rb_eval_iseq

Slide 25

Slide 25 text

The Rubby VM ‣ Interesting symbols to start with: ‣ rb_eval_iseq ‣ rb_define_method ‣ vm_define_method

Slide 26

Slide 26 text

The Rubby VM ‣ Interesting symbols to start with: ‣ rb_eval_iseq ‣ rb_define_method ‣ vm_define_method ‣ rb_f_eval (lol)

Slide 27

Slide 27 text

Ok so we have bytecode right ‣ Now what?

Slide 28

Slide 28 text

A stack of Rubbies ‣ Rubby's VM is a stack machine ‣ Opcodes consume operands from the stack and leave values on it ‣ A few simple registers for storing branch conditions, pc, etc

Slide 29

Slide 29 text

Deeper into the YARV

Slide 30

Slide 30 text

Expressive IR is nice ‣ YARV bytecode is pretty easy to read ‣ Auditing by hand isn't too bad ‣ Happily it's also sufficiently expressive that decompilation is pretty tenable

Slide 31

Slide 31 text

Reversal ‣ Research project from Michael Edgar @ dartmouth ‣ Similar in operation to pyRETic by Rich Smith

Slide 32

Slide 32 text

Reversal ‣ Over the course of this research I found several versions of rubby that simply won't compile ‣ Several debug flags that cause rubby simply not to build ‣ The VM has gained more instructions since 2010

Slide 33

Slide 33 text

Aside: instructions ‣ bitblt:

Slide 34

Slide 34 text

Aside: Docs ‣ Rubby is an english language (now) ‣ This is.. not super true for large chunks of the codebase

Slide 35

Slide 35 text

Reviving Reversal ‣ Patched reversal until it started working again ‣ Added support for rubby 1.9.3 ‣ And it's delightful new instructions

Slide 36

Slide 36 text

Presenting: unrubby ‣ Hacked up rubby VM ‣ Lots and lots of hooks into internal behaviour ‣ Reaches out to reversal for decompilation ‣ Gives you back source!

Slide 37

Slide 37 text

Why not just reversal ‣ Reversal's mode of operation is a bit fragile ‣ Unrubby hooks the behaviour of the VM, not the format of the bytecode ‣ Attempts to defeat unrubby would in turn be fragile

Slide 38

Slide 38 text

Digging further in ‣ Reversal suggests it can take the whole program and turn it back into source. ‣ This is largely untrue in my experience.

Slide 39

Slide 39 text

Obfuscation at many layers ‣ Problem space includes two layers: ‣ Obfuscation of the bytecode itself ‣ Difficult to read bytecode

Slide 40

Slide 40 text

Obfuscation at many layers

Slide 41

Slide 41 text

Obfuscation at many layers

Slide 42

Slide 42 text

Digging further in ‣ We can keep abusing the runtime behaviour of the VM ‣ hook more stuff! ‣ rb_mod_include ‣ rb_obj_extend ‣ rb_define_class ‣ rb_define_method

Slide 43

Slide 43 text

Patchy patchy

Slide 44

Slide 44 text

Patchy patchy

Slide 45

Slide 45 text

Bonus ‣ This also gives us a more flexible intermediate state ‣ Write your own hooks in rubby!

Slide 46

Slide 46 text

More bonus ‣ This has the impact of "unfurling" metaprogramming ‣ We get dynamically generated methods as well

Slide 47

Slide 47 text

Aside: Classes ‣ Rubby classes are weird ‣ If you think that hooking rb_define_class is enough you would be sadly mistaken ‣ Luckily our hook function is idempotent ‣ Skim class.c and hook *everything*

Slide 48

Slide 48 text

Demo time!

Slide 49

Slide 49 text

Making it go ‣ Rubby's insanity is super useful to us ‣ We can preload our library, then hijack execution flow during the eval step ‣ An atexit(3) hook will just dump the code to stdout

Slide 50

Slide 50 text

Real world breaking ‣ Things have dependencies ‣ Things want to talk to databases ‣ Rubby to the rescue again!

Slide 51

Slide 51 text

Naively ‣ Reimplement rails without any bodies

Slide 52

Slide 52 text

Rubby: richo has feels ‣ Rubby lets you do a bunch of things it ought not to: ‣ method_missing ‣ const_missing ‣ reopening classes ‣ monkey patching ‣ etc

Slide 53

Slide 53 text

Or!

Slide 54

Slide 54 text

Stealth ‣ Reversing things is kinda noisy ‣ Do this in an unroutable vm ‣ Unroutable vm's are miserable to work with

Slide 55

Slide 55 text

Stealth ‣ Reversing things is kinda noisy ‣ Do this in an unroutable vm ‣ Unroutable vm's are misrable to work with ‣ Compromises end up getting made

Slide 56

Slide 56 text

What's in the box? ‣ Rubby source tree ‣ Patched version of reversal ‣ A rails shim that ought to appease many applications ‣ Please play with it! ‣ Please report bugs! ‣ I'll drop some tips in the readme for how to report bugs without coughing up privileged code ‣ UNRUBBY_REPORT_BUG

Slide 57

Slide 57 text

More goodies ‣ Lots of environment variables to control what gets emitted ‣ UNRUBBY_FULL_ISEQ ‣ UNRUBBY_METHODS ‣ YOLO ‣ Abusing the autoloader can yield results

Slide 58

Slide 58 text

Care and Feeding ‣ unrubby currently targets rubby 2.1 ‣ Vendors typically ship shims for their rubby ‣ Upstream vendors make loader bundles available ‣ Autoloaded packages can make you sad ‣ Implement your own entrypoint ‣ Overwrite their bundled rubby

Slide 59

Slide 59 text

How would I defeat it? ‣ No super obvious way ‣ Unfortunately Rubby is just a really obtuse VM to target ‣ Cat and mouse games abound: ‣ Checksum argv[0] ‣ Recalculate internal offsets ‣ Best I came up with was to shove everything into .rodata and statically link a binary

Slide 60

Slide 60 text

Go forth! ‣ No obvious way to defeat the attack! ‣ Cost of attack:defense way in favour of attacker ‣ Novel technique that can be applied to other VMs easily ‣ Go reverse stuff

Slide 61

Slide 61 text

Gr33tz and shit ‣ Rich Smith - pyRETic ‣ Michael Edgar - Reversal ‣ TROOPERS for having me ‣ Whoever I'm missing

Slide 62

Slide 62 text

Resources ‣ https://github.com/richo/unrubby ‣ https://github.com/michaeledgar/reversal ‣ I'll toot the link to these slides - @rich0H Questions?