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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
CVE-2026-34213 — يمكن لمستخدم Docmost ذو صلاحية منخفضة تقديم attachmentId ضحية إلى نقطة نهاية التحميل العامة واستبدال المرفق المخزن لصفحة أخرى داخل نفس مساحة العمل. | Kitploit
أدوات/GitHubGitHub/0xmrma/cve-2026-34213
تحليل الثغرات الأمنيةاستغلال تطبيقات الويباختبار الاختراقالأوراق والأبحاثالتعلم والتعليم
GitHub0xmrma/cve-2026-34213

CVE-2026-34213

يمكن لمستخدم Docmost ذو صلاحية منخفضة تقديم attachmentId ضحية إلى نقطة نهاية التحميل العامة واستبدال المرفق المخزن لصفحة أخرى داخل نفس مساحة العمل.

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

الأكثر شعبية

عرض الكل →

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

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

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

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

CVE-2026-34213

يمكن لمستخدم Docmost ذي صلاحيات منخفضة توفير attachmentId خاص بالضحية إلى نقطة نهاية التحميل العامة والكتابة فوق مرفق مخزّن في صفحة أخرى داخل نفس مساحة العمل.

مقدمة

لقد حددت وكشفت بشكل مسؤول وأعدت إنتاج ثغرة في التفويض عالية الخطورة في Docmost، منصة التوثيق التعاوني مفتوحة المصدر.

يقدم الموقع الرسمي لـ Docmost نفسه كويكي محلي جاهز للمؤسسات مع أكثر من 3 ملايين تحميل، ويذكر أنه موثوق من قبل فرق في مؤسسات تشمل مدينة فيلنيوس، Bechtle، الحكومة الأسترالية، الصليب الأحمر، وETS Quebec.

كان الخلل موجودًا في مسار تحميل الملفات العام الذي يستخدمه Docmost أيضًا لتدفقات حفظ/تحديث المخططات.

كنت أراجع ذلك الكود مع سؤال محدد جدًا في ذهني:

ماذا يحدث إذا أثبتت نقطة نهاية التحميل صلاحية التحرير في صفحة واحدة، ولكن الهدف المراد الكتابة فوقه يتم تحديده باستخدام معرف مرفق منفصل يتحكم به المستخدم؟

في هذه الحالة، أدى هذا السؤال مباشرة إلى فشل حقيقي في ربط الكائنات.

سمح Docmost للمتصل بإرسال:

  • pageId لصفحة يُسمح له بتحريرها، و
  • attachmentId ينتمي إلى صفحة مختلفة في نفس مساحة العمل

قام الخادم بالفعل بإجراء فحص تناسق للكتابة فوق، لكن الحارس استخدم منطقًا منطقيًا خاطئًا.

هذا يعني أن الطلب يمكن أن يمر عبر التفويض ويكتب فوق مرفق الضحية على أي حال.

أصبحت هذه المشكلة CVE-2026-34213.

Docmost: docmost/docmost
الاستشارة: CVE-2026-34213

---
GHSA-89fp-2hch-j9gp

CVE:

تم التصحيح في:
v0.71.0
photo0

سلسلة الهجوم

pageId يتحكم به المهاجم مع صلاحية تحرير -> attachmentId ضحية يتحكم به المهاجم -> حارس كتابة فوق معيب يعالج الكتابة فوق عبر الصفحات على أنها صالحة -> إعادة بناء مسار التخزين من attachmentId الضحية -> بايتات المهاجم تحل محل ملف الضحية -> تستمر صفحة الضحية في خدمة المرفق المعدل


ماذا يفعل هذا الجزء من Docmost

يقوم Docmost بتخزين المرفقات المرفوعة للصفحات كسجلات قاعدة بيانات بالإضافة إلى ملفات داعمة في التخزين.

بالنسبة للتحميلات العادية، يقوم الخادم بإنشاء معرف مرفق جديد وكتابة ملف جديد.

بالنسبة لتدفقات حفظ/تحديث المخططات، يعيد العميل استخدام attachmentId موجود عن قصد بحيث يمكن تحديث نفس ملف المخطط في مكانه بدلاً من إنشاء سجل مرفق جديد في كل مرة.

هذا السلوك مشروع في حد ذاته.

المشكلة هي أنه يُنشئ مسارًا عالي المخاطرة:

  • إدخال واحد يحدد الصفحة التي يتم تفويضها
  • إدخال آخر يحدد المرفق الذي يتم الكتابة فوقه

عندما تخلط نقطة نهاية بين هاتين المسؤوليتين، يجب على التنفيذ ربطهما معًا بالضبط.

لم يفعل Docmost ذلك.


لماذا كان هذا السطح يستحق النظر

نقاط النهاية المختلطة للإنشاء/التحديث هي أماكن شائعة لأخطاء التفويض.

السبب بسيط:

  • تدفقات الإنشاء عادةً ما تُفوض ضد الكائن الحاوي
  • تدفقات التحديث عادةً ما تُفوض ضد السجل الموجود
  • إذا حاولت نقطة نهاية واحدة القيام بكليهما، فمن السهل التحقق من الشيء الخطأ أولاً ثم معالجة المعرف الثاني على أنه "مجرد بيانات وصفية"

هذا هو النمط بالضبط هنا.

قام POST /api/files/upload بالتحقق من أن المتصل يمكنه تحرير الصفحة المسماة بـ pageId.

ولكن إذا تم توفير attachmentId أيضًا، تحول الخادم إلى مسار الكتابة فوق وحدد سجل مرفق موجود بشكل منفصل.

هذا جعل السؤال الأمني الحرج هو:

هل يُثبت مسار الكتابة فوق أن المرفق المحدد ينتمي بالفعل إلى الصفحة المفوّضة؟

كانت الإجابة في الإصدارات الضعيفة: لا.


السبب الجذري

كان السبب الجذري تجاوز التفويض من خلال مفتاح يتحكم به المستخدم، بالإضافة إلى خطأ في المنطق المنطقي في حارس الكتابة فوق.

بدا التدفق الضعيف كالتالي:

  1. AttachmentController.uploadFile() قرأ pageId من بيانات النموذج متعدد الأجزاء.
  2. قام بتحميل تلك الصفحة واستدعى validateCanEdit(page, user).
  3. قبل بشكل منفصل attachmentId اختياريًا من نفس الطلب.
  4. AttachmentService.uploadFile() قام بتحميل المرفق الموجود عبر ذلك المعرف الذي قدمه المهاجم.
  5. حاول حارس الكتابة فوق التحقق من أن المرفق الموجود يطابق الصفحة المفوّضة.
  6. استخدم الحارس && بدلاً من الرفض عند أي عدم تطابق.

كان الحارس الضعيف:

root@kitploit:~
if (
  existingAttachment.pageId !== pageId &&
  existingAttachment.fileExt !== preparedFile.fileExtension &&
  existingAttachment.workspaceId !== workspaceId
) {
  throw new BadRequestException("File attachment does not match");
}

هذا الشرط يرفض الطلب فقط إذا:

  • معرف الصفحة غير متطابق، و
  • امتداد الملف غير متطابق، و
  • معرف مساحة العمل غير متطابق

كل ذلك في نفس الوقت.

هذا هو عكس ما يجب أن يفعله حارس الكتابة فوق.

بالنسبة لحالة الهجوم الحقيقية، بقي المهاجم عن قصد داخل نفس مساحة العمل.

لذا:

  • existingAttachment.workspaceId !== workspaceId كانت false

بمجرد أن يصبح هذا المعامل false، تم تقييم شرط && بالكامل إلى false، حتى لو كان المرفق ينتمي إلى صفحة مختلفة.

لذا تعامل الخادم مع الكتابة فوق عبر الصفحات على أنها صالحة.

كان هذا هو النصف الأول من الخلل.

النصف الثاني هو ما جعل التأثير حقيقيًا.

بعد الفحص، أعادت الخدمة بناء مسار التخزين الوجهة باستخدام attachmentId واسم الملف اللذين قدمهما المهاجم:

root@kitploit:~
const filePath =
  `${getAttachmentFolderPath(AttachmentType.File, workspaceId)}/` +
  `${attachmentId}/${preparedFile.fileName}`;

ثم، في مسار التحديث، قام Docmost فقط بتحديث البيانات الوصفية القابلة للتغيير مثل:

  • fileSize
  • updatedAt

لم يقم بإعادة ربط الملكية بصفحة المهاجم.

لذا استمرت صفحة الضحية في الإشارة إلى نفس سجل المرفق ونفس معرف المرفق. فقط بايتات الملف الأساسية تغيرت.

لهذا لم يكن هذا مجرد عدم تطابق غير ضار.

كانت بدائية كتابة فوق غير مصرح بها ودائمة.


لماذا هذه مشكلة أمنية، وليست مجرد خطأ منطقي

لم يكن هذا خطأ تجميليًا ولم يكن مشكلة تضارب في اسم الملف.

لم يحتاج المهاجم إلى سباق. لم يحتاج المهاجم إلى تخمين مسار عشوائي. لم يحتاج المهاجم إلى صلاحية كتابة على صفحة الضحية.

كل ما احتاجه هو:

  • صلاحية قراءة لمعرفة مرجع مرفق ضحية، و
  • صلاحية كتابة على أي صفحة أخرى في نفس مساحة العمل

من هناك، يمكنه استبدال بايتات الملف المخزنة لمرفق صفحة أخرى بينما تستمر صفحة الضحية في الإشارة إلى ذلك المرفق وخدمته كما لو لم يتغير شيء.

هذا فشل مباشر في التكامل.

من الناحية العملية، يمكن للمهاجم:

  • التلاعب بالمخططات
  • استبدال المرفقات بمحتوى مضلل
  • إتلاف الملفات المشار إليها
  • إنشاء مسارات تدقيق مربكة لأن المرفق لا يزال يبدو أنه ينتمي إلى صفحة الضحية

النقطة المهمة هي هذه:

قبل الخادم هدفًا للكتابة فوق اختاره المهاجم، دون ربطه بالصفحة التي تم التحقق من صلاحية تحريرها بالفعل.

هذا فشل في التحكم بالوصول، وليس مجرد سوء النظافة المنطقية.


لماذا كان الاستغلال عمليًا

كان الاستغلال عمليًا بشكل خاص لمرفقات المخططات.

يعيد عميل Docmost استخدام attachmentId عن قصد لحفظ المخططات ويستخدم أسماء ملفات حتمية:

  • diagram.excalidraw.svg
  • diagram.drawio.svg

هذا مهم لأنه يقلل من متطلبات المهاجم.

بالنسبة للمرفقات العامة، يحتاج المهاجم إلى كليهما:

  • معرف مرفق الضحية
  • اسم ملف الضحية

بالنسبة للمخططات، اسم الملف متوقع بالفعل.

لذا إذا كان بإمكان المهاجم قراءة محتوى صفحة الضحية، فغالبًا ما يمكنه استرداد القطعة المفقودة الوحيدة التي يحتاجها:

  • attachmentId الضحية

في إعداد التحقق الخاص بي، استخدمت هذا المسار بالضبط:

  • كان لدى المهاجم صلاحية قارئ فقط لمساحة الضحية
  • كان لدى المهاجم صلاحية كاتب لمساحة مختلفة يتحكم بها المهاجم
  • تنتمي كلتا المساحتين إلى نفس مساحة العمل

كان ذلك كافياً.

عبر الاستغلال حدود الصفحات وحدود المساحات داخل نفس مساحة العمل، مع استمرار تلبية فحص مساحة العمل المعيب.


إثبات المفهوم

لقد تحققت من المشكلة مباشرة ضد Docmost v0.70.3 باستخدام مختبر قابل للتصميم مبني من docmost/docmost:0.70.3 و Postgres و Redis.

كان تدفق PoC كالتالي:

  1. إنشاء حساب مالك.
  2. إنشاء مساحة ضحية ومساحة يتحكم بها المهاجم في نفس مساحة العمل.
  3. دعوة مستخدم ثانٍ كمهاجم.
  4. منح المهاجم:
    • صلاحية قارئ لمساحة الضحية
    • صلاحية كاتب لمساحة المهاجم
  5. في مساحة الضحية، تحميل مرفق مخطط إلى صفحة ضحية.
  6. كمهاجم، استرداد معلومات صفحة الضحية وملاحظة attachmentId الضحية.
  7. إرسال POST /api/files/upload مع:
    • pageId = معرف صفحة المهاجم
    • attachmentId = معرف مرفق الضحية
    • file = ملف بديل يتحكم به المهاجم باستخدام اسم ملف الضحية
  8. تنزيل مرفق الضحية قبل وبعد الكتابة فوق ومقارنة التجزئة.

كان شكل الطلب الأدنى:

root@kitploit:~
POST /api/files/upload
Content-Type: multipart/form-data

pageId=<attackerPageId>
attachmentId=<victimAttachmentId>
[email protected];filename=diagram.excalidraw.svg

كانت النتيجة الحية المرصودة:

  • معرف مرفق الضحية الذي تعلمه المهاجم: 019d18ae-b176-751c-8525-b5f3cede131d
  • معرف صفحة المهاجم المستخدم في طلب الكتابة فوق: 019d18ae-b15b-70e9-ac67-64948e87cc5e
  • بقي معرف صفحة مالك الضحية: 019d18ae-b12f-75ec-8c1c-5aff3ba6be9c
  • استجابة الخادم لطلب الكتابة فوق: 200 OK
  • SHA-256 لملف الضحية قبل الكتابة فوق:
root@kitploit:~
686a0a0ede90ece1cbb975bb29304a6c3a90373a9c3ab2496345cf7ca59cc8fa
  • SHA-256 لملف الضحية بعد الكتابة فوق:
root@kitploit:~
e0168298846cdaf75c4d880f4b721d7c0ef0ef310f75617bf2b833af34cdbeba
  • SHA-256 لحمولة المهاجم:
root@kitploit:~
e0168298846cdaf75c4d880f4b721d7c0ef0ef310f75617bf2b833af34cdbeba
  • أكد التخزين المُركّب أن مسار الضحية يحتوي الآن على:
root@kitploit:~
بديل المهاجم من صفحة أخرى

هذا إثبات كامل للكتابة فوق من البداية إلى النهاية، وليس مجرد مراجعة مصدر نظرية.


لماذا تم اختيار PoC بهذه الطريقة

استخدمت نمطين من الإثبات أثناء التقييم:

  • أداة اختبار ضيقة مستقلة عكست منطق الكتابة فوق الضعيف، و
  • استغلال HTTP حي كامل ضد مثيل Docmost قابل للتصميم

كانت الأداة المستقلة مفيدة لعزل فشل المنطق المنطقي.

كان PoC الحي عبر HTTP هو الأثر الأقوى لأنه أثبت القصة الأمنية الكاملة:

  • نجح تفويض الصفحة على صفحة المهاجم
  • تم قبول attachmentId الضحية
  • أعاد طلب الكتابة فوق النجاح
  • بقيت صفحة الضحية هي المالك المنطقي
  • تغيرت البايتات المخزنة على القرص إلى محتوى يتحكم به المهاجم

هذا التمييز مهم في أخطاء التحكم بالوصول.

"الشرط خاطئ" ليس كافيًا بحد ذاته.

"الشرط خاطئ، ويمكن قيادة التطبيق من البداية إلى النهاية إلى كتابة فوق غير مصرح بها ودائمة" هو الحالة الكاملة.


تحليل الإصلاح

تم شحن الإصلاح في v0.71.0 وقام بتغيير حارس الكتابة فوق من && إلى ||:

root@kitploit:~
if (
  existingAttachment.pageId !== pageId ||
  existingAttachment.fileExt !== preparedFile.fileExtension ||
  existingAttachment.workspaceId !== workspaceId
) {
  throw new BadRequestException("File attachment does not match");
}

هذا التصحيح بسيط ومباشر وصحيح للخلل الذي تم الإبلاغ عنه.

يعيد القاعدة الصحيحة:

الكتابة فوق مسموح بها فقط عندما يطابق المرفق الموجود تمامًا افتراضات الصفحة/مساحة العمل/النوع المفوّضة.

بمجرد أن يرفض الحارس أي عدم تطابق:

  • تفشل عمليات الكتابة فوق عبر الصفحات
  • تفشل عمليات الكتابة فوق عبر مساحات العمل
  • تفشل عدم تطابق النوع/الامتداد

كان هذا النوع الصحيح من الإصلاح:

  • لا إعادة تصميم
  • لا منطق توافق غامض
  • لا محاولة "بأفضل جهد" للاسترداد

مجرد ربط صارم بين الصفحة المفوّضة وهدف الكتابة فوق.

لا يزال هناك درس هندسي أوسع هنا:

يجب معاملة نقاط نهاية التحميل العامة التي تخدم أيضًا تدفقات التحديث الموضعي كأسطح API عالية المخاطر.

حتى عند إصلاح الخلل الفوري، فإن التصميمات الأقوى على المدى الطويل هي:

  • نقاط نهاية تحديث مخصصة لتدفقات حفظ المخططات
  • فحوصات ربط ثابتة على اسم الملف بالإضافة إلى معرف المرفق
  • تغطية اختبار انحدارية تصمم صراحةً محاولات الكتابة فوق عبر الصفحات

لكن بالنسبة للثغرة نفسها، أغلق التصحيح المنشور المشكلة الأساسية بشكل نظيف.


حالات الانحدار المهمة

سواء أضاف المشروع اختباراته الخاصة الخاصة بالإصلاح أم لا، فهذه هي الحالات المهمة للتغطية طويلة المدى:

  • يجب أن تنجح الكتابة فوق بنفس معرف الصفحة ونفس معرف المرفق
  • يجب أن تفشل الكتابة فوق بمعرف صفحة مختلف ونفس مساحة العمل
  • يجب أن تفشل الكتابة فوق بمساحة عمل مختلفة
  • يجب أن تفشل الكتابة فوق بامتداد ملف غير متطابق
  • يجب أن تفشل الكتابة فوق باستخدام اسم ملف مخطط معروف ولكن معرف مرفق أجنبي
  • يجب ألا تحافظ الكتابة فوق بصمت على ملكية الضحية بعد كتابة بايتات يتحكم بها المهاجم

الهدف من هذه الاختبارات ليس فقط الصحة.

هو تثبيت ربط التفويض بحيث لا تؤدي إعادة هيكلة التحميل "المفيدة" المستقبلية إلى إعادة فتح نفس فئة الخلل.


الخطورة والتصنيف

صنفت الاستشارة المنشورة هذه المشكلة على أنها:

  • CWE-639: تجاوز التفويض من خلال مفتاح يتحكم به المستخدم
  • CVSS v3.1:
root@kitploit:~
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:L

هذا يصل إلى 7.1 / عالية، وهو الاستنتاج الصحيح.

المقياس المهم هنا هو التكامل.

لم يكن هذا خطأ بيانات وصفية منخفض المستوى. سيطر المهاجم بشكل كامل على بايتات الاستبدال المكتوبة في مسار مرفق صفحة أخرى، واستمرت صفحة الضحية في خدمة الكائن المعدل بعد ذلك.

هذا هو بالضبط نوع العبث المسجل عبر السجلات الذي يستحق تكامل عالي.

تبقى التوفر منخفضة منطقية أيضًا لأن إتلاف مخطط أو مستند مرفق يمكن أن يجعل محتوى الضحية غير قابل للاستخدام، ولكن التأثير الأساسي لا يزال تعديلًا غير مصرح به بدلاً من تعطيل الخدمة بالكامل.


الإفصاح

أبلغت عن المشكلة بشكل خاص من خلال استشارات أمان GitHub مع:

  • تحليل السبب الجذري
  • PoC HTTP حي
  • أدلة الطلب/الاستجابة
  • تجزئات الملفات قبل/بعد
  • إعداد مختبر قابل للتصميم ومُثبت

تم قبول المشكلة من قبل المشرف، وتم تعيين CVE-2026-34213، ونشرت في 14 أبريل 2026.

تسرد الاستشارة العامة:

  • الإصدارات المتأثرة: >= v0.3.0
  • الإصدار المصحح: v0.71.0

تطابق هذا التاريخ أيضًا مع مراجعة المصدر المحلية الخاصة بي: كان منطق الكتابة فوق الضعيف موجودًا في أقدم إصدار تم إصداره قمت بفحصه في السطر الضعيف.


ما يعلمه هذا الخلل بالفعل

الدرس المثير للاهتمام هنا ليس مجرد "استخدام || بدلاً من &&."

هذا هو العرض.

الدرس الأعمق هو:

إذا أثبت حقل واحد يتحكم به المستخدم التفويض وحدد حقل آخر يتحكم به المستخدم الكائن الذي يتم تحديثه، يجب ربط هذين الحقلين معًا بشكل صريح ودقيق.

تظهر هذه القاعدة في كل مكان:

  • مرفقات المستندات
  • وسائط الملف الشخصي
  • مراجع الكائنات السحابية
  • تعديلات المشكلات/التعليقات
  • إعادة معالجة المهام الخلفية

في اللحظة التي يقول فيها النظام:

  • "يمكنك تحرير الصفحة X"
  • "من فضلك أخبرني أيضًا أي سجل موجود تريد تحديثه"

فقد خلق حدًا أمنيًا يجب فرضه باستخدام ثوابت تطابق تام.

أي شيء أقل من ذلك يتحول إلى خطأ مفتاح يتحكم به المستخدم عاجلاً أم آجلاً.

تعزز هذه المشكلة أيضًا نقطة ثانية يسهل التقليل من شأنها:

يمكن أن يكون للأخطاء المنطقية الصغيرة في كود الحارس عواقب أمنية من الدرجة الأولى.

كان شرط ثلاثي يبدو "معقولاً" للوهلة الأولى كافياً لعكس نموذج الحماية لمسار الكتابة فوق.

لهذا السبب تستحق هذه الأسطح مراجعة متعمدة بدلاً من الثقة العابرة.


النقاط الرئيسية

  • استخدم Docmost نقطة نهاية واحدة لكل من التحميلات الجديدة وتحديثات المرفقات الموضعية.
  • تم التحقق من التفويض ضد pageId الذي قدمه المتصل، لكن اختيار هدف الكتابة فوق استخدم attachmentId منفصلًا قدمه المتصل.
  • رفض حارس الكتابة فوق فقط عندما تكون جميع شروط عدم التطابق صحيحة في وقت واحد.
  • في حالة الهجوم ضمن نفس مساحة العمل، فشل هذا الفحص مفتوحًا.
  • أعادت الخدمة بناء مسار التخزين من معرف مرفق الضحية وكتبت بايتات يتحكم بها المهاجم فيه.
  • بقي سجل المرفق مرتبطًا بصفحة الضحية بعد الكتابة فوق.
  • جعلت أسماء ملفات المخططات الحتمية الاستغلال عمليًا بشكل خاص.
  • قام الإصلاح في v0.71.0 بتغيير الحارس بشكل صحيح لرفض أي عدم تطابق.

الكلمات الأخيرة

لم تكن هذه الثغرة تتعلق بسلوك تخزين غريب.

كانت تتعلق بمسار تحديث يثق في معرف كائن يختاره المهاجم أكثر مما ينبغي.

أثبت Docmost صلاحية التحرير في صفحة واحدة، وقبل معرف مرفق موجود من صفحة أخرى، ثم ترك فحص كتابة فوق معيب يحول هذا عدم التطابق إلى استبدال ملف ناجح عبر الصفحات.

لهذا أصبحت CVE-2026-34213.

أصلح التصحيح في v0.71.0 المشكلة الفورية بشكل نظيف، لكن الدرس الأوسع لا يزال قيماً:

عندما يتم تقسيم التفويض واختيار الكائن عبر حقول منفصلة يتحكم بها المستخدم، فإن الربط الدقيق هو خاصية الأمان.

تنزيل الأداة