HackTheBox: Soccer
偵察 — nginx:80 + WebSocket:9091 + /tiny ディレクトリ発見
ポートスキャン
HTTP (80) が soccer.htb へリダイレクト。9091 は未知サービスだが WebSocket と判明。/etc/hosts に 10.129.22.189 soccer.htb を追加する。
ディレクトリ列挙 — /tiny/ 発見
/tiny/ ディレクトリを発見。ブラウザでアクセスすると Tiny File Manager 2.4.3 のログイン画面が表示される。
WebSocket ポート 9091 の確認
9091 は Node.js WebSocket サーバ。サブドメイン soc-player.soccer.htb が確認できる。/etc/hosts に追記しブラウザでアクセスするとチケット確認フォームが表示される。
Tiny File Manager 2.4.3 — デフォルト認証情報 → nginx 設定読み取り
デフォルト認証情報でログイン
Tiny File Manager のデフォルト認証情報は admin:admin@123。変更されていない場合そのままログインできる。ログイン後はファイルシステム全体をブラウズ・ダウンロード・アップロード可能。
nginx 設定ファイルでサブドメインを確認
nginx の設定から soc-player.soccer.htb:9091 がチケット確認 WebSocket の実体と判明。このエンドポイントが次の SQLi の対象になる。
PHP webshell のアップロード試行
ファイルのアップロードは成功 ({"status":"success"}) するが、http://soccer.htb/tiny/uploads/shell.php は nginx が 404 を返す。nginx の location ブロックが /tiny/uploads/ を serve しない設定になっているため webshell 経路は封じられている。
WebSocket Blind SQLi — sqlmap → soccer_db.accounts → player 認証情報
チケット確認エンドポイントの脆弱性確認
id フィールドが SQL クエリに直接渡されており、Blind SQLi が成立。OR 1=1 を注入すると常に “Ticket Exists” が返る。
sqlmap による WebSocket Blind SQLi
sqlmap は WebSocket エンドポイントを直接対象にできる。ws:// URL と --data で JSON ペイロードを指定し、* がインジェクションポイントを示す。Time-based Blind SQLi で数分かかる。
💎 取得認証情報
player : PlayerOftheMatch2022
SSH ログイン → user.txt 取得
SSH 接続確認
user.txt 取得
🚩 user.txt
d5322eb390859e8e2dfb429fab51d6d1
doas + dstat Python plugin → root.txt
doas SUID と doas.conf の確認
doas は OpenBSD 由来の sudo 互換ツール。permit nopass player as root cmd /usr/bin/dstat は「player ユーザーがパスワードなしで root として /usr/bin/dstat を実行できる」という意味。
dstat プラグインディレクトリの権限確認
ディレクトリの所有グループが player で rwx 権限あり。player は任意のファイルをこのディレクトリに書き込める。dstat は /usr/local/share/dstat/dstat_*.py を Python プラグインとして import する。
悪意のある dstat プラグインを作成
dstat はプラグインを import する際、モジュールレベルのコードを即座に実行する。dstat_plugin クラスが未定義でもモジュールのロード時に os.system() が走る — “fail to load” エラーが出ても攻撃コードは実行済み。
doas で dstat を root 権限実行
“Module dstat_pwn failed to load” と出るが、os.system() はインポート時に実行済み。/tmp/.rf に root.txt がコピーされているため cat でフラグを読める。
🚩 root.txt
fac232af4a3012ce510125b626f3fc24
全体まとめと防御側の学び
攻撃チェーンの全体像
| 段階 | 使った脆弱性 | 取得したもの |
|---|---|---|
| 1 | gobuster / nmap でのサービス発見 | /tiny/ (TFM 2.4.3) と soc-player.soccer.htb:9091 の特定 |
| 2 | TFM デフォルト認証情報 admin:admin@123 |
nginx 設定ファイル参照 → サブドメイン確認 |
| 3 | WebSocket Blind SQLi (id フィールド) | player:PlayerOftheMatch2022 |
| 4 | 取得認証情報での SSH ログイン | user.txt: d5322eb390859e8e2dfb429fab51d6d1 |
| 5 | doas + dstat Python plugin injection | root.txt: fac232af4a3012ce510125b626f3fc24 |
防御側の学び
- デフォルト認証情報の変更: Tiny File Manager に限らず、デフォルトパスワードを使い続けることは最初の侵入口になる。インストール後即座に変更し、定期的にローテーションする。
- SQLi 対策: ユーザー入力を SQL クエリに直接渡さない。プリペアドステートメント (parameterized queries) を使う。WebSocket 経由のリクエストも同様に検証が必要。
- nginx の serve 範囲制限: ファイルアップロード先のディレクトリを nginx の公開スコープから外すことで webshell 経由の初期侵入は防げる(本機ではこれが機能していた)。
- doas / sudo の最小権限:
permit nopass ... cmd /usr/bin/dstatのような設定は、プラグインディレクトリへの書き込み権限と組み合わさると完全な権限昇格になる。コマンドのホワイトリスト制御に加えて、プラグインディレクトリの権限も厳格に管理する。 - 機密情報のアクセス制御: nginx の設定ファイル (
/etc/nginx/sites-enabled/) を TFM 経由で閲覧できる状況は情報漏えいにつながる。Web 公開ディレクトリはサービスに必要な最小限に制限する。

