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

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

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

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

دليل الأدوات

الفئات

عرض جميع الفئات
Loading categories
أدوات/GitHubGitHub/squeeze440/zotlit-poc
تحليل الثغرات الأمنيةالاستغلالتسريب البياناتجمع المعلوماتالمحاكاة الافتراضية للأمانالأوراق والأبحاث
GitHubsqueeze440/zotlit-poc

zotlit-PoC

PoC — استيراد المرفقات ينسخ الملفات من مسارات محلية غير معتمدة في ZotLit (GHSA-4qh7-66xv-h329، CVE-2026-87000، CVSS 5.5).

عرض المستودع
منذ 7 أياملم تتم المراجعة بعد

الأكثر شعبية

عرض الكل →

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

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

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

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

ZotLit: تنبيه أمني

حالة CVE: مطلوب، في انتظار التعيين. تم نشر هذا الاكتشاف باسم GHSA-4qh7-66xv-h329. عند تعيين CVE، سيُعاد تسمية هذا المستودع إلى CVE-YYYY-NNNNN-zotlit-PoC وسيُستبدل هذا الشعار برابط CVE.

الباحثDostxodjayev Abdullox (@squeeze440)
التنبيهGHSA-4qh7-66xv-h329
CVSS 3.15.5 (متوسط)
نقطة الضعفCWE-73, CWE-200

الملخص

التحكم الخارجي في اسم الملف أو المسار في ميزة استيراد المرفقات في AidenLx ZotLit (aidenlx/zotlit) 1.1.12 يسمح للمهاجم الذي يتحكم في مكتبة Zotero مشتركة/متزامنة بالكشف عن ملفات محلية عشوائية من نظام ملفات الضحية إلى خزنة Obsidian الخاصة بالضحية عبر مسار مرفق linked_file مُصمَّم بعناية.

المنتج

ZotLit — إضافة Obsidian لتكامل Zotero (aidenlx/zotlit، معرّف الإضافة zotlit، إصدار البيان 1.1.12)

الإصدار المُختبَر

التزام Git 41e60aaa6178629b34f8a42d104e757594b72435 (2026-07-31)

تقدير CVSS v3.1

CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:N/A:N — 5.5 (متوسط)

مقاييس غير بديهية: AV:L — يحدث الاستغلال عندما تعالج عملية Obsidian/zotlit المحلية للضحية بيانات وصفية لعنصر Zotero مُقدَّمة من المهاجم (تُسلَّم عبر مكتبة مشتركة/متزامنة)، وهو نفس الاصطلاح المستخدم في أخطاء "ملف ضار تعالجه تطبيق محلي"، حتى وإن كان التسليم نفسه يمكن أن يحدث عبر الشبكة (مكتبة جماعية مشتركة، ملف تصدير مُرسَل بالبريد). UI:R — يجب على الضحية استيراد/مزامنة المكتبة الضارة في Zotero وتشغيل ميزة استيراد الملاحظات في ZotLit (أو تضمين التعليقات/الاقتباسات) على ملاحظة تشير إلى المرفق المُصمَّم؛ وهذا استخدام روتيني لوظيفة الإضافة الأساسية والمفعّلة افتراضيًا (attachment.import افتراضيًا true)، وليس إجراءً غير معتاد. I:N/A:N — هذا الاكتشاف هو أساس قراءة/نسخ فقط؛ لا يُدَّعى أي اجتياز مسار على جانب الوجهة (انظر التفاصيل لملاحظة ذات صلة لكن غير مُتحقَّق منها).

التفاصيل

يقرأ ZotLit البيانات الوصفية للمرفقات مباشرة من قاعدة بيانات SQLite الخاصة بـ Zotero (أو مكتبة متزامنة/مشتركة)، بما في ذلك عمود itemAttachments.path النصي الحر، ويثق به تمامًا عند تحديد مكان قراءة مرفق "مرتبط" منه:

  • packages/db/src/lib/zt-path.ts:62-63 — attachmentAbsPath()، الحالة "linked-absolute":

    root@kitploit:~
    case "linked-absolute":
      return parsed.path;
    

    بالنسبة لصفوف linkMode: 2 (linked_file) التي لا يحمل مسارها العنصر النائب attachments: للمجلد الأساسي، فإن parsed.path هو السلسلة الخام من قاعدة البيانات التي تُعاد حرفيًا كمسار نظام ملفات مطلق للقراءة — لا قائمة سماح، ولا حصر في مجلد بيانات Zotero أو أي موقع معتمد من المستخدم.

  • packages/db/src/lib/context/zt-template-attach.ts:101-106 — attachmentFilename()، الحالة "linked-absolute":

    root@kitploit:~
    case "linked-absolute":
      return basename(path.path);
    

    اسم الملف المستخدم لبناء النسخة داخل الخزنة مشتق من نفس المسار الذي يتحكم فيه المهاجم عبر basename()، لذا فإن اسم ملف الوجهة متأثر بالمهاجم لكنه خالٍ من فواصل المسار (آمن ضد الاجتياز في هذا الفرع).

  • apps/obsidian/src/services/note-import/note-parser.ts:403-430 — يُستدعى resolveEmbeddedImage() أثناء تحويل تعليق صورة مضمّنة في ملاحظة أدبية من Zotero إلى Markdown الخاص بـ Obsidian (إجراء روتيني وافتراضي لميزة "Import Note" في ZotLit). يحل sourcePath = attachmentAbsPath(attachment, ...) ويستدعي deps.resolveLink({ sourcePath, vaultName: \${attachment.key}-${filename}` })` — مما يضع في قائمة الانتظار نسخة من أي مسار مطلق يختاره المهاجم إلى الخزنة.

  • apps/obsidian/src/services/attachment-import/service.ts:125-155 — يضع AttachmentImportBatch.resolveLink() في قائمة الانتظار { source: sourcePath, dest: <vault attachment folder>/<key>-<filename> }، مقيّدًا فقط بإعداد attachment.import، الذي قيمته الافتراضية true (apps/obsidian/src/services/settings/schema.ts:123).

  • apps/obsidian/src/lib/copy-attachments.ts:43-60 — ينفّذ copyAttachment() القراءة والكتابة الفعليتين دون أي تحقق من المسار: stat(source) ثم copyFile(source, dest).

النتيجة الصافية: يمكن للمهاجم القادر على إدخال عنصر Zotero من نوع linked_file (linkMode 2) إلى مكتبة الضحية — مثل مكتبة Zotero جماعية مشتركة، أو تصدير .rdf/.json/Better BibTeX يستورده الضحية، أو مكتبة متزامنة يملك المهاجم حق الكتابة فيها — أن يضبط مسار مرفق ذلك العنصر إلى أي ملف على قرص الضحية (~/.ssh/id_rsa، مخازن بيانات اعتماد المتصفح، خزائن أخرى، ملفات .env، إلخ). في اللحظة التي يشغّل فيها الضحية استيراد الملاحظات في ZotLit (أو يعرض/يضمّن ذلك التعليق) مع الإعداد الافتراضي attachment.import: true، ينسخ ZotLit بصمت محتوى ذلك الملف إلى خزنة Obsidian الخاصة بالضحية تحت اسم متوقع (<attachmentKey>-<basename>). ولأن الخزائن تُزامَن أو تُرفع إلى git أو تُنشر بشكل روتيني، فإن هذا ينقل بيانات لم يكن بمقدور المهاجم الوصول إليها بأي طريقة أخرى إلى موقع يمكن للمهاجم (أو أي شخص آخر لديه وصول إلى هدف المزامنة) قراءته.

ملاحظة ذات صلة، غير مُتحقَّق منها (ليست جزءًا من PoC هذا الاكتشاف): الفرع الشقيق "storage" في attachmentFilename() (zt-template-attach.ts:103-104) يعيد لاحقة المسار الخام دون استدعاء basename() المطبَّق على الفرعين الآخرين. ما إذا كان هذا قابلًا للاستغلال بشكل مستقل يعتمد على كيفية تسمية آلية مزامنة التخزين الخاصة بـ Zotero للملفات المُنزَّلة محليًا، وهو أمر خارج هذا المستودع ولم يُتحقَّق منه — يُشار إليه هنا فقط كفجوة تقوية تستحق الإغلاق للاتساق.

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

التحقق الديناميكي: تم استخراج الدوال المعرّضة للخطر بالضبط (parseAttachmentPath، attachmentAbsPath، attachmentFilename، copyAttachments/copyAttachment/writeCopy/destMatches، isErrno، reflink) حرفيًا (مع الاستشهاد بالملف:السطر أعلاه، والمنطق دون تغيير) من المصدر المُصدَّر وتنفيذها مباشرة في Node، لأن تثبيت مساحة عمل pnpm كاملًا دون اتصال لم يكن متاحًا في هذه البيئة المعزولة (سلسلة أدوات corepack/pnpm معطلة دون اتصال). كان الاستبدال الوحيد هو تبديل استدعاء مسجّل LogTape بـ console.warn — تجميلي فقط، دون أي تأثير على تدفق التحكم. السكربت: ~/engagements/zotlit/evidence/poc-verify.mjs.

الخطوات:

  1. سر الضحية المحاكى في ~/engagements/zotlit/evidence/victim-disk/id_rsa (محتوى وهمي، مُعلَّم بوضوح كمحاكى).
  2. صف مرفق Zotero مُصمَّم يتحكم فيه المهاجم: { key: "EVILKEY1", path: "<path to victim's id_rsa>", linkMode: 2 } — بالضبط الشكل الذي يعيده getAttachmentByKey من قاعدة بيانات Zotero.
  3. تشغيل attachmentAbsPath() الحقيقية — حلّ المصدر كملف الضحية، حرفيًا، دون تحقق.
  4. تشغيل attachmentFilename() الحقيقية — حلّ id_rsa كاسم ملف وجهة يبدو آمنًا.
  5. إعادة إنتاج بناء vaultName الحقيقي من note-parser.ts:427 (${key}-${filename}).
  6. تشغيل copyAttachments() الحقيقية — النتيجة { copied: 1, skipped: 0, missing: 0 }.
  7. قراءة fake-vault/attachments/EVILKEY1-id_rsa مرة أخرى — المحتوى مطابق بايت ببايت للملف الأصلي للضحية.

لقطة شاشة للتشغيل الكامل (الأمر + المخرجات) في xterm حقيقي: ../evidence/poc-run.png

التأثير

يمكن للمهاجم القادر على التأثير في محتويات مكتبة Zotero الخاصة بالضحية (مكتبة مشتركة/جماعية، تصدير ببليوغرافي مستورد، أو مكتبة متزامنة) أن يسحب بشكل غير مصرح به ملفات محلية عشوائية يمكن لمستخدم نظام الضحية قراءتها — مفاتيح SSH، مخازن بيانات الاعتماد، محتويات خزائن أخرى، أسرار .env/الإعدادات — إلى خزنة Obsidian الخاصة بالضحية، دون أي مطالبة أو تأكيد، في اللحظة التي يستخدم فيها الضحية وظيفة استيراد الملاحظات الأساسية في ZotLit بالإعدادات الافتراضية. غالبًا ما تُزامَن الخزائن (Obsidian Sync، git، مجلدات سحابية) أو تُنشر، لذا يحوّل هذا أساس قراءة ملف محلي إلى تعرّض عن بُعد واقعي.

نقاط الضعف

  • CWE-73: التحكم الخارجي في اسم الملف أو المسار
  • CWE-200: كشف معلومات حساسة لجهة غير مصرح لها

المعالجة

يُقترح حصر مصادر مرفقات linked_file (linkMode 2) في مواقع نظام الملفات التي أعدّها الضحية أو وافق عليها صراحةً (مثل baseAttachmentPath المُعدّ في Zotero نفسه، أو مجلد بيانات Zotero)، ومطالبة المستخدم قبل النسخ التلقائي لمرفق مرتبط يقع مساره خارج أي جذر متوقع. وكدفاع في العمق، يُنظر في تطبيق نفس التعقيم القائم على basename() فقط والمستخدم بالفعل في فرعي linked-absolute/linked-base من attachmentFilename() على الفرع "storage" أيضًا، حتى لا يعيد أي مسار في الكود جزءًا من اسم ملف غير مُعقَّم.

الشكر

Dostxodjayev Abdullox (GitHub: squeeze440)

قناة الإبلاغ

الإبلاغ الخاص عن الثغرات مُفعَّل على aidenlx/zotlit — أبلغ عبر مسودة GitHub Security Advisory (GHSA) على المستودع بدلًا من مشكلة عامة.

تنزيل الأداة