
تحليل تقني واستغلال إثبات المفهوم لثغرة CVE-2023-28252، وهي ثغرة تصعيد امتيازات في برنامج تشغيل نظام ملفات السجل المشترك (CLFS) في ويندوز، استُخدمت في هجمات برنامج الفدية Nokoyawa.
منذ فبراير 2022 تم الإبلاغ عن برنامج فدية جديد يبدو أنه
يستخدم ثغرة يوم-صفر في ويندوز، وفقًا للبحث الذي أجرته
شركة تريند مايكرو.
مزيد من المعلومات حول برنامج الفدية هذا متاح على هذا
الرابط.
وفقًا لتحليل كاسبرسكي، استخدمت مجموعة فدية Nokoyawa
استغلالات أخرى تستهدف برنامج تشغيل نظام ملفات السجل المشترك (CLFS)
منذ يونيو 2022، ذات خصائص مشابهة لكنها متميزة، وكلها مرتبطة
بمطور استغلال واحد.
في أبريل 2023 عندما أصدرت مايكروسوفت التصحيح، تم تخصيص
CVE-2023-28252.
سابقًا، في عام 2022، قمنا بالبحث عن خطأ مشابه في المكوّن نفسه،
وتم توثيقه في هذه
التدوينة
لمواجهة التحليل، من الضروري معرفة تنسيق ملف .blf، الذي يعالجه برنامج تشغيل نظام ملفات السجل المشترك المعرّض للثغرة المسمى CLFS.sys والموجود في مجلد برامج التشغيل داخل system32.
مزيد من المعلومات حول هذا النوع من الملفات موجود في الروابط أدناه:
https://github.com/ionescu007/clfs-docs/blob/main/README.md
https://www.coresecurity.com/core-labs/articles/understanding-cve-2022-37969-windows-clfs-lpe
تم إجراء هذا التحليل على Windows 11 21H2 بإصدار clfs.sys 10.0.22000.1574، على الرغم من أنه يعمل أيضًا على Windows 10 21H2 وWindows 10 22H2 وWindows 11 22H2 وWindows server 2022.
في إصدارات ويندوز السابقة، من الضروري تعديل بعض القيم، وإلا فسوف نسبب شاشة زرقاء (BSOD).
تحديثات الثلاثاء من مايكروسوفت أبريل 2023.
يمكنك التحقق من إصدار برنامج التشغيل
كما هو موضح
عندما نُشرت الثغرة في أبريل 2023، بدأت مع إستيبان كازيميروف بفحص برنامج تشغيل CLFS.sys عكسيًا، على الرغم من أنه في هذه الحالة كان تحليل التصحيح وحده صعبًا جدًا لاستنتاج مكان الخطأ وكيفية استثارته، لأن الاستغلال معقد جدًا.
لاحقًا، صدرت تدوينة أظهر مؤلفها، من عينة من برنامج خبيث، بعض أجزاء الكود المفكك بواسطة HexRays وبعض المعلومات التي وجهت إلى أين يجب توجيه الاستغلال.
من الواضح أن المعلومات المقدمة لم تكن كاملة، ولكن بدون هذه المساعدة لم يكن من المرجح أن نتمكن من بناء الإثبات (PoC) ثم استغلالًا وظيفيًا.
لتسهيل الفهم، سنشرح أولًا كيفية بناء الإثبات (PoC) ثم سنقوم بتحليل الثغرة.
تحتوي هذه التدوينة على قسمين:
بناء الإثبات (PoC):
1-الحصول على عناوين النواة التي نحتاجها للاستغلال
2-تحضير المسار لإنشاء ملفات .blf:
3-إنشاء ملف "trigger blf" باستخدام دالة CreateLogFile()
4-صياغة ملف “trigger blf”
5-الحصول على عنوان النواة للكتلة الأساسية BASE BLOCK لملف trigger blf
6-استدعاء AddLogContainer بمقبض ملف trigger blf
7-تحضير ملفات spray blf
8-تحضير الذاكرة لتنفيذ الرش
9-استثارة الخطأ
التصحيح:
1-التحقق من رش الذاكرة
2-النظر إلى RecordOffset[12] في ملف trigger blf
3-النظر إلى قيمة iFlushBlock في ملف spray blf
4-لماذا يقرأ من BLOCK 1 SHADOW بدلاً من BLOCK 0 CONTROL؟
5-لماذا يكون المجموع الاختباري مساويًا صفرًا في ملفات blf spray؟
6-إنهاء الاستغلال.
7-التصحيح الحقيقي
سأنشئ دالة باسم InitEnvironment للحصول على بعض عناوين النواة الضرورية.
احصل على عنوان EPROCESS الخاص بعملي وأخزنه في المتغير g_EProcessAddress، ثم عنوان EPROCESS لعملية SYSTEM، وأخزنه في system_EPROCESS، ثم عنوان EHTREAD للـخيط الرئيسي في عملي، وأخزنه في g_EThreadAddress، وأخيرًا عنوان PREVIOUS MODE الذي لن يُستخدم في هذا الإصدار من الإثبات (PoC).

هذه الطريقة معروفة جيدًا، فدالة GetObjectKernelAddress تستدعي NtQuerySystemInformation مرتين مع الوسيط الأول SystemExtendedHandleInformation، وتُمرَّر المكالمة الأولى بحجم غير صحيح وتُرجع خطأً، ولكنها تُرجع أيضًا الحجم الصحيح الذي يُستخدم في المكالمة الثانية وتحصل على معلومات جميع المقابض، ثم تمر في حلقة على معلومات كل مقبض وفي الحقل Object من بنية handleinfo الصحيحة تحصل على العنوان المبحوث عنه في النواة.

أحتاج أيضًا إلى عناوين النواة للدوال التالية المُصدَّرة من CLFS.sys:
• ClfsEarlierLsn
• ClfsMgmtDeregisterManagedClient
والدوال المُصدَّرة من NTOSKRNL.exe
• RtlClearBit/PoFxProcessorNotification
• SeSetAccessStateGenericMapping
للحصول على هذه العناوين تُستخدم طريقة مشابهة لتلك المستخدمة للحصول على قاعدة النواة لكلا الوحدتين، عبر استدعاء NtQuerySystemInformation مرتين، لكن في هذه الحالة ستكون الوسيطة الأولى SYSTEM_INFORMATION_CLASS (في الإثبات PoC نستخدم دالة FindKernelModulesBase لهذا الغرض).
ثم يقوم بتحميل CLFS.sys
وNTOSKRNL.exe كوحدات عادية في وضع المستخدم عن طريق استدعاء
LoadLibrary، ويحصل على العناوين في وضع المستخدم باستخدام
GetProcAddress، ثم يطرح قاعدة الصورة من كل منهما، مما يحصل
على إزاحة الدالة، وأخيرًا يضيف كل إزاحة إلى قواعد النواة
المقابلة وبذلك يحصل على عناوين النواة لجميع الدوال الضرورية.

أنشئ دالة تسمى createInitialTriggerBlfFile ستقوم بتوليد وكتابة ملف .blf.
المسار المستخدم كوسيطة في CreateLogFile يختلف عن المسار العادي، على سبيل المثال لفتح الملف 1280.blf الموجود في مجلد C:\Users\Public، يجب تعيين المسار LOG:C:\Users\Public\1280. سيتم حفظ ذلك في المتغير stored_name_CreateLog.
أقوم بذلك باستخدام wsprintfW() لأن stored_env يخزن المسار C:\Users\Public، الذي تم الحصول عليه مسبقًا من متغيرات البيئة. إلى هذه السلسلة سأضيف في البداية السلسلة LOG: واسمًا عشوائيًا في النهاية، بدون امتداد .blf.

سيكون هذا هو المسار إلى ملفي الأولي الذي سأسميه "trigger blf". بالطبع، يجب أيضًا حفظ المسار العادي لنفس الملف بدون LOG: في المقدمة ومع امتداد BLF لفتحه وتعديله باستخدام CreateFile() وWriteFile() مثل أي ملف آخر، سيكون هذا المسار مثلًا: C:\Users\Public\1280.blf، وسيتم تخزينه في المتغير stored_name_fopen.

بالطبع، كلا المسارين يشيران إلى الملف نفسه، ويجب استخدام أحدهما أو الآخر وفقًا للسياق.
تقوم دالة CreateLogFile بوظيفة مشابهة جدًا لدالة CreateFile() (إنشاء ملفات جديدة أو فتح ملفات موجودة والحصول على مقبضها)، حتى أن بعض الوسائط متشابهة، لكن CreateLogFile() تعمل فقط مع ملفات blf.
بالإضافة إلى ذلك، عند فتح ملف موجود، تتحقق من أن التنسيق سليم، حتى أن كل كتلة تحتوي على مجموع اختباري وإذا لم يكن صحيحًا فستُرجع خطأً.
سأنشئ نوعين من ملفات BLF: