Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Sandboxing Ruby

eallam
October 05, 2011

Sandboxing Ruby

Presented at RubyConf 11, this presentation is a brief introduction to sandboxing in Ruby.

eallam

October 05, 2011
Tweet

Other Decks in Programming

Transcript

  1. puts '' puts 'Hello there, and what\'s your first name?'

    name = gets.chomp puts 'Your name is ' + name + '? What a lovely name!' puts 'You must have a middle name though?' name1 = gets.chomp puts 'Your middle name is ' + name1 + '? What a handsome middle name!' puts 'Lastly, your last name must be as dashing as the first two?, What is it if I may ask?' name2 = gets.chomp puts 'Please to meet you, ' + name + ' ' + name1 + ' ' + name2 +'. You sound like a fine specimen! ' insert credit
  2. duh, #gsub! black_list = %w(chmod chown File flock IO.ioctl Kernel

    syscall trap fork setpgid Process setsid setpriority egid ` Object HTTP IO Fiber GC IRB Module Thread Net:: ObjectSpace OpenSSL OpenURI require load __callee__ __method__ abort autoload binding eval exit fail fork open raise readline set_trace_func sleep spawn system throw trap taint untaint STDOUT STDERR %x exec connection popen send module_eval Base64 logger alias try to_sym begin rescue Exception Error ensure instance_variable logger).join('|') code.gsub!(Regexp.new(black_list), '')
  3. duh, #gsub! black_list = %w(chmod chown File flock IO.ioctl Kernel

    syscall trap fork setpgid Process setsid setpriority egid ` Object HTTP IO Fiber GC IRB Module Thread Net:: ObjectSpace OpenSSL OpenURI require load __callee__ __method__ abort autoload binding eval exit fail fork open raise readline set_trace_func sleep spawn system throw trap taint untaint STDOUT STDERR %x exec connection popen send module_eval Base64 logger alias try to_sym begin rescue Exception Error ensure instance_variable logger).join('|') code.gsub!(Regexp.new(black_list), '') while $:.shift; end
  4. run untrusted code • Protect against namespace pollution • Block

    dangerous operations • limit resource utilization
  5. run untrusted code • Protect against namespace pollution • Block

    dangerous operations • limit resource utilization • Protect secrets (/etc/passwd)
  6. run untrusted code • Protect against namespace pollution • Block

    dangerous operations • limit resource utilization • Protect secrets (/etc/passwd)
  7. run untrusted code • Protect against namespace pollution • Block

    dangerous operations • limit resource utilization • Protect secrets (/etc/passwd) Do something fun!
  8. keep_methods = [:eval, : +, :to_s, :methods, :new, :__id__, :object_id,

    :equal?, :==, :undef_method, :puts, :__send__, :const_get] (Kernel.methods - keep_methods).each {|m| Kernel.__send__(:undef_method, m) rescue nil } Object.constants.each {|con| (Object.const_get(con).methods - keep_methods).each {|m| Object.const_get(con).__send__(:undef_method, m) rescue nil } } puts eval(%{#{ARGV[0]}}) sandbox.rb $ ruby sandbox.rb "1+1" 2 $ ruby sandbox.rb "system('echo HELLO')" sandbox.rb:7:in `eval': undefined method `system'
  9. is it $SAFE yet? code = params[:code] #=> "`rm -rf

    /`" code.tainted? # => true eval(code) # => world 'splodes $SAFE = 1 code = params[:code] #=> "`rm -rf /`" code.tainted? # => true eval(code) # => SecurityError: Insecure operation - eval
  10. code = params[:cmd] #=> "`rm -rf /`" code = <<-RUBY

    $SAFE=3 #{code} RUBY Thread.new { eval(code) }.value # => SecurityError http://www.ruby-doc.org/docs/ProgrammingRuby/html/taint.html
  11. “Considering that $SAFE has fallen out of use and there

    is a renewed interest in managing many namespaces/environments on a single VM, I figured hey.” - _why (http://www.ruby-forum.com/topic/150864)
  12. Semantic Analysis ripper (ruby parser) + access control lists code

    = 'eval("evil")' pp Ripper.sexp code [:program, [[:method_add_arg, [:fcall, [:@ident, "eval", [1, 0]]], [:arg_paren, [:args_add_block, [[:string_literal, [:string_content, [:@tstring_content, "evil", [1, 6]]]]], false]]]]]
  13. rubycop (0.5.0) code = "class Foo; end" policy = Rubycop::Analyzer::Policy.new

    Rubycop::Analyzer::NodeBuilder.build(code).accept(policy) # => false policy.whitelist_const('Foo') Rubycop::Analyzer::NodeBuilder.build(code).accept(policy) # => true https://github.com/rubymaverick/RubyCop
  14. CALL_BLACKLIST = %w[ abort alias_method at_exit autoload ... syscall system

    trap undef __callee__ __method__ ].to_set.freeze
  15. Cons • Doesn’t create an new isolated “environment” • If

    code gets through it can do anything • Too restricted, not enough ruby
  16. Cons • Doesn’t create an new isolated “environment” • If

    code gets through it can do anything • Too restricted, not enough ruby • scary ruby edge cases
  17. Many many edge cases in ruby begin x rescue (`ls`;

    RuntimeError) => err end "abc#{`ls`}" :"abc#{`ls`}" `ls` %x[ls] system("ls")
  18. freaky freaky sandboxes (a.k.a. “jails”) http://www.ruby-forum.com/topic/150864 jruby_sandbox Isolates Namespace: s

    = Sandbox.new s.eval <<-RUBY class Foo def self.bar; 'bar'; end end RUBY s.eval 'Foo.bar' # => 'bar' Foo # => NameError: uninitialized constant Foo
  19. RubyInstanceConfig cfg = new RubyInstanceConfig(); ... SandboxProfile profile = new

    SandboxProfile(this); cfg.setProfile(profile); wrapped = Ruby.newInstance(cfg)
  20. sand = Sandbox.safe sand.eval %{`echo HELLO`} # => "HELLO\n" sand.activate!

    sand.eval %{`echo HELLO`} #=> Sandbox::SandboxException: NoMethodError: undefined method ``' for main:Object Blocks dangerous operations:
  21. Protects secrets: File.read('/etc/passwd') => "##\n# User Database etc.." s =

    Sandbox.safe s.activate! s.eval 'File.read("/etc/passwd")' #=> Sandbox::SandboxException: Errno::ENOENT: No such file or directory - /etc/passwd
  22. Limits resource utilization sandbox.eval %{while; true; end}, timeout: 5 #

    => Sandbox::SandboxException: Timeout::Error: execution expired
  23. Can give sandbox “capabilities” class Foo def bar; 'bar'; end

    end sandbox.ref(Foo) foo = sandbox.eval('Foo.new') # => #<Foo:0x7bc5b828> foo.bar # => 'bar'
  24. The Freaky Theory of Sandboxes Ginsberg’s Theorem: conservation of mass/energy

    entropy increases impossibility of reaching absolute zero
  25. The Freaky Theory of Sandboxes Ginsberg’s Theorem: 1. You can’t

    win: conservation of mass/energy entropy increases impossibility of reaching absolute zero
  26. The Freaky Theory of Sandboxes Ginsberg’s Theorem: 1. You can’t

    win: 2. You can’t break even: conservation of mass/energy entropy increases impossibility of reaching absolute zero
  27. The Freaky Theory of Sandboxes Ginsberg’s Theorem: 1. You can’t

    win: 2. You can’t break even: 3. You can’t quite the game conservation of mass/energy entropy increases impossibility of reaching absolute zero
  28. The Freaky Theory of Sandboxes There will always be another

    exploit One exploit is enough to take everything down No amount of exploits will stop us from trying
  29. 1. You can’t win: The Freaky Theory of Sandboxes There

    will always be another exploit One exploit is enough to take everything down No amount of exploits will stop us from trying
  30. 1. You can’t win: 2. You can’t break even: The

    Freaky Theory of Sandboxes There will always be another exploit One exploit is enough to take everything down No amount of exploits will stop us from trying
  31. 1. You can’t win: 2. You can’t break even: 3.

    You can’t quite the game The Freaky Theory of Sandboxes There will always be another exploit One exploit is enough to take everything down No amount of exploits will stop us from trying