
استغلال إثبات المفهوم لـ CVE-2025-55182، يوضح RCE غير المصادق عليه في React Server Components عبر إلغاء التسلسل غير الآمن لـ Server Actions، مع خطوات إعادة إنتاج مفصلة وإرشادات التخفيف.
يحتوي هذا المستودع على نسخة طبق الأصل (PoC) من CVE-2025-55182، وهي ثغرة أمنية خطيرة في مكونات خادم React (RSC) تسمح بتنفيذ تعليمات برمجية عشوائية بدون مصادقة.
توجد الثغرة في طريقة إلغاء تسلسل مكونات خادم React لـ"إجراءات الخادم" من طلبات العميل. على وجه التحديد، فشلت دالة requireModule في التحقق من أن اسم التصدير المطلوب هو خاصية مباشرة للوحدة. سمح هذا للمهاجمين بالوصول إلى خاصية constructor للدوال المصدرة، والحصول على مرجع إلى منشئ الدوال العام Function، والذي يمكن استخدامه لتنفيذ تعليمات برمجية عشوائية.
يستخدم هذا الإثبات (PoC) بيئة Node.js بسيطة لعزل الثغرة في مكتبة react-server-dom-webpack، فقط للتأكد من أن الاستغلال يوضح الخلل في المكتبة نفسها، وليس سوء تكوين في إطار عمل.
npmnpm install
[!NOTE] ملف
package.jsonمثبت على الإصدار الضعيف19.0.0.
يقوم هذا البرنامج النصي بإعداد خادم HTTP خام يستخدم وقت تشغيل React الضعيف لفك تشفير الطلبات.
# tty1
node --conditions react-server server.js
في محطة طرفية منفصلة، شغّل الاستغلال. يرسل هذا حمولة Flight خبيثة إلى الخادم.
# tty2
node exploit.js id
يجب أن ترى مخرجات الأمر في الرد:
المخرجات المتوقعة:
Response: uid=0(root) gid=0(root) groups=0(root)
لماذا حدثت الثغرة؟
دالة requireModule في ReactFlightDOMServerNode.js كانت تثق ببساطة في أي name يرسله العميل. كانت تنفذ moduleExports[metadata[NAME]] دون التحقق مما إذا كانت هذه الخاصية مخصصة للإفصاح فعلاً. لذلك، إذا قال العميل "أخي، أريد هذه الخاصية"، كان الخادم يقول "طبعاً! تفضل يا صاح".
لماذا يعتبر السماح بالوصول إلى أي خاصية فكرة سيئة؟
لأنها تسمح لأي شخص بالوصول إلى سلسلة النموذج الأولي، حتى constructor، وهو أمر خطير جداً. إذا كانت الوحدة تُصدر دالة (مثل module.exports = () => {})، فإن constructor الخاص بها هو حرفياً منشئ الدوال العام Function.
لماذا يؤدي الحصول على منشئ Function إلى تنفيذ تعليمات برمجية (RCE)؟
بمجرد أن يحصل المهاجم على منشئ Function، يمكنه إساءة استخدام ميزة "إجراء الخادم المرتبط". يربط سلسلة تحتوي على تعليمات برمجية خبيثة به (ليصبح عملياً new Function("كود خبيث")). وعند تشغيلها، ينفذ الخادم أي كود يضعه المهاجم.
لماذا سيقوم React فعلياً بتشغيل تلك الدالة الخبيثة؟
لأن إجراءات الخادم يمكن تشغيلها بواسطة معرف. إذا صمم المهاجم حمولة تحتوي على معرف إجراء يشير إلى مرجع module#constructor الخاص به، يقوم React بحلّه كإجراء عادي وتنفيذه. هذا "الإجراء" هو في الواقع دالته الخبيثة.
لماذا لم يتم التحقق من أي من هذا؟
كان النظام يفترض أن id و name من بيانات تعريف مرجع الخادم سيشيران دائماً إلى تصديرات صالحة محددة من قبل المطور. لم يكن هناك فحص أمان مثل hasOwnProperty للتأكد من أن الخاصية المطلوبة هي تصدير حقيقي وليست شيئاً موروثاً من سلسلة النموذج الأولي.
server.js بدلاً من Next.js؟أستخدم server.js خام (ومساعد webpack-runtime.js) لتكوين وقت تشغيل مكونات خادم React يدوياً. يسمح لنا هذا بما يلي:
module.exports = fn). قد يغير المُجمِّع الحقيقي طريقة تغليف التصديرات حسب إعداداته.react-server-dom-webpack، وليس Next.js.react-server-dom-webpack أنه يعمل داخل حزمة Webpack. ملف webpack-runtime.js الخاص بنا يوفر له المتغيرات العامة التي يتوقعها (__webpack_require__, __webpack_chunk_load__).
هذا ليس محاكاة للثغرة، بل فقط توفير الحد الأدنى من وقت التشغيل الذي تحتاجه المكتبة للعمل فعلاً.كانت هناك مناقشات حول "إثباتات غير صالحة" تعمل فقط إذا تعمد المطور كشف أشياء خطيرة مثل child_process.exec.
إثباتنا ليس واحداً من هذه. إنه يعمل على إعداد عادي وآمن.
الدالة المكشوفة غير ضارة
يعرض التطبيق دالة بسيطة updateProfile تعيد سلسلة فقط ولا شيء مريب، لا أوامر شل.
الاستغلال يهرب بالكامل من تلك الدالة
تسمح الثغرة للمهاجم بتجاهل التصدير الآمن والانتقال مباشرة إلى updateProfile.constructor، وهو منشئ الدوال العام Function.
المشكلة الأساسية هي الوصول إلى الخاصية
كان يجب على React ألا يسمح بالوصول إلى .constructor. لم يقصد المطور كشف منشئ Function، بل قام إلغاء التسلسل غير الآمن بذلك نيابة عنه.
الشرط الوحيد الحقيقي هو أن تصدر الوحدة دالة مباشرة (module.exports = fn)، وهو أمر شائع جداً في CommonJS والعديد من إعدادات المُجمِّع.
تقوم الحمولة في exploit.js بصياغة رسالة Flight من React تحتوي على ثلاث قطع:
id: "user-profile-action#constructor"، بمعنى "أعطني المنشئ".bound: تشير إلى القطعة 2، التي تحتوي على الوسائط.["console.log('nice try, diddy!')"]: سلسلة التعليمات البرمجية الخبيثة.عندما يقوم React بإلغاء تسلسل هذا:
user-profile-action..constructor => يحصل على الدالة العامة Function.new Function("console.log('nice try, diddy!')")وهذا هو تنفيذ التعليمات البرمجية (RCE)!
قم بالترقية فوراً إلى الإصدارات المصححة:
react-server-dom-webpack >= 19.0.1react-server-dom-parcel >= 19.0.1react-server-dom-turbopack >= 19.0.1يقدم التصحيح فحوصات hasOwnProperty لمنع الوصول إلى الخصائص الموروثة ويقيد تحميل ملفات base64.
إذا قمت بتشغيل هذا الإثبات ضد إصدار مصحح، سيتعطل الخادم أو يظهر خطأ:
$ node --conditions react-server server.js
Listening on http://localhost:3000
/path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726
resolvedValue = resolvedValue.bind.apply(
^
TypeError: Cannot read properties of undefined (reading 'bind')
at /path/to/CVE-2025-55182/node_modules/react-server-dom-webpack/cjs/react-server-dom-webpack-server.node.development.js:2726:43
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
Node.js v20.19.3
هذا يؤكد أن الاستغلال فشل في الوصول إلى خاصية constructor (أرجعت undefined بدلاً من Function)، وبالتالي فشلت استدعاء .bind اللاحق.
هذا الكود لأغراض تعليمية واختبارية فقط. لا تستخدم هذا الاستغلال ضد أنظمة لا تملكها أو ليس لديك إذن صريح لاختبارها.
مُصدَر بموجب DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE.