
معمل Docker لـ PoC: ربط تجاوز رفع الملفات + XSS المخزن لإنشاء حسابات إدارية. مورد تعليمي لمختبري الاختراق.
تطبيق ويب ضعيف عن قصد يوضح كيف يرتبط تجاوز رفع الملف مع XSS المخزّن لإنشاء حسابات مدير خلفية، حتى مع وجود حماية CSP وCORS وCSRF.
المقالة كاملة: مدونة KurtiseBear
هذا مختبر تعليمي للتدريب على الأمن الدفاعي. لا تنشره في أي مكان يمكن الوصول إليه علنًا.
يحتوي التطبيق على ضوابط أمنية حقيقية:
'self' (ولكن مع السماح بـ 'unsafe-inline' و 'unsafe-eval')مُهاجم لديه حساب مستخدم بامتيازات منخفضة يربط بين ثغرتين لتجاوزها جميعًا:
تجاوز رفع الملف – يقتصر نموذج الرفع على .pdf عبر خاصية accept من جانب العميل، لكن الخادم لا يقوم بأي تحقق من نوع الملف. يقوم المهاجم برفع ملف يحتوي على JavaScript. يقوم نقطة نهاية التحميل بتقديمه من نفس المصدر، لذا لا تمنعه CSP وCORS.
.jsXSS مخزّن عبر موضوع الرسالة – تقوم ميزة المراسلة بتخزين إدخال المستخدم دون تعقيم. يعرض صندوق الوارد الخاص بالمشرف موضوع الرسالة كـ HTML خام. يستخدم حمولة XSS معالج `` لجلب البرنامج النصي المرفوع وتنفيذه عبر eval(). تسمح CSP بذلك لأن 'unsafe-inline' و 'unsafe-eval' مسموح بهما.
غياب CSRF في نقطة نهاية API – لا تتحقق API إدارة المستخدم (/api/manage-user.php) من رموز CSRF، على الرغم من أن نقاط نهاية النماذج تفعل ذلك. تستدعي حمولة XSS هذه API باستخدام جلسة المشرف من نفس المصدر. حتى لو كان CSRF موجودًا، يمكن لـ JavaScript من نفس المصدر قراءة الرمز من DOM.
النتيجة: عندما يفتح المشرف صندوق الوارد الخاص به، ينطلق XSS، ويقوم JavaScript بإنشاء حساب مدير خلفي باستخدام جلسة المشرف. جميع الدفاعات موجودة وفعالة. يعمل السلسل لأنه لا يغادر المصدر أبدًا.
docker-compose up -d
انتظر 10-15 ثانية حتى يتم تهيئة MySQL، ثم قم بزيارة http://localhost:8080
| الدور | البريد الإلكتروني | كلمة المرور |
|---|---|---|
| مشرف | [email protected] | admin |
| مستخدم | [email protected] | user |
انتقل إلى http://localhost:8080 وسجل الدخول باستخدام [email protected] / user.
اذهب إلى رفع الملفات. يقول النموذج "PDF فقط" لكنه يفرض ذلك فقط من جانب العميل. إما:
accept=".pdf" من حقل الملف، أوقم برفع payload.js المقدم (أو الخاص بك). لاحظ معرف الملف الذي تم إرجاعه (مثل 1).
الملف المرفوع يُقدَّم الآن من /api/download.php?file_id=1 على نفس المصدر. لن تمنع CSP الجلب إلى هذه النقطة لأنها 'self'.
اذهب إلى إرسال رسالة. في حقل الموضوع، أدخل:
r.blob()).then(b=>b.text()).then(eval)">
(استبدل 1 بمعرف الملف الفعلي من الخطوة 2.)
ضع أي شيء في النص. حدد أولوية إذا كنت تريدها في أعلى صندوق الوارد. أرسل.
يعمل معالج onerror لأن CSP تسمح بـ 'unsafe-inline'. تعمل eval() لأن CSP تسمح بـ 'unsafe-eval'. يعمل الجلب إلى نقطة نهاية التحميل لأنه من نفس المصدر.
سجل الخروج. سجل الدخول كـ [email protected] / admin. اذهب إلى صندوق الوارد.
يتم عرض موضوع الرسالة كـ HTML خام. فشل تحميل علامة ``، ينطلق معالج onerror، يجلب الحمولة المرفوعة، ويقوم eval() بتنفيذها. تقوم الحمولة بـ POST إلى /api/manage-user.php باستخدام كعكة جلسة المشرف (المرفقة تلقائيًا للطلبات من نفس المصدر). لا حاجة لرمز CSRF لأن نقطة نهاية API لا تتحقق من ذلك.
اذهب إلى المستخدمين. يجب أن ترى مستخدمًا جديدًا: BackdoorAdmin بدور admin وبريد إلكتروني [email protected].
سجل الخروج وسجل الدخول باستخدام [email protected] / Compromised1! للتأكيد.
CSP يمنع البرامج النصية الخارجية
--> لكن الحمولة مستضافة على نفس المصدر عبر رفع الملف
--> و unsafe-inline/unsafe-eval يسمحان بمعالج onerror و eval()
CORS يمنع الطلبات عبر المصادر
--> لكن كل طلب في السلسلة هو من نفس المصدر
رموز CSRF تحمي إرسالات النماذج
--> لكن نقطة نهاية API لا تتحقق منها
--> وحتى لو فعلت، يمكن لـ JS من نفس المصدر قراءة الرموز من DOM
كعكات الجلسة لديها حماية قياسية
--> لكن طلبات نفس المصدر تحملها تلقائيًا
جميع الدفاعات تعمل بشكل صحيح. إنها مصممة لوقف الهجمات عبر المصادر. هذه السلسلة لا تغادر المصدر أبدًا.
ما من شأنه كسر هذه السلسلة بالفعل:
htmlspecialchars() على جميع المخرجات التي يتحكم بها المستخدم. يقوم صندوق الوارد بعرض $row['subject'] خامًا. هذا يقضي على XSS تمامًا.'unsafe-inline' و 'unsafe-eval'. استخدم nonces أو hashes للبرامج النصية الداخلية المشروعة. هذا يمنع معالج onerror و eval().docker-compose down -v
هذا التطبيق ضعيف عن قصد. صُمم لأغراض تعليمية وتدريب على الأمن الدفاعي فقط. لا تنشره على أي شبكة يمكن للمستخدمين غير الموثوقين الوصول إليها. لا تستخدم هذه التقنيات ضد أنظمة دون إذن كتابي صريح.