
مختبر تجريبي آمن افتراضيًا يوضح كيف يمكن لتحصين الحاويات (صور distroless، التشغيل بغير صلاحيات root، نظام ملفات للقراءة فقط، أسرار محقونة في وقت التشغيل) أن يحيد ثغرة RCE حرجة في Next.js/React Server Actions (CVE-2025-55182 "React2Shell")، مع عرض نشر آمن وغير آمن جنبًا إلى جنب وسجلات الاستغلال.
يوضح هذا المشروع ثغرة خطيرة لتنفيذ التعليمات البرمجية عن بُعد (RCE) في تطبيق Next.js (وتحديدًا عبر Server Actions) وكيف أن تقوية البنية التحتية تُبطل الهجوم بفعالية حتى عندما تظل ثغرة الكود قائمة.
يقارن هذا المشروع بين نشر "غير آمن" قياسي ونشر "آمن" مُقوّى باستخدام صور Distroless وأنظمة ملفات للقراءة فقط.
ثغرات البرمجيات أمر لا مفر منه. عندما يفشل الكود، يجب أن تمنع بنيتك التحتية المهاجم من توسيع نطاق وجوده.
توجد ثغرة RCE حرجة (CVE-2025-55182، والمعروفة بـ React2Shell) في تنفيذ React Server Components (RSC) المستخدم في Next.js.
spawnSync) دون مصادقة.curl, wget, ls, cat) لسرقة الأسرار أو تنزيل برمجيات خبيثة.
child_process.spawnSync() في Node.js. وينفّذ هذا الثنائيات مباشرة، دون الحاجة إلى شل (/bin/sh).chmod +x)، ثم يشغّلها.تُظهر السجلات التالية كيف تبدو محاولات الهجوم من منظور التطبيق. يبرز هذا التباين بوضوح فعالية الإجراءات الأمنية.
logs/server.safe.log)تُظهر السجلات حالات فشل متكررة (ENOENT).
spawnSync تشغيل ls, id, curl. صورة Distroless ببساطة لا تحتوي على هذه الثنائيات. الأمر لا يتعلق فقط بغياب الشل؛ فالأدوات نفسها غير موجودة.[Instrumentation] Logging initialized. Writing to: /app/logs/server.safe.log
⨯ Error: NEXT_REDIRECT
... digest: '`{"step":"1. Write Initial Chunk to /tmp/hello_test","success":true}`'
⨯ Error: NEXT_REDIRECT
... digest: '`{"step":"2. Verify Binary was Written","verification":{...},"success":true}`'
⨯ Error: NEXT_REDIRECT
... digest: '`{"step":"4. Execute Binary","stdout":"","stderr":"","error_obj":{"message":"spawnSync /tmp/hello_test EACCES","code":"EACCES"},"success":true}`'
logs/server.unsafe.log)تؤكد السجلات نجاح تنفيذ الأوامر والتلاعب بنظام الملفات.
[Instrumentation] Logging initialized. Writing to: /app/logs/server.unsafe.log
⨯ Error: NEXT_REDIRECT
... digest: '`{"step":"1. Write Initial Chunk to /tmp/hello_test","success":true}`'
⨯ Error: NEXT_REDIRECT
... digest: '`{"step":"4. Execute Binary","stdout":"Hello from Go binary!\\n","stderr":"","error_obj":null,"success":true}`'
⨯ Error: NEXT_REDIRECT
... digest: '`{"command":"id","args":[],"stdout":"uid=0(root) gid=0(root) ...","stderr":"","status":0,"signal":null}`'
⨯ Error: NEXT_REDIRECT
... digest: '`{"command":"cat","args":["/app/.env"],"stdout":"","stderr":"cat: can\'t open \'/app/.env\': No such file or directory\n","status":1,"signal":null}`'
(ملاحظة: في سجلات غير الآمن، يفشل أمر cat /app/.env أعلاه لأن الملف يُسمى .env في الجذر، لكن ls -la في السجلات الكاملة سيكشف هيكل الدليل.)
محاولة تشغيل أوامر شل قياسية.
id, ls, cat .env، والوصول إلى بيانات حساسة.spawnSync /bin/sh ENOENT. لا يوجد شل لتنفيذ الأوامر.محاولة تجاوز "الأدوات المفقودة" عن طريق رفع ثنائية مخصصة.
/tmp/malware.chmod +x.EROFS: read-only file system.هل يمكن للمهاجم تحميل ثنائية في متغير وتنفيذها مباشرة من الذاكرة؟
global.payload = "...")، ثم تنفيذها.child_process في Node.js (spawn, exec) تتطلب مسار ملف. لا يمكنها تنفيذ مخزن مؤقت أو سلسلة نصية مباشرة.memfd_create (استدعاء نظام لإنشاء ملف مجهول في الذاكرة).memfd_create بشكل أصلي. يتطلب الوصول إليه إضافة C++ (مثل ffi-napi) مثبتة مسبقًا في node_modules.gcc, make)، لا يمكن للمهاجم بناء هذه الإضافة في الوقت الفعلي.صور "Distroless" تحتوي فقط على تطبيقك وتبعيات وقت التشغيل الخاصة به. لا تحتوي على مديري حزم أو شل أو أدوات UNIX القياسية.
ls) أو تنزيل الملفات (curl) أو تصعيد الامتيازات بسهولة.قم بتكوين بيئة تشغيل الحاويات لديك لتركيب نظام الملفات الجذر كقراءة فقط.
docker-compose.yml:
read_only: true
tmpfs:
- /tmp:noexec # CRITICAL: explicitly block execution!
/tmp (كتابة ناجحة)، لكن التنفيذ يفشل مع EACCES (تم رفض الإذن) بسبب علامة noexec. وهذا يوازن بين الوظيفة (tmp قابل للكتابة) والأمان.لا تضع ملفات .env في صور الحاويات الخاصة بك. إذا كان بإمكان المهاجم قراءة الملفات (مثل cat .env)، فستتعرض أسرارك للخطر.
environment في Docker).ابدأ البيئة:
يتم تعريف كل من التطبيق الآمن وغير الآمن في ملف docker-compose.yml واحد.
docker compose up --build -d
شغّل الاستغلالات: يمكنك تشغيل الاستغلالات ضد المنافذ المحددة لرؤية الفرق.
استهداف التطبيق غير الآمن (المنفذ 3001):
# 1. Standard RCE (LotL) - SUCCEEDS
python exploit/poc.py http://localhost:3001
# 2. Advanced Attack (BYOL) - SUCCEEDS
python exploit/poc_advanced.py http://localhost:3001
استهداف التطبيق الآمن (المنفذ 3000):
# 1. Standard RCE (LotL) - FAILS (ENOENT)
python exploit/poc.py http://localhost:3000
# 2. Advanced Attack (BYOL) - FAILS (EACCES/EROFS)
python exploit/poc_advanced.py http://localhost:3000
التنظيف:
docker compose down
| الميزة | ❌ البيئة غير الآمنة (المنفذ 3001) | ✅ البيئة الآمنة (المنفذ 3000) |
|---|
| الصورة الأساسية | node:20-alpine (تحتوي على ls, curl, wget, إلخ.) | gcr.io/distroless/nodejs20-debian12 (لا شل، ولا أدوات) |
| نظام الملفات | قابل للكتابة (الافتراضي القياسي لـ Docker) | للقراءة فقط (read_only: true) |
| الأسرار | ملف .env على القرص (عرضة لأمر cat .env) | متغيرات البيئة (تُحقن وقت التشغيل) |
| المستخدم | root (الافتراضي) | غير الجذر (تُطبقه Distroless) |