Lucene search

K
hackeroneJeremyevansH1:706934
HistoryOct 03, 2019 - 5:19 a.m.

Ruby: Variant of CVE-2013-0269 (Denial of Service and Unsafe Object Creation Vulnerability in JSON)

2019-10-0305:19:48
jeremyevans
hackerone.com
$500
22

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.026 Low

EPSS

Percentile

89.1%

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:

  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:

  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.

7.5 High

CVSS2

Access Vector

NETWORK

Access Complexity

LOW

Authentication

NONE

Confidentiality Impact

PARTIAL

Integrity Impact

PARTIAL

Availability Impact

PARTIAL

AV:N/AC:L/Au:N/C:P/I:P/A:P

0.026 Low

EPSS

Percentile

89.1%