Site icon becoration

Run commands by sending JSON: learn how insecure deserialization vulnerabilities work in Ruby projects.

Attackers can execute arbitrary commands on a remote server simply by sending JSON if the code running has insecure deserialization vulnerabilities. But how is this possible?

In this article, we will describe how insecure deserialization vulnerabilities work and how to detect these flaws in Ruby projects. We will use the JSON serialization library for Ruby called Oj for our examples, although these vulnerabilities are not limited to this library. In the end, we will provide a link to a repository with sample exploits that work for Oj (JSON), Ox (XML), Psych (YAML), and Marshal (custom binary format), and explain how CodeQL can detect such vulnerabilities. Understanding how insecure deserialization works can help you avoid this type of errors without focusing on specific methods.

Building a detection chain for Oj

Many have a notion of how a deserialization vulnerability could be exploited, but we will delve into the details. We will show how to build an insecure deserialization detection gadget for Oj, a Ruby JSON deserialization library, that calls an external URL. This gadget is based on the work of William Bowling with universal deserialization gadgets adapted for Oj and Ruby 3.3.

  1. Start with a class

Most of the time, insecure deserialization vulnerabilities arise due to the deserialization library’s ability to support polymorphism, allowing instantiated classes specified in the serialized data. An attacker can chain these classes to execute code on the system. These useful classes are called gadgets, and the strings formed from them are called gadget chains. Traditionally, the serialization-deserialization of arbitrary constructs was considered a powerful feature, but in 2015 public perception changed with the discovery of Java deserialization vulnerabilities.

A Ruby project using the Oj library is vulnerable with a construct like:

data = Oj.load(untrusted_json)

Oj, by default, supports the instantiation of classes specified in JSON, although this feature can be disabled. To instantiate a class, like MyClass with a member field, the JSON would be:

via
  1. Maps, lists, getters, setters, and more

The vulnerability can be exploited using different methods depending on the language. For example, in Ruby, the hash method can be used instead of the initialize constructor method. Examples for different libraries in Ruby include:

  • Marshal: _load
  • Oj: hash
  • Ox: hash
  • Psych: hash, init_with
  • JSON: json_create
  1. Building a payload with gadgets

In our target project, we use classes available from the project itself or from Ruby. When deserializing in Oj, we can start the gadget chain with the hash method.

Imagine a simplified class like this:

class SimpleClass
  def initialize(cmd)
    @cmd = cmd
  end

  def hash
    system(@cmd)
  end
end

We use hash to execute the command open -a calculator. The JSON payload would be:

via

When loading this JSON with Oj.load(json_payload), the command will be executed and the calculator will open.

Extension to a universal RCE chain

To turn a detection into remote code execution, we need to manipulate existing class members like Gem::Source::Git that can execute commands. One solution involves using the zip binary based on GTFOBins, allowing command execution through zip and its arguments -TmTT.

Finally, we run a command like:

{
    "^o": "Gem::Resolver::SpecSpecification",
    "spec": {
        "^o": "Gem::Resolver::GitSpecification",
        "source": via,
        "spec": Referrer
    }
}

Detection using CodeQL

If you have access to the source code, CodeQL can detect insecure deserialization vulnerabilities with its user-controlled data deserialization query. This tool will show all the locations where unreliable data flows into insecure deserializers.

Summary and recommendations

This article showed how to detect and exploit insecure deserialization vulnerabilities in Ruby. Using GitHub CodeQL is the most effective way to identify these vulnerabilities in the source code. Gadgets were also provided to detect and exploit vulnerabilities without access to the source code, highlighting the importance of using secure deserializers in projects.

via: GitHub Security

{Source|via|Referrer}: MiMub in Spanish

Exit mobile version