An insecure deserialization vulnerability in the Ruby project could allow an attacker to execute arbitrary commands on a remote server by sending JSON data. According to the GitHub blog, these vulnerabilities occur when the deserialization process allows instantiation of arbitrary classes or class-like structures specified in the serialized data.
How unsafe deserialization works
In Ruby, unsafe deserialization vulnerabilities are often exploited through libraries that support polymorphism, such as the Oj JSON serialization library. By chaining multiple classes together, an attacker can execute code on the system under attack. These classes, known as gadgets, are combined into gadget chains to form larger attacks.
For example, when using the Oj library to deserialize JSON, you may be vulnerable if your project contains the following configuration:
data = Oj.load(untrusted_json)
The Oj library supports instantiation of classes specified in JSON by default, which can be disabled using: Oj.safe_load
Instead of.
To demonstrate how this works, consider the following class: SimpleClass
and hash
Method to execute command:
class SimpleClass
def initialize(cmd)
@cmd = cmd
end
def hash
system(@cmd)
end
end
The JSON payload that instantiates this class is:
"^o": "SimpleClass",
"cmd": "open -a calculator"
Load this JSON using: Oj.load
doesn’t trigger hash
Executes the method directly, but placing a class as a key inside the hash can trigger the method.
Oj.load(json_payload)
This will execute the command specified next. @cmd
Member variable.
Building a Detection Gadget
You can build a chain of detection gadgets to detect insecure deserialization vulnerabilities. For example, a class like this: Gem::Requirement
Can be used. hash
method to call to_s
About internal members. By generating the appropriate JSON payload, this chain can be triggered to detect vulnerabilities.
Detection gadgets can also be extended to a complete remote code execution (RCE) chain. This includes using classes and methods that are part of Ruby or its dependencies to execute arbitrary commands.
Avoid unsafe deserialization
To avoid these vulnerabilities, it is important to use a safe deserialization method. for example, Oj.safe_load
Instead of Oj.load
It can prevent instantiation of arbitrary classes. Additionally, tools like CodeQL can help detect unsafe deserialization by analyzing your source code for vulnerable patterns.
For developers with access to the source code, scanning code on GitHub using CodeQL can identify unsafe deserialization sinks. If you don’t have access to the source code, you can use detection gadgets to identify vulnerabilities remotely.
Understanding how insecure deserialization works and implementing secure coding practices can help prevent these vulnerabilities. For more detailed examples and detection methodology, see the original blog post on the GitHub blog.
Image source: Shutterstock