漏洞簡介
Apache Kafka是一個(gè)分布式數(shù)據(jù)流處理平臺(tái),可以實(shí)時(shí)發(fā)布、訂閱、存儲(chǔ)和處理數(shù)據(jù)流。Kafka Connect是一種用于在kafka和其他系統(tǒng)之間可擴(kuò)展、可靠的流式傳輸數(shù)據(jù)的工具。攻擊者可以利用基于SASLJAAS 配置和SASL 協(xié)議的任意Kafka客戶端,對Kafka Connect worker 創(chuàng)建或修改連接器時(shí),通過構(gòu)造特殊的配置,進(jìn)行JNDI 注入來實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行。
影響版本
2.4.0<=Apache kafka<=3.3.2
修復(fù)方案
更新Apache Kafka至官方最新版本
環(huán)境搭建
通過https://github.com/vulhub/vulhub搭建
漏洞復(fù)現(xiàn)
exp可參考:
https://github.com/projectdiscovery/nuclei-templates/blob/5d90e8275084b0ae9166ec38cacd22e5a5a94fb8/http/vulnerabilities/apache/apache-druid-kafka-connect-rce.yaml
發(fā)起攻擊請求:
構(gòu)造payload ,執(zhí)行新建/tmp/test.txt文件

驗(yàn)證漏洞存在,文件新建成功

開啟RASP后發(fā)起攻擊:
在業(yè)務(wù)優(yōu)先模式下,RASP會(huì)出現(xiàn)JNDI注入的告警,攔截最終的命令執(zhí)行

堆棧信息為

在防護(hù)模式下將直接在JNDI注入處被攔截

堆棧信息為

漏洞分析
開始
org.apache.kafka.clients.producer.KafkaProducer#KafkaProducer(java.util.Properties)

跟進(jìn)到
org.apache.kafka.clients.producer.KafkaProducer#KafkaProducer(java.util.Propertiesorg.apache.kafka.common.serialization.Serializer,org.apache.kafka.common.serialization.Serializer)

調(diào)用
org.apache.kafka.common.utils.Utils#propsToMap
對傳入對象進(jìn)行處理

將map型的對象傳入
org.apache.kafka.clients.producer.KafkaProducer#KafkaProducer(java.util.Maporg.apache.kafka.common.serialization.Serializerorg.apache.kafka.common.serialization.Serializer)

之后調(diào)用
org.apache.kafka.clients.producer.ProducerConfig#appendSerializerToConfig

將返回的newConfigs傳入
org.apache.kafka.clients.producer.ProducerConfig#ProducerConfig(java.util.Map)

將配置參數(shù)傳入
org.apache.kafka.clients.producer.KafkaProducer#KafkaProducer(org.apache.kafka.clients.producer.ProducerConfig,
org.apache.kafka.common.serialization.Serializerorg.apache.kafka.common.serialization.Serializerorg.apache.kafka.clients.producer.internals.ProducerMetadata,
org.apache.kafka.clients.KafkaClientorg.apache.kafka.clients.producer.internals.ProducerInterceptorsorg.apache.kafka.common.utils.Time)
need-to-insert-img

賦值后調(diào)用
org.apache.kafka.clients.producer.KafkaProducer#newSender
need-to-insert-img


調(diào)用到
org.apache.kafka.clients.ClientUtils#createChannelBuilder

賦值后調(diào)用
org.apache.kafka.common.network.ChannelBuilders#clientChannelBuilder
need-to-insert-img

這里對值做了一個(gè)判斷后調(diào)用
org.apache.kafka.common.network.ChannelBuilders#create



Create方法中得到map型的configs后進(jìn)行switch,得到SaslChannelBuilder類型channelBuilder的對象,switch結(jié)束后調(diào)用了
org.apache.kafka.common.network.SaslChannelBuilder#configure


org.apache.kafka.common.network.SaslChannelBuilder#configure
進(jìn)入循環(huán)后到
org.apache.kafka.common.security.authenticator.LoginManager#acquireLoginManager



判斷值后到
org.apache.kafka.common.security.authenticator.LoginManager#LoginManager


跟進(jìn)到
org.apache.kafka.common.security.authenticator.AbstractLogin#login

調(diào)用
javax.security.auth.login.LoginContext#login

調(diào)用
javax.security.auth.login.LoginContext#invokePriv

調(diào)用
javax.security.auth.login.LoginContext#invoke
進(jìn)行邏輯判斷后調(diào)用initialize方法


Initialize中得到userProvider

user.provider.url通過jndi提供

調(diào)用
com.sun.security.auth.module.JndiLoginModule#login

調(diào)用
com.sun.security.auth.module.JndiLoginModule#attemptAuthentication

通過
javax.naming.InitialContext#lookup(java.lang.String)
執(zhí)行userProvider的值


由于RASP對javax.naming.InitialContext.lookup調(diào)用做了防護(hù)策略檢測,所以會(huì)在此處攔截。
Reference
https://github.com/luelueking/Java-CVE-Lists#cve-2023-25194
https://blog.snert.cn/index.php/2023/04/04/cve-2023-25194-kafka-jndi-injection-%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/