近日JFrog的安全研究团队披露了Apache Cassandra中的一个RCE(远程代码执行)漏洞,该漏洞被分配给了CVE-2021-44521 (CVSS 8.4)。这个Apache安全漏洞很容易被利用,并且有可能对系统造成严重破坏,但幸运的是,它只体现在 Cassandra 的非默认配置中。
Cassandra 是一个高度可扩展的分布式 NoSQL 数据库,由于其分布式特性的优势,它非常受欢迎。 Cassandra 被 Netflix、Twitter、Urban Airship、Constant Contact、Reddit、Cisco、OpenX、Digg、CloudKick、Ooyala 等企业使用。 Cassandra 在 DevOps 和云原生开发圈中也非常受欢迎,这从它对 CNCF 项目(例如 Jaeger)的支持可以看出。
一些公司甚至提供基于 Cassandra 的基于云的一站式解决方案,例如 DataStax(一种无服务器、多云 DBaaS)。
在这篇文章中,我们将介绍研究人员是如何发现 RCE 安全漏洞的背景,提供有关 PoC 漏洞利用的详细信息,并分享建议的修复和缓解选项。
UDF 和 Nashorn
Cassandra 提供了创建用户定义函数 (UDF) 以执行数据库中数据的自定义处理的功能。
Cassandra UDF 默认可以用 Java 和 JavaScript 编写。在 JavaScript 中,它使用 Java 运行时环境 (JRE) 中的 Nashorn 引擎,这是一个运行在 Java 虚拟机 (JVM) 之上的 JavaScript 引擎。
在接受不受信任的代码时,不保证 Nashorn 是安全的。因此,任何允许此类行为的服务都必须始终将 Nashorn 执行包含在沙箱中。
例如,运行以下 Nashorn JavaScript 代码允许执行任意 shell 命令 -
Cassandra 的开发团队决定围绕 UDF 执行实现一个自定义沙箱,该沙箱使用两种机制来限制 UDF 代码:
1.使用白名单和黑名单的过滤机制(只允许匹配白名单和不匹配黑名单的类):
2.使用 Java 安全管理器来强制执行代码的权限(在默认配置中,不授予权限)
如 NashornEscape项目实施沙箱来保护 Nashorn 代码执行。
通过 Nashorn 访问 Java 类
Nashorn 引擎通过使用 Java.type 提供对任意 Java 类的访问。
例如: var System = Java.type("java.lang.System") 将允许我们使用 System 变量访问 java.lang.System 数据包。
具有足够权限的用户可以使用 create函数查询创建任意函数。例如,此函数会将其输入打印到控制台:
用户可以使用以下 SELECT 查询调用该函数。
CVE-2021-44521什么时候会被利用
当我们研究 Cassandra UDF 沙箱实现时,我们意识到特定(非默认)配置选项的混合可以让我们滥用 Nashorn 引擎、逃离沙箱并实现远程代码执行,这就是CVE-2021-44521 的漏洞。
当 cassandra.yaml 配置文件包含以下定义时,Cassandra 部署容易受到 CVE-2021-44521 的攻击:
请注意,这些是唯一需要的非默认配置选项,因为启用 UDF 时,所有用户都可以创建和执行任意 UDF,这包括默认启用的匿名登录 (authenticator=AllowAllAuthenticator)。
请注意,Cassandra 也可以通过 Config.java 配置文件进行配置,该文件支持与上述相同的标志。
前两个标志启用对 Java 和 JavaScript的 UDF 支持。
enable_user_defined_functions_threads 是利用 CVE-2021-44521 的关键。
Cassandra 还支持在 UDF 中使用的其他脚本语言,例如 Python。
JFrog 产品是否容易受到 CVE-2021-44521 的攻击?
JFrog 产品不受 CVE-2021-44521 攻击,因为它们不使用 Apache Cassandra。
解释 enable_user_defined_functions_threads
源代码(Config.java)如下:
enable_user_defined_functions_threads 默认设置为 true,这意味着每个调用的 UDF 函数都将在不同的线程中运行,并且具有没有任何权限的安全管理器,我们将在后面的部分中介绍针对此默认配置的 DoS 攻击。
当该选项设置为 false 时,所有调用的 UDF 函数都在 Cassandra 守护程序线程中运行,该线程具有具有某些权限的安全管理器。我们将展示如何滥用这些权限来实现沙箱逃逸和 RCE。
请注意,源代码中的文档暗示关闭该值是不安全的,但由于拒绝服务漏洞。我们将演示关闭此值直接导致远程代码执行。
RCE通过沙箱逃逸
UDF 沙箱不会直接允许我们在服务器上执行代码,例如通过调用 java.lang.Runtime.getRuntime().exec()。
在研究沙箱实现时,我们发现我们可以使用至少两种方式逃离沙箱:
滥用 Nashorn 引擎实例;
java.lang.System 的 load 和 loadLibrary 函数;
由于 Cassandra 的类过滤机制允许访问 java.lang.System,所以这两种方法都可以用来逃避沙箱。
第一种方法:滥用 Nashorn 引擎实例
为了完全逃离沙箱,我们必须:
1.禁用类过滤机制;
2.在没有安全管理器的情况下运行;
当 enable_user_defined_functions_threads 设置为 false 时,我们的 UDF 代码运行在 daemon 线程中,该线程具体有调用 setSecurityManager 的权限!这立即允许我们关闭安全管理器,所以现在我们只需要绕过类过滤机制。
在 Nashorn 上运行 JavaScript 代码时,我们可以使用 this.engine 来访问 Nashorn 实例引擎。正如 Beware the Nashorn 博客中所述,这实际上允许我们通过创建一个不受类过滤机制限制的新脚本引擎来绕过任何类过滤器。
但是,较新的 Java 版本(8u191 及更高版本)已收到缓解措施,可在安全管理器处于活动状态时阻止访问 this.engine。
我们可以调用 setSecurityManager 来禁用安全管理器,然后访问 this.engine。
PoC 查询结果如下所示:
此查询将关闭安全管理器,将其设置为空,然后创建一个不受类过滤机制限制的新脚本引擎,在Cassandra服务器上运行任意shell命令。
执行 PoC 是为了在 Cassandra 服务器上创建一个名为“hacked”的新文件:
第二种方法:java.lang.System的load和loadLibrary函数
除了 Nashorn 转义技术之外,还有更多的库函数未被类过滤器过滤,并且在安全管理器关闭时可能被滥用于代码执行。
例如,java.lang.System 的 load 方法允许我们通过指定绝对路径来加载任意共享对象。
假设攻击者可以以某种方式将恶意共享对象文件上传到易受攻击的系统(只要攻击者知道上传文件的完整路径,受害者设备上的上传目录是什么并不重要),可以使用加载方法加载库,它可以运行任意代码作为其入口例程的一部分。
其他值得注意的漏洞
当我们在一些非默认配置(尽管合理)上运行Cassandra和相关工具)时,我们发现并披露了一些值得一提的漏洞。这些选项被记录为不安全,但我们想强这些漏洞及其确切影响,以便供应商不要在可公开访问的网络中部署此类配置。
Cassandra UDF 拒绝服务
当启用UDF函数并将enable_user_defined_functions_threads标志设置为true(默认值)时,恶意用户可以创建一个将关闭Cassandra守护进程的UDF,这是由UDF超时机制的行为引起的,该机制由user_defined_function_fail_timeout标志控制。
如果 UDF 函数运行超过分配的时间,则整个 Cassandra 守护程序将被闭(不仅仅是运行 UDF 的线程)。尽管这是记录在案的行为,但攻击者可以通过创建一个使用 while(true) 永远循环的函数来轻松地对整个数据库进行 DoS。
目前还没有什么直接方法缓解此漏洞(将 user_function_timeout_policy 标志从 die 更改为 ignore 可能会导致更严重的 DoS),尽管可以通过确保低权限用户无法创建任意 UDF 来间接缓解该漏洞。
通过不安全对象反序列化的StressD RCE
Cassandra 包含一个名为 cassandra-stressd 的工具,用于对数据库进行压力测试。该工具已被 Apache 记录为“不安全”工具;
这是一个面向网络的工具,默认情况下只监听 localhost 接口;
但是,这个工具可以通过提供-h标志和IP地址来监听任何接口;
来自套接字的输入直接由 StressServer.java 反序列化,这意味着攻击者可能会提供一个序列化的“gadget”对象,导致反序列化时执行任意代码:
这个漏洞的利用取决于正在运行的 Cassandra 实例的类路径中的可用类。
我们敦促用户确保他们没有运行带有指向外部接口的 -h 标志的 cassandra-stressd 工具。
如何修复 CVE-2021-44521?
我们强烈建议所有 Apache Cassandra 用户升级到以下版本,它可以缓解 CVE-2021-44521:
3.0.x 用户应升级到 3.0.26
3.11.x 用户应升级到 3.11.12
4.0.x 用户应升级到 4.0.2
Apache 的修复添加了一个新标志——allow_extra_insecure_udfs(默认为 false),它不允许关闭安全管理器并阻止对 java.lang.System 的访问。
如果用户希望他们的udf与沙箱外的元素交互(并且不介意潜在的安全风险),可以打开该标志来恢复原来的行为(不推荐!)。
如何缓解 CVE-2021-44521?
对于无法升级Cassandra实例的用户,我们建议采取以下缓解措施:
如果UDF没有被积极使用,可以通过将enable_user_defined_functions设置为false(这是默认值)来完全禁用它们;
如果需要 UDF,请将 enable_user_defined_functions_threads 设置为 true(这是默认值);
通过删除以下权限来删除为不受信任的用户创建、更改和执行函数的权限:ALL FUNCTIONS、ALL FUNCTIONS IN KEYSPACE 和 FUNCTION 用于 CREATE、ALTER 和 EXECUTE 查询。
这可以使用以下查询来完成,方法是将role_name替换为所需的角色。
总结
最后,我们强烈建议将 Cassandra 升级到最新版本,以避免CVE-2021-44521威胁。
本文翻译自:https://jfrog.com/blog/cve-2021-44521-exploiting-apache-cassandra-user-defined-functions-for-remote-code-execution/如若转载,请注明原文地址