HexBrain

RubyGems · Report #274990

Remote code execution on rubygems.org

Validstatus
criticalseverity
$1,500bounty
51upvotes
9 Nov 2017disclosed

Summary

An unsafe object deserialization vulnerability was found in RubyGems. Unfortunately this vulnerability can be used as a way to escalate to a remote code execution exploit.

How it was found

When parsing a gem POSTed to the /api/v1/gems endpoint, the rubygems.org application immediately calls Gem::Package.new(body).spec inside app/models/pusher.rb. The authors of the application correctly observed that parsing untrusted YAML is dangerous (since it can serialize more or less arbitrary objects), so they monkey-patched the spec parser to use Psych.safe_load set from config/initializers/forbidden_yaml.rb.

However, YAML.load is called directly when parsing the gem's checksum file in Gem::Package#read_checksums. Using classes accessible within the application, I was able to turn this into a call to Marshal.load on attacker-controlled data. From there, I was able to use known Marshal exploitation techniques to achieve code execution on the server (I'm omitting some details here for brevity so that I can submit this report right away).

A proof of concept, poc.gem, is attached. Run the exploit with the following command: cat poc.gem | curl -H 'Content-Type: application/gzip' --data-binary @- -H 'Authorization: █████' https://rubygems.org/api/v1/gems

I ran the attached PoC twice. It just does a wget to my server.

Please let me know if I should clarify anything! Thanks for running this program.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original