RubyGems, a package of software tools that installs, upgrades and configures Ruby libraries and programs, on Monday announced it had patched a critical vulnerability.
Attackers could leverage the flaw—an unsafe object deserialization vulnerability—to escalate privileges and remotely execute code. To do so, an attacker would have to be able to inject an instance of an object on a vulnerable system, and do so in a way that would enable code execution, the RubyGems team said.
“The RubyGems team audited all Gems, and using the data available to us we can say we have high confidence that no recently published Gems have been impacted, but due to the amount of time this bug has been in production, we cannot say for sure that zeroGems have been impacted,” wrote Aaron Patterson, one of the RubyGems maintainers, in an advisory published Monday. Patterson added that the bug was introduced in 2012 and it’s likely RubyGems has been vulnerable for at least five years.
From the advisory:
“This particular case has to do with the way RubyGems stores checksums inside Gem files. Checksums are stored in YAML inside the Gem, and before this fix, they were read with just a bare YAML.load. YAML, like Marshal, is meant to serialize and deserialize arbitrary Ruby objects. When RubyGems.org processes a Gem upload, it reads the Gem specification, which in turn reads the checksums in the Gem. A clever attacker could write a checksum file to a Gem that contains YAML formatted in such a way as to inject an arbitrary Ruby object and use that object as an escalation point.”
A researcher named Max Justicz found the bug and reported last Friday, and published a description of the issue on Saturday two days before it was patched.
Justicz’s description of the bug says the YAML files contained in a gem contain everything from its name, author, version, source code and cryptographic hashes of its contents.
“I was surprised to learn that parsing untrusted YAML is dangerous,” Justicz wrote. “I had always figured it was a benign interchange format like JSON. In fact, YAML allows for the encoding of arbitrary objects, much like python’s pickle.”
Justicz said that when a gem is uploaded to the rubygems[.]org site, it uses unsafe calls to load YAML files into the gem. He speculated that the authors of rubygems[.]org knew this and had been patching the YAML and gem parsing libraries to allow deserialization of classes on a whitelist.
Justicz explains his proof-of-concept exploit in detail in his advisory.
“For me, one of the takeaways here is that YAML is very powerful, and sometimes used in contexts where less expressive (but safer) interchange formats like JSON might be more appropriate,” he wrote. “Perhaps in the future, YAML.load could be modified to take a whitelist of classes as an optional parameter, making the deserialization of complex objects an opt-in behavior.”
Patterson said the fix involved adding code in order to monkey patch RubyGems in order to allow only safe types be deserialized.
“Since this monkey patch is patching RubyGems and not RubyGems.org, we decided it would be better to patch RubyGems itself,” Patterson said. “This is why the CVE was issued for RubyGems, and a patch created for RubyGems.”