Variant of CVE-2013-0269 (Denial of Service and Unsafe Object Creation Vulnerability in JSON)
Medium
R
Ruby
Submitted None
Actions:
Reported by
jeremyevans
Vulnerability Details
Technical details and impact analysis
During my recent keyword argument separation work on `rb_scan_args` in the master branch, I discovered what I now think is a vulnerability.
While the CVE-2013-0269 change fixed most usage of `JSON.parse`, it ended up not fixing `Kernel#JSON`. The reason behind this is that internally, in `JSON::Parser#initialize` (in `cParser_initialize` in `ext/json/parser/parser.c`), there is a separate branch taken depending on whether an option hash was provided. The fix for CVE-2013-026 only fixed one of these branches (when a option hash is provided). It did not fix the other branch (when no option hash is provided).
`Kernel#JSON` is able to easily hit the case where no option hash is provided, because it does:
```ruby
def JSON(object, *args)
if object.respond_to? :to_str
JSON.parse(object.to_str, args.first)
```
In the common case, no extra arguments are provided, and `args.first` is `nil`. Historically, Ruby has allowed the `rb_scan_args` `:` character to handle a `nil` option hash like no option hash was provided. This is deprecated in the master branch, and a warning is issued, but it is still supported.
I fixed this in the master branch in the `rb_scan_args` commit, as it was needed to avoid the warning:
https://github.com/ruby/ruby/commit/80b5a0ff2a7709367178f29d4ebe1c54122b1c27#diff-59fb0f5411be4c22009691e1a7f5a185 . It was only later, when I was going to report this issue upstream that I realized the security implications.
I believe all previously released versions of Ruby since 1.9 (when JSON was included in stdlib) are vulnerable to this. I think this fix should be backported to Ruby 2.4, 2.5, and 2.6, and another CVE issued.
In addition to `Kernel#JSON`, there are some other vulnerable calls, though they are likely to be less common.
Full example code:
```ruby
require 'json'
class A < Struct.new(:a)
def self.json_create(object)
new(*object['args'])
end
def to_json(*args)
{
'json_class' => self.class.name,
'args' => [ a ],
}.to_json(*args)
end
end
js = A.new(1).to_json
p JSON.parse(js) #=> {"json_class"=>"A", "args"=>[1]}
p JSON(js) #=> #<struct A a=1>
# Also vulnerable, resulting in #<struct A a=1>
p JSON.parse(js, nil)
p JSON[js, nil]
p JSON::Parser.new(js).parse
```
## Impact
This highly depends on the application using in question. In order to be vulnerable, `Kernel#JSON` or one of the other vulnerable calls must be called with user provided input.
I am not sure this results in denial of service since Ruby 2.2, due to the support of dynamic symbols. However, I have not analyzed the related JSON code to determine if it creates dynamic or static symbols when `create_additions` is used.
Assuming that `Kernel#JSON` is called with user-provided input, this allows creation of arbitrary objects where there is a named class that has a `json_create` singleton method.. More precisely, this allows calling `json_create` methods on any named constant with arbitrary arguments (assuming the constant returns a true value for `json_createable?`). Many Ruby applications use libraries that have objects in constants that support `method_missing` and could possibly be vulnerable. However, I have not done any research into possible exploitability, which is why I listed severity as Medium.
If any `json/add/*` files have been required, this could possibly be very dangerous, as those can allow the creation of arbitrary core/stdlib objects. For example `json/add/ostruct` being required, when combined with this vulnerability, allows the creation of arbitrary objects that support attacker-defined methods with attacker-defined values of any type supported by JSON. `json/add/regexp` allows the creation of arbitrary Regexps which could easily lead to denial of service, and combined with a vulnerability in the regexp engine (Onigmo), could potentially lead to remote code execution.
Related CVEs
Associated Common Vulnerabilities and Exposures
CVE-2013-0269
UNKNOWN
The JSON gem before 1.5.5, 1.6.x before 1.6.8, and 1.7.x before 1.7.7 for Ruby allows remote attackers to cause a denial of service (resource consumption) or bypass the mass assignment protection mechanism via a crafted JSON document that triggers the creation of arbitrary Ruby symbols or certain internal objects, as …
Report Details
Additional information and metadata
State
Closed
Substate
Resolved
Bounty
$500.00
Submitted
Weakness
Business Logic Errors