
إثبات مفهوم يوضح تجاوز فحص الوصول لملفات السحابة في ويندوز (CVE-2026-83991) يحوّل ملفًا للقراءة فقط إلى عنصر نائب سحابي عبر دلالات الاستبدال، مع تحليل تقني مفصّل وخطوات إعادة إنتاج.
CVE-2026-83991 هي ثغرة عبث في ملفات السحابة في Windows، ويبدأ نطاق الإصدارات المتأثرة المنشور بها من Windows 10 الإصدار 1809، أي قبل ما يقرب من ثماني سنوات من إصلاح سبتمبر 2026.
طلبتُ من Windows فتح ملف للكتابة. أجاب بـ ERROR_ACCESS_DENIED.
طلبتُ من Windows حذف الملف نفسه. مرة أخرى، ERROR_ACCESS_DENIED.
ثم طلبتُ من حزمة ملفات السحابة أن تتفوق على اسم الملف هذا. أعادت S_OK وغيّرت الملف الموجود إلى عنصر نائب لملفات السحابة.
كان الملف قد قال لا مرتين. مسار التفوق سمع شيئًا أقرب إلى "يُرجى المتابعة".
ذلك الانقسام في التفويض هو CVE-2026-83991. تسميه Microsoft ثغرة العبث في برنامج تشغيل المرشح الصغير لملفات السحابة في Windows، وتصنّفه بدرجة مهم، وخصصت له درجة أساسية 5.5 من متوسط وفقًا لـ CVSS 3.1. المتجه الرسمي هو CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N/E:U/RL:O/RC:C.
ينشئ إثبات المفهوم دليلاً جديدًا وملفًا عاديًا. يمنح المتصل حق الوصول للكتابة إلى الدليل، ثم يطبق قائمة تحكم وصول (DACL) محمية على الملف تمنح المتصل حق الوصول للقراءة دون حق الوصول العادي للكتابة أو الحذف.
باستخدام رمز مؤشر ترابط واحد مقيد بمستوى تكامل متوسط، يثبت التسلسل التالي:
عالج الاستدعاء إدخالاً واحدًا، وأعاد رقم USN إنشاء غير صفري، وأعطى الملف وسم IO_REPARSE_TAG_CLOUD بقيمة 0x9000001A. في التشغيل المُعاد إنتاجه، كان معرف الملف متطابقًا قبل الاستدعاء وبعده. استمر نفس ملف NTFS بينما تغيرت حالته إلى عنصر نائب سحابي.
قدّم Windows 10 الإصدار 1709 واجهة برمجة تطبيقات ملفات السحابة. تمنح محركات المزامنة المكتبية طريقة مدعومة لتسجيل شجرة دليل، وإنشاء إدخالات نائبة، وترطيب محتواها عند الحاجة.
ثلاثة عناصر مهمة هنا:
CldApi.dll يكشف عن واجهة برمجة تطبيقات مرشح السحابة في وضع المستخدم.cldflt.sys هو المرشح الصغير لنظام الملفات في مركز مسار التخزين.تستخدم العناصر النائبة السحابية نقاط إعادة التحليل. نقطة إعادة التحليل هي آلية في نظام الملفات تحمل وسمًا وبيانات مرتبطة. وهي مفهوم أوسع من الارتباط الرمزي، ولا ينبغي التعامل مع الاثنين كمرادفين.
واجهة البرمجة ذات الصلة هي CfCreatePlaceholders. تنشئ ملفًا أو أكثر من الملفات أو الدلائل النائبة تحت جذر مزامنة مسجل. تقول وثائق Microsoft إن المتصل يجب أن يمتلك حق الوصول WRITE_DATA أو WRITE_DAC إلى الدليل الأساسي.
العلم الخاص بكل إدخال CF_PLACEHOLDER_CREATE_FLAG_SUPERSEDE بقيمة 0x4، يوفر دلالات الكتابة فوق عنصر نائب موجود. التفصيل المثير للاهتمام في هذا CVE هو أن المسار المعرض للخطر قبل أيضًا ملفًا عاديًا موجودًا وحوّله إلى عنصر نائب.
تفصل التجربة الحقوق على الدليل عن الحقوق على الملف الموجود.
يمنح الدليل الأصلي المستخدم الحالي:
FILE_GENERIC_READ
FILE_GENERIC_WRITE
FILE_GENERIC_EXECUTE
DELETE
بالنسبة للدليل، يتضمن FILE_GENERIC_WRITE حق FILE_WRITE_DATA، ويسمى أيضًا FILE_ADD_FILE. هذا كافٍ لمتطلب الدليل الأساسي الموثق المستخدم بواسطة CfRegisterSyncRoot وCfCreatePlaceholders.
لا يمنح ACE الخاص بالدليل الأصلي حق FILE_DELETE_CHILD. بت DELETE الخاص به ينطبق على كائن الدليل نفسه. هذا التمييز مهم لأن DeleteFileW يتطلب إما DELETE على الملف الهدف أو FILE_DELETE_CHILD على دليله الأصلي.
يمنح العنصر الطرفي الموجود المستخدم الحالي FILE_GENERIC_READ فقط. قائمة DACL الخاصة به مميزة كـ PROTECTED_DACL_SECURITY_INFORMATION، لذا فهي لا ترث ACEs الخاصة بالدليل الأصلي.
يخلق هذا السؤال المركزي:
هل إذن إنشاء طفل جديد في دليل يسمح أيضًا بعملية تفوق تغيّر الحالة ضد طفل أكثر تقييدًا موجود بالفعل؟
الوصول العادي للملفات يجيب بالنفي. مسار ملفات السحابة المعرض للخطر أجاب بالإيجاب.
تشرح وثائق أمان الملفات الخاصة بـ Microsoft سبب توقع هذا التمييز. عادةً ما يتحكم واصف أمان الملف نفسه في الوصول إليه. لا يستبدل واصف الدليل الأصلي فحص وصول الطفل بشكل عام، باستثناء قواعد محددة مثل الوراثة وFILE_DELETE_CHILD.
تصبح عروض التحكم في الوصول غير مقنعة عندما يعمل الإعداد كهوية واحدة وتعمل العملية المثيرة للاهتمام كهوية أخرى. يتجنب إثبات المفهوم هذا هذا المشكلة.
يشتق رمزًا مقيدًا من رمز العملية الحالي، ويجعل SID المسؤولين غائبًا أو مرفوضًا فقط، ويضبط تكاملًا متوسطًا، ويكرر رمز انتحال عند SecurityImpersonation، ويُثبته على مؤشر الترابط الحالي بـ SetThreadToken.
تستحق الصياغة الدقيقة للامتيازات عناية. CreateRestrictedToken مع DISABLE_MAX_PRIVILEGE يعطل كل امتياز باستثناء SeChangeNotifyPrivilege. هذا الامتياز المتبقي يتجاوز بعض فحوصات اجتياز الدلائل. لا يمنح حقوق كتابة بيانات الملف أو حذفه.
ينفذ إثبات المفهوم بعد ذلك الإعداد وفحوصات التحكم وتسجيل جذر المزامنة والاتصال واستدعاء التفوق بينما يظل رمز انتحال مؤشر الترابط نفسه نشطًا. لا يوجد تبديل هوية مناسب بين "تم رفض الوصول" وS_OK.
الكود المصدري الكامل موجود في main_poc.c، مع build.bat لـ GCC أو مترجم C من Microsoft.
ينشئ البرنامج دليل اختبار جديدًا باسم GUID تحت دليل بيانات التطبيق المحلي للمستخدم الحالي. يمكن توفير مسار اختياري، لكن البرنامج يرفض استخدام مسار موجود بالفعل.
هذا التقييد مقصود. يوضح إثبات المفهوم الثغرة ضد بيانات ينشئها لنفسه. لا يحتاج إلى موفر مزامنة تابع لجهة خارجية مثبتًا ولا يستهدف جذر مزامنة موجودًا.
ينشئ البرنامج protected_existing.bin، ويكتب بيانات اختبار معروفة، ويمنحه سمات ملف عادية. يسجل البيانات الوصفية الأساسية للملف وحجمه المنطقي وسماته ومعرف الملف.
قبل استدعاء ملفات السحابة، الملف ليس نقطة إعادة تحليل.
يستبدل البرنامج DACL الخاص بالعنصر الطرفي بثلاثة ACEs سماحية غير موروثة:
| المبدأ | حقوق العنصر الطرفي |
|---|---|
SYSTEM | تحكم كامل |
Administrators | تحكم كامل |
| المستخدم الحالي | FILE_GENERIC_READ |
لأن SID المسؤولين في الرمز الفعال غائب أو مرفوض فقط، لا يمكن لـ ACE السماح للمسؤولين منح وصول إداري لمؤشر الترابط.
ينفذ إثبات المفهوم بعد ذلك ثلاثة فحوصات تحكم. يفشل GENERIC_WRITE بالخطأ 5، ويفشل DeleteFileW بالخطأ 5، وينجح GENERIC_READ. يؤكد أيضًا أن DACL محمية.
تثبت هذه الفحوصات الأذونات المستخدمة في العمليتين العاديتين. لا يختبر إثبات المفهوم WRITE_DAC أو كل طريقة ممكنة يمكن لمالك ملف الاختبار الاصطناعي أن يؤثر بها على ذلك الملف. التناقض الموضح هو تحديدًا بين عمليات الكتابة والحذف المرفوضة وعملية التفوق الناجحة في ملفات السحابة.
يسجل إثبات المفهوم دليله الجديد بسياسة ترطيب تدريجي وسياسة تعداد كاملة. يوفر GUID جديدًا كهوية الموفر والجذر.
ثم يستدعي CfConnectSyncRoot بجدول استدعاء يحتوي فقط على إدخال CF_CALLBACK_NONE الختامي. لا حاجة لاستدعاء ترطيب لانتقال البيانات الوصفية الذي يتم اختباره.
يحافظ إدخال العنصر النائب على الطوابع الزمنية والحجم المنطقي للملف الأصلي، ويوفر هوية ملف GUID، ويضبط الثابت المحلي الذي يطابق علم التفوق الرسمي:
#define CF_CREATE_SUPERSEDE 0x00000004UL
placeholder.RelativeFileName = leaf_name;
placeholder.FsMetadata.BasicInfo = basic_info;
placeholder.FsMetadata.FileSize = standard_info.EndOfFile;
placeholder.FileIdentity = &run_id;
placeholder.FileIdentityLength = sizeof(run_id);
placeholder.Flags = CF_CREATE_SUPERSEDE;
create_hr = cf.Create(root, &placeholder, 1, 0, &processed);
يحمل المصدر CldApi.dll ديناميكيًا ويحل الدوال العامة في وقت التشغيل. تغطي هياكله المعلنة يدويًا فقط ABI اللازم لهذا الاختبار.
يمكن لواجهة برمجة تطبيقات دفعية معالجة إدخال فشل. تقول وثائق Microsoft صراحةً إن EntriesProcessed يتضمن الإدخالات الفاشلة، لذا فإن القيمة واحد لا تثبت النجاح بحد ذاتها.
لذلك يتطلب إثبات المفهوم كل هذه الشروط قبل طباعة CONFIRMED والخروج برمز صفر:
CfCreatePlaceholders بالضبط S_OK.S_OK.FILE_ATTRIBUTE_REPARSE_POINT.FSCTL_GET_REPARSE_POINT قيمة IO_REPARSE_TAG_CLOUD.يجب أيضًا أن تنجح فحوصات الكتابة والحذف والقراءة المباشرة وDACL والملف الموجود مسبقًا في وقت سابق من البرنامج، أو يتوقف التنفيذ قبل عملية ملفات السحابة.
انتقال الحالة المُعاد إنتاجه كان:
0x00000020 هو FILE_ATTRIBUTE_ARCHIVE. قناع 0x00401600 الناتج يحتوي على FILE_ATTRIBUTE_SPARSE_FILE وFILE_ATTRIBUTE_REPARSE_POINT وFILE_ATTRIBUTE_OFFLINE وFILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS.
معرف الملف دون تغيير مفيد بشكل خاص. يظهر أنه في هذا التشغيل، لم تكن النتيجة مجرد ملف مختلف يظهر في نفس اسم المسار. نجا كائن الملف الموجود بينما اكتسب حالة ملفات السحابة.
يحافظ البرنامج على الحجم المنطقي للملف، لكنه لا يتحقق من البايتات الأصلية بعد التحويل. لا يتبع أي ادعاء حول التحكم التعسفي في المحتوى من إثبات المفهوم هذا.
يمكن ذكر الفشل الملحوظ دون اختراع مكدس استدعاء داخلي:
CfCreatePlaceholders طلب تفوق لذلك العنصر الطرفي.هذا السلوك متسق مع فحص مفقود أو غير مكتمل ضد العنصر الطرفي الموجود على مسار التفوق. لا يحدد الوظيفة الداخلية الدقيقة أو الفرع أو IRP أو استدعاء النواة المسؤول. لا يحتوي إثبات المفهوم على تصحيح أخطاء النواة أو تحليل اختلاف ثنائي، لذا يتوقف التفسير عند الحدود التي تم التحقق منها خارجيًا.
خصصت Microsoft CWE-306، المصادقة المفقودة للوظيفة الحرجة. على مستوى كائن Windows، تكشف التجربة عن إنفاذ تفويض غير متسق. أستخدم CWE الرسمي من Microsoft في البيانات الوصفية وأصف سلوك التحكم في الوصول الملحوظ في التحليل الفني.
يوضح إثبات المفهوم تغييرًا في السلامة وحالة الملف لم تستطع العمليات المباشرة المختبرة تنفيذه. يمكن لمتصل محلي منخفض الامتياز يمتلك وصول الدليل الأساسي المطلوب أن يجعل عنصرًا طرفيًا موجودًا للقراءة فقط يصبح عنصرًا نائبًا لملفات السحابة عبر المسار المتأثر.
يعطي تنبيه Microsoft تأثير المنتج الأوسع: يمكن للمهاجم إجراء تغييرات غير مصرح بها على بيانات النظام المحمية وتغيير حالة النظام أو تكوينه بما يتجاوز الامتيازات العادية. هذا تقييم Microsoft للثغرة. لا يختار إثبات المفهوم المعزول هدف نظام محمي أو يوضح سلسلة استغلال كاملة بعد الاستغلال.
يعكس متجه CVSS نفس الشكل الواسع:
الإجابة الدقيقة هي ما يقرب من ثماني سنوات في نطاق الإصدارات المتأثرة المنشور من Microsoft.
يبدأ سجل CVE الرسمي أقدم فرع متأثر عند 10.0.17763.0 لـ Windows 10 الإصدار 1809 وWindows Server 2019. يسرد سجل إصدارات Windows 10 من Microsoft أول إصدار 1809، 17763.1، في 2 أكتوبر 2018. نشرت Microsoft الإصلاح في 8 سبتمبر 2026.
هذا يضع أقرب نقطة مؤكدة في النطاق العام قبل أقل من ثماني سنوات من الإصلاح بقليل.
وصلت واجهة برمجة تطبيقات ملفات السحابة نفسها مع Windows 10 الإصدار 1709 في 2017، وتدرج وثائق واجهة البرمجة 1709 كحد أدنى للعميل المدعوم. هذا لا يثبت أن الثغرة كانت موجودة في 1709. لا يدرج سجل CVE الخاص بـ Microsoft 1709، ولم يختبر هذا البحث ذلك. عيد ميلاد واجهة برمجة التطبيقات ليس تلقائيًا عيد ميلاد الثغرة، مهما كان العنوان مغريًا.
استخدم نظام اختبار متأثرًا على NTFS. شغّل إثبات المفهوم من موجه أوامر عادي غير مرتفع.
build.bat
main_poc.exe
يستخدم سكربت البناء MinGW-w64 GCC عند توفره ويعود إلى مترجم C من Microsoft. ينشئ البرنامج ويسجل جذر الاختبار الجديد الخاص به. يلغي التسجيل ويفصل الاتصال أثناء التنظيف، ثم يترك دليل الاختبار في مكانه للفحص.
صيغة المسار الاختيارية هي:
main_poc.exe C:\path\to\a\new-test-directory
يجب ألا يكون المسار المقدم موجودًا بالفعل. أبقِ الاختبار معزولًا وأزل دليله بعد جمع النتائج.
على نظام مُصلح، لا ينبغي أن يصل الشرط الكامل إلى CONFIRMED. لا تستنتج حالة التصحيح من سطر وحدة تحكم واحد. افحص النتيجة الإجمالية ورمز الخروج ونتيجة كل إدخال وUSN والسمات ووسم إعادة التحليل معًا.
أكثر ثغرات Windows إثارة للاهتمام غالبًا ما تكون جدالات حول أي كائن كان فحص الوصول يدور حوله حقًا.
هنا، وصل إذن الإنشاء تحت دليل إلى مسار يمكنه تحويل طفل أكثر تقييدًا موجودًا بداخله. احترمت واجهات برمجة تطبيقات الملفات العادية DACL الحالي لذلك الطفل. لم يحافظ تفوق ملفات السحابة على نفس الحدود.
لم يكن مطلوبًا تلف ذاكرة مذهل. قال كائن واحد لا، وقدم كائن آخر سلطة كافية للمتابعة، وأصبح اسم ملف مألوف شيئًا آخر بهدوء.
هذه هي الحيلة كلها. وهو أيضًا سبب أهمية الحيلة.
| العملية | النتيجة |
|---|
فتح الملف الموجود بـ GENERIC_WRITE | ERROR_ACCESS_DENIED |
حذفه بـ DeleteFileW | ERROR_ACCESS_DENIED |
فتحه بـ GENERIC_READ | نجاح |
| تسجيل الدليل الأصلي وربطه كجذر مزامنة | S_OK |
استدعاء CfCreatePlaceholders بدلالات التفوق | S_OK |
| فحص الإدخال الناتج | نقطة إعادة تحليل سحابية |
| الخاصية | قبل | بعد |
|---|
| السمات | 0x00000020 | 0x00401600 |
| نقطة إعادة التحليل | لا | نعم |
| وسم إعادة التحليل | لا شيء | 0x9000001A |
| نتيجة الإدخال | غير قابل للتطبيق | S_OK |
| USN الإنشاء | غير قابل للتطبيق | غير صفري |
| معرف الملف | مسجل | دون تغيير |