JFrog’s Security Research team recently disclosed an RCE (remote code execution) issue in Apache Cassandra, which has been assigned to CVE-2021-44521 (CVSS 8.4). This Apache security vulnerability is easy to exploit and has the potential to wreak havoc on systems, but luckily only manifests in non-default configurations of Cassandra.
Cassandra is a highly scalable, distributed NoSQL database that is extremely popular due to the benefits of its distributed nature. Cassandra is used by enterprises such as Netflix, Twitter, Urban Airship, Constant Contact, Reddit, Cisco, OpenX, Digg, CloudKick, Ooyala, and more. Cassandra is also extremely popular in DevOps and cloud-native development circles, as can be seen by its support in CNCF projects (such as Jaeger).
Some companies even provide cloud-based turnkey solutions based on Cassandra, such as DataStax (a serverless, multi-cloud DBaaS).
In this blogpost, we present the background on how we discovered the RCE security vulnerability, provide details on a PoC exploit, and share the suggested fix and mitigation options.
UDFs and Nashorn
Cassandra offers the functionality of creating user-defined-functions (UDFs) to perform custom processing of data in the database.
Cassandra UDFs can be written by default in Java and JavaScript. In JavaScript it uses the Nashorn engine in the Java Runtime Environment (JRE) which is a JavaScript engine that runs on top of the Java Virtual Machine (JVM).
Nashorn is not guaranteed to be secure when accepting untrusted code. Therefore, any service that allows such behavior must always wrap the Nashorn execution in a sandbox¹.
For example, running the following Nashorn JavaScript code allows execution of an arbitrary shell command –
java.lang.Runtime.getRuntime().exec("touch hacked")
Cassandra’s development team decided to implement a custom sandbox around the UDF execution which uses two mechanisms to restrict the UDF code:
- A filtering mechanism using a whitelist and a blacklist (only classes that match the whitelist and don’t match the blacklist are allowed):
private static final String[] allowedPatterns = { "com/google/common/reflect/TypeToken", "java/io/IOException.class", "java/io/Serializable.class", "java/lang/", "java/math/", "java/net/InetAddress.class", "java/net/Inet4Address.class", ... private static final String[] disallowedPatterns = { "com/datastax/driver/core/Cluster.class", "com/datastax/driver/core/Metrics.class", "com/datastax/driver/core/NettyOptions.class", "com/datastax/driver/core/Session.class", "com/datastax/driver/core/Statement.class", "com/datastax/driver/core/TimestampGenerator.class", "java/lang/Compiler.class", "java/lang/InheritableThreadLocal.class", "java/lang/Package.class", "java/lang/Process.class", ...
- Usage of the Java Security Manager to enforce permissions of the executed code (in the default configuration, no permissions are granted)
¹Some projects such as NashornEscape implement a sandbox to secure Nashorn code execution
Accessing Java classes through Nashorn
The Nashorn engine gives access to arbitrary Java classes by using Java.type
.
For example: var System = Java.type("java.lang.System")
will allow us to access the java.lang.System
package by using the System
variable.
Users with sufficient permissions can create arbitrary functions by using the create function
query. For example, this function will print its input to the console:
create or replace function print(name text) RETURNS NULL ON NULL INPUT RETURNS text LANGUAGE javascript AS $$var System = Java.type("java.lang.System"); System.out.println(name);name$$;
Users can invoke the function using the following SELECT query.
select print(name) from table;
When can CVE-2021-44521 be exploited?
As we were researching the Cassandra UDF sandbox implementation, we realized that a mix of specific (non-default) configuration options could allow us to abuse the Nashorn engine, escape the sandbox and achieve remote code execution. This is the vulnerability that we reported as CVE-2021-44521.
Cassandra deployments are vulnerable to CVE-2021-44521 when the cassandra.yaml configuration file contains the following definitions:
enable_user_defined_functions: true
enable_scripted_user_defined_functions: true
enable_user_defined_functions_threads: false
Note that these are the only non-default configuration options required, since when enabling UDFs, all users are allowed to create and execute arbitrary UDFs. This includes anonymous logins, which are enabled by default (authenticator=AllowAllAuthenticator
).
Note that Cassandra is also configurable via the Config.java configuration fi