CVE TOMEK posted June 2015
My coworker Tomek found a vulnerability in Rack, a Ruby thingy that is used pretty much in every web framework (Rails, Ramaze, Sinatra...) to translate queries (POST and GET) into Ruby objects.
Tomek: David you don't understand anything, go read this: https://www.omniref.com/ruby/gems/railties/4.2.0/symbols/Rails::Application#annotation=4084035&line=161
It all started when he read about how to_sym() used to work in Ruby versions prior to MRI 2.2. This function converts strings into symbols. A symbol is this thing: :symbol
, that usually is tied to a value: :symbol => 'something'
and that you must have seen written in a really nice way thanks to Ruby's lovely syntax sugar: symbol: 'something'
. Developers use the to_sym()
method a lot to transform the strings from GET
/POST
to symbols. Problem: the symbols created by to_sym()
were stored in the memory and never freed. No garbage collection.
That is a problem if you let user input infinitely use that to_sym()
method.
For example if you naively transformed the GET
variables of a request to symbols through that function, then a malicious user could have queried that page with many ?stuff=something
so that your code would have infinitely stocked symbols in memory until no memory was left.
Tomek was looking for the fastest method to fill up a server's memory. To do this, he tested various forms of parameters to see what would be the most effective. This included many small symbol names, large symbol names, and nested parameters. The most efficient way ended up being a lot of concurrent requests with huge symbol names, the server would go down in less than 2 minutes.
And it was through the nested parameter testing that he found CVE-2015-3225
CVE-2015-3225
https://groups.google.com/forum/#!topic/rubyonrails-security/gcUbICUmKMc
Potential Denial of Service Vulnerability in Rack
There is a potential denial of service vulnerability in Rack. This
vulnerability has been assigned the CVE identifier CVE-2015-3225.
Versions Affected: All.
Not affected: None.
Fixed Versions: 1.6.2, 1.5.4
Impact
------
Carefully crafted requests can cause a `SystemStackError` and potentially
cause a denial of service attack.
All users running an affected release should either upgrade or use one of the workarounds immediately.
In Ruby on Rails, one of the nice things you can do is use associative arrays (called hashes in Ruby) in your forms.
For example, in your HTML
<input type="text" name="form[name]" value="david">
would translates to Ruby as
{"form"=>{"name"=>"david"}}
And that is thanks to Rack! But there is a small problem here, Rack parses these nested hashes by recursively calling itself:
def normalize_params(params, name, v = nil)
...
if params_hash_type?(params[k].last) && !params[k].last.key?(child_key)
normalize_params(params[k].last, child_key, v)
else
params[k] << normalize_params(params.class.new, child_key, v)
Here, Ruby seems to push a bunch of info to the stack before calling the new function. A bit like an assembly prolog.
The thing is, after a while the stack gets full and Ruby throws an exception. And then? Rack catch the exception? Tries again? We don't really know, but the program hangs there.
So Tomek found out that when you would send a POST request with a deep enough hash you would cause the program to hang. This is bad because of DoS attacks.
Also, the problem cannot happen in json because json has a nest limit, and doesn't happen in GET requests either for the same reason.
What now?
CVE and Patches are talked about here: http://www.openwall.com/lists/oss-security/2015/06/16/14
Another thread there: https://hackerone.com/reports/42797
He's still trying to find out what is happening exactly, and he just opened a blog. So who knows, he might write something about it soon.
Comments
leave a comment...