
HackTheBox「Nexus」の権限昇格に関するPoCおよび解説: root権限で実行されるGiteaテンプレート同期サービスが、細工されたGitオブジェクトを介したパストラバーサルに対して脆弱。教育目的のみ。
偽造 Git オブジェクトを介した Gitea テンプレート同期のパストラバーサル → root
HackTheBox マシン Nexus 向けの概念実証(PoC)権限昇格エクスプロイト。
root 所有の systemd サービスが Gitea の テンプレート リポジトリをディスクへ同期する際に、
エントリ名をサニタイズしていないため、認証済みの低権限ユーザーがディレクトリトラバーサルを
通じて root として任意のファイルを書き込める — ここでは /root/.ssh/authorized_keys に
SSH 鍵を植え付けるために使用する。
このコードは 教育目的および許可されたセキュリティテストのみ — つまり HackTheBox などの ラボ環境、またはあなたが所有するか、明示的な書面による許可を得てテストするシステム — に 提供される。あなたが管理していないシステムに対する不正使用は 違法 である。作者は 誤用に対して一切の責任を負わない。
Nexus マシンが HackTheBox 上でまだ アクティブ な場合、このエクスプロイトを公開または 共有しないこと — HTB のルールはアクティブなマシンへの解答の配布を禁止している。
| クラス | パストラバーサル (CWE-22) → ローカル権限昇格 |
| コンポーネント | gitea-template-sync.service (カスタム /etc/gitea/template-sync.py) |
| 実行ユーザー | root、gitea-template-sync.timer により約60秒ごとに起動 |
| 根本原因 | Git ツリーオブジェクトから取得した未サニタイズの名前に対する os.path.join() |
| 影響 | 認証済み低権限ユーザー → root |
同期スクリプトは Gitea で テンプレート としてフラグ付けされたリポジトリからファイルを 読み取り、ローカルファイルシステムへ書き込む。書き込み先パスは概ね次のように構築される:
dest = os.path.join(base_dir, name) # name comes straight from the Git tree
open(dest, "w").write(content)
os.path.join() は .. シーケンスを 無効化しない。したがって、名前がトラバーサルパス
(例: ../../../../../root/.ssh/authorized_keys) であるツリーエントリは、特権プロセスに
意図されたディレクトリの 外側 へ書き込ませる。
Git はコンテンツと名前を別々に保存する:
name → object をマッピングする (ファイル名はここにある);ツリーエントリ内のファイル名は単なるテキストであるため、.. に なり得る — しかし標準の
Git クライアントは、まさにこの攻撃を防ぐために、そのようなエントリの作成を 拒否する。
この PoC は、生の Git オブジェクト を .git/objects/ に直接書き込み (SHA-1 id を手計算で)、
refs/heads/main を手動で細工することで、そのクライアント側チェックを回避する。プッシュされた
リポジトリには .. という名前のツリーエントリが含まれ、root 同期プロセスがそれを解決して
辿る。
www-data として RCE。.env 内の平文認証情報がシステムパスワードとして再利用される → 低権限ユーザーとして SSH。root。3段階すべてに共通するテーマ: 検証なしに攻撃者制御のデータを信頼する特権プロセス (偽装された MIME タイプ、再利用されたパスワード、未サニタイズのファイル名)。
http://localhost:3000 で到達可能であること。git、python3、curl、ssh が利用可能であること (ボックスのデフォルト)。chmod +x nexus_privesc.sh
./nexus_privesc.sh -t <TARGET_IP> -u <GITEA_USER> -p <GITEA_PASS> [-d DEPTH]
例:
./nexus_privesc.sh -t 10.129.21.192 -u jones -p 'REDACTED' -d 5
/tmp/.exploit_key)。/root/.ssh/authorized_keys にマッピングされる .. トラバーサルツリーをエンコードした
生の Git オブジェクトを偽造する。コンテンツは攻撃者の公開鍵。root としてログインする。ターゲット上で同期を監視するには:
tail -f /var/log/template-sync.log
成功した実行では次のような行がログに記録される:
synced: ../../../../../root/.ssh/authorized_keys
DEPTH の調整DEPTH は、同期/ステージングディレクトリからファイルシステムルート (/) まで登るのに
必要な .. の階層数である。ログ上で同期が成功しているのに root SSH が失敗する場合、
トラバーサルが誤った階層に着地している — -d 4 または -d 6 で再試行すること。正確な値は
/etc/gitea/template-sync.py 内のステージングパスを読むことで確認できる。
信頼できない名前から os.path.join() だけでファイルシステムパスを構築しないこと。
パスを正規化して制限する。例:
base = os.path.realpath(base_dir)
dest = os.path.realpath(os.path.join(base, name))
if not dest.startswith(base + os.sep):
raise ValueError("path traversal blocked")
..、絶対パス、またはパス区切り文字を含むツリーエントリ名を拒否する。
同期サービスを root ではなく 専用の低権限アカウント で実行する。
Gitea で receive.fsckObjects = true を有効にして、不正な形式のプッシュされたオブジェクトを拒否する。
<your name / handle> — HackTheBox での教育目的使用向け。
| フラグ | 説明 | デフォルト |
|---|
-t | ターゲット IP (最終的な root SSH 用) | — (必須) |
-u | Gitea ユーザー名 | — (必須) |
-p | Gitea パスワード | — (必須) |
-d | 同期ディレクトリから / に到達するための .. の階層数 | 5 |