السباق ذهابًا وإيابًا: الثغرة الصغيرة التي فعلت الكثير

امرأة شابة تبدو شاردة الذهن بينما تعمل على كمبيوتر ليلًا.

الثغرة الصغيرة التي فعلت الكثير: CVE-2024-30089 هي ثغرة دقيقة في النواة استخدمتها لاستغلال جهاز Windows 11 مُحدث بالكامل (مع تفعيل كافة ميزات الأمان القائم على المحاكاة الافتراضية وتخفيف مخاطر الأجهزة)، وقد حققتُ بها فوزي الأول في مسابقة Pwn2Own هذا العام.

في هذه المقالة، أوجز نهجي المباشر في صيد الأخطاء البرمجية: اختيار نقطة بداية واتباع المسار بصورة حدسية حتى يلفت انتباهي شيء ما. هذا الخطأ البرمجي لافت لأنه يمكن استغلاله بصورة موثوقة نتيجة خطأ منطقي. يحدث الخطأ في حالة محددة داخل نظام اتصال بين العمليات، ما يؤدي لاحقًا إلى use-after-free. يتطلب العثور على الخطأ مقارنة مسارات التعليمات البرمجية الخاصة بالبرنامج عبر حالاته المختلفة المحتملة، وهي العملية التي وصفتها بالتفصيل. ولا يقل إثارة للاهتمام أصل هذا الخطأ البرمجي ونهج Microsoft في تصحيحه. ويتناول هذا المنشور هذه الموضوعات أيضًا.

البحث عن ثغرات من اليوم الأول: من أين تبدأ؟

من الأسئلة الشائعة التي أتلقاها حول البحث عن الثغرات الأمنية هو كيف أبدأ. في الواقع، قد يكون اختيار الهدف والالتزام به من أصعب الخطوات في عملية البحث. توجد الثغرة الأمنية التي تمت مناقشتها هنا في Microsoft Kernel Streaming Service (mskssrv.sys). راجع منشور المدونة هذا للحصول على نظرة عامة على النظام الفرعي. في ذلك المنشور، أشرت إلى بعض خصائص النظام الفرعي MSKSSRV التي قد تجعله سطحًا جيدًا للهجوم، وتحديدًا آلية الاتصالات بين العمليات (IPC) الخاصة به.

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

طرق على الباب: من الطارق؟

من أفضل الطرق لاكتساب أفكار بحثية جديدة البقاء على اطلاع بالأبحاث الحالية. قرأت منشور مدونة ممتازًا على k0shl كان مصدر إلهامي للبحث عن نوع معين من الحشرات. في الثغرة التي اكتشفها k0shl، يتم تهيئة عدد مراجع الكائن وزيادته من دون آلية قفل مناسبة، ما يخلق نافذة يمكن أن يحدث خلالها use-after-free. ورغم أن الخطأ البرمجي لدى k0shl يقع في userland وليس في نواة، فإن أسلوب كتابة تعليمات برمجية في المكتبة المعرّضة للثغرة ذكّرني بتدقيقي السابق لبرنامج التشغيل MSKSSRV.

يتفاعل MS KS Server (MSKSSRV) مع عملية في userland عبر كائناتFSStreamReg و FSContextReg . FSStreamReg و FSContextReg كلاهما مشتق من FSRegObject base class. لاحظت أن FSContextReg لا تنفذ دالة قفل ضمن vtable، وأن تنفيذ (FSRegObject ) base class ليس سوى تعليمات nop. وهذا يعني أنه لم يتم تنفيذ أي آلية قفل فعليًا لكائناتFSContextReg. وعلى العكس من ذلك ، ينفذ FSStreamReg دالة قفل تستخدم كائن المزامنة (mutex). وتُستخدم آلية القفل عند الوصول إلى الكائنات لأغراضر التنظيف، في الدالةFSRendezvousServer::Close:

لقطة شاشة لدالّة FSRendezvousServer::Close

كتلة التعليمات البرمجية 1: FSRendezvousServer::Close، مسار القفل وإلغاء القفل لكائنات FSRegObjects

يوجد كائنان مشتقان من base class FSRegObject ، لكن أحد النوعين يطبق آلية قفل سليمة، بينما الآخر لا يطبق ذلك. كان هذا الأمر مثيراً للريبة بالنسبة لي. ولاختبار فرضيتي، حاولت استثارة سلوك غير معرّف عبر استخدام مراجع إلى كائن FSContextReg غير المحمي. لكن بسبب حماية القفل المطبقة على الكائن العام FSRendezvousServer  object، الذي يحمل المؤشرات إلى قوائم FSRegObjects , لم أستطع استثارة أي سلوك لافت، رغم غياب حماية القفل على كائنات FSContextReg  . ومع ذلك ، كان لدي شعور بأن هناك شيئًا "مريبًا" بشأن نظام العد المرجعي للكائن FSRegObjects  . لكنني لم أستطع تحديده بعد.

IPC في خادم MS KS

كما ذكرت في منشوري السابق، فإن جانب مشاركة الكائنات بين العمليات في MSKSSRV مسار جدير بالاهتمام من ناحية الثغرات، لذلك قررت التعمق فيه. يوضح الرسم التالي آلية IPC في هذا النظام الفرعي:

رسم تخطيطي لآلية IPC في النظام الفرعي

الرسم التخطيطي 1: الاتصال بين العمليات في MS KS Server

يؤدي فتح مُعرّف ملف لجهاز MSKSSRV عبر CreateFile إلى إنشاء FILE_OBJECT يقابل هذا المُعرّف. وباستخدام هذا المُعرّف، يمكن لعملية تهيئة دفق جديد أو كائن سياق عبر إرسال IOCTL إلى الجهاز باستخدام دالّة DeviceIoControl. تحدد عملية التهيئة أي عملية بعيدة يمكنها تسجيل الكائن عبر تحديد معرف العملية من خلال المتغيرlpInBuffer . يمكن الآن للعملية البعيدة، باستخدام مُعرّف ملف جديد لجهاز MSKSSRV، تسجيل الكائن عبر IOCTL للجهاز. يتم تخزين مؤشر FSRegObject في

Irp->CurrentStackLocation->FileObject->FsContext2.

يتم تخزين المؤشر نفسه إلى كائن FSRegObject مرتين في FsContext2: مرة في FILE_OBJECT الذي تستخدمه عملية التهيئة، ومرة فيFILE_OBJECT الذي تستخدمه عملية التسجيل. وبهذه الطريقة، يمكن مشاركة المراجع إلى كائن FSRegObject عبر العمليات. فعلى سبيل المثال، باستخدام كائن FSStreamReg يمكن لعدة عمليات الوصول إلى مخزن إطار الدفق المؤقت، كما هو موضح في الرسم التخطيطي 1. يتم تهيئة عدد مراجع FSRegObject إلى 1، ثم تتم زيادته مرة أخرى بعد اكتمال التهيئة. ويؤدي تسجيل FSRegObject إلى زيادة عدد مراجعه مرة أخرى، ليصبح المجموع ثلاثة مراجع لكل كائن.

رسم تخطيطي لتهيئة كائنات FSContextReg وتسجيلها

الرسم التخطيطي 2: تهيئة كائنات FSContextReg وتسجيلها

العثور على خطأ برمجي

قررت أن أعود إلى الجزء الذي دقّقته سابقًا بحثًا عن ثغرات تتعلق بآليات القفل. لاحظت أن الدالةFSRendezvousClose, ، التي تستدعيFSRendezvousServer::Close ، تُستدعى ضمن روتيني الدالتين DispatchCleanup وDispatchClose في برنامج التشغيل:

لقطة شاشة لكتلة تعليمات برمجية تتضمن روتيني DispatchCleanup وDipatchCleanup لبرنامج تشغيل MS KS Server

كتلة التعليمات البرمجية 2: إجراءات DispatchCleanup وDipatchCleanup لبرنامج تشغيل MS KS Server

يعالج روتينالإرسال نوعًا واحدًا أو أكثر من IRPs، وهي طلبات إدخال/إخراج مجمّعة. في Windows، عند إغلاق جميع مراجع المُعرّف لملف ما، يتلقى برنامج تشغيل نظام الملفات المعني طلبIRP_MJ_CLEANUP  وطلب IRP_MJ_CLOSE  ، ويتولى معالجتهما روتينا الدالتين DispatchCleanup وDispatchClose في برنامج التشغيل.

في MSKSSRV، تُستدعىFSRendezvousClose  ضمن روتيني الدالتين DispatchCleanup وDispatchClose في برنامج التشغيل إذا كان المؤشر المخزّن فيIrp->CurrentStackLocation->FileObject->FsContext2  لا يساوي NULL. ومن الأمور التي لفتت انتباهي فيFSRendezvousServer::Close ، الذي سبق أن حللته، تعدد عمليات التحقق من معرف عملية الجهة المستدعية. سياق العملية مهم لأن جميع التعليمات البرمجية لوضع النواة (kernel) تعمل ضمن مساحة عناوين النواة الفردية، منفصلة عن مساحات عناوين وضع user-mode. لكل عملية سياق ذاكرة خاص في وضع user-mode، ويحدد سياق العملية التي يُنفَّذ ضمنها خيط النواة أي مساحة عناوين user-mode ستُستهدف إذا حاول الخيط الوصول إلى عناوين المستخدم. يتحقق الكود التالي مما إذا كانت العملية المستدعية هي عملية التهيئة أو عملية التسجيل:

لقطة شاشة لدالّة FSRendezvousServer::Close

كتلة التعليمات البرمجية 3: FSRendezvousServer::Close، فحوصات العملية على FSRegObjects

يتم تخزين معلومات خاصة بالعملية فيFSRegObject المخزّن في

 Irp->CurrentStackLocation->FileObject->FsContext2

 
في وقت التهيئة أو التسجيل. يحدد برنامج التشغيل الموارد الخاصة بالعملية (

EPROCESS

 كائنات، كائنات أحداث، وغيرها) التي يجب تحريرها عبر التحقق من معرف عملية الجهة المستدعية. وإذا كانت العملية هي عملية التهيئة أو عملية التسجيل، تُجرى عملية تنظيف إضافية لتلك الموارد الخاصة بالعملية.

لفت هذا انتباهي لأن إجراءات Dispatch تعمل عادة ضمن سياق عملية اعتباطي، مع بعض الاستثناءات. بعبارة أخرى، يختار النظام خيطًا لتنفيذ عمل Dispatch، واختيار الخيط يكون اعتباطيًا. اكتشفت أنDispatchCleanup تُستدعى ضمن سياق العملية التي أغلقت المرجع الأخير لمُعرّف. لذلك، في هذه الحالة تبدو فحوصات معرف العملية منطقية. لكنDispatchClose تُستدعى من سياق عملية اعتباطي. وهذا يعني أنه إذا تم استدعاءFSRendezvousServer::Close نتيجة طلبIRP_MJ_CLOSE ، فسيكون الاستدعاء من سياق عملية اعتباطي، ما يُفقد فحوصات معرف العملية الهدف منها. كانت هذه إشارة قوية إلى وجود خطأ برمجي هنا.

إضافة إلى ذلك، ومن ميزات نظام التشغيل Windows، يمكن مشاركة المُعرّفات مع عمليات أخرى (عبر وراثة عملية فرعية أو باستخدام دالّة DuplicateHandle ضمن واجهات برمجة تطبيقات النظام). وعبر مُعرّف الملف المشترك، يمكن للعملية الأخرى أيضًا التفاعل معFILE_OBJECT نفسه.

رسم تخطيطي لمشاركة مُعرّف جهاز MS KS Server

 الرسم التخطيطي 3: مشاركة مُعرّف جهاز MS KS Server

وبناءً على ذلك، قد يكون سياق العملية أثناء DispatchCleanup  ليس سياق عملية التهيئة ولا سياق عملية التسجيل.. إذا تم تكرار أي من مُعرّفات الملفات هذه ومشاركته مع عملية أخرى، وكانت تلك العملية هي آخر من يغلق المُعرّف، فسيتم استدعاء DispatchCleanup ضمن سياق تلك العملية الخارجية (وهي ليست عملية التهيئة ولا عملية التسجيل).

رسم تخطيطي لقيام عملية خارجية بإغلاق آخر مُعرّف مرتبط بكائن FILE_OBJECT

الرسم التخطيطي 4: إغلاق عملية خارجية لآخر مُعرّف مرتبط بكائن FILE_OBJECT

لاحظت أن الدالة FSRendezvousServer::Close قد تُستدعى مرتين عند إغلاق معرّف الملف (مرة لطلبIRP_MJ_CLEANUP ومرة واحدة لطلب IRP_MJ_CLOSE ، كتلة التعليمات البرمجية 2). وداخل هذه الدالة، هناك استدعاءان محتملان للدالة FSRegObject::Release (كتلة التعليمات البرمجية 4) ، وهي تقوم بإلغاء مرجعية الكائن (dereference) وتحرير ذاكرته إذا انخفض عدد المراجع إلى 0. وهذا يعني أن FSRegObject::Release قد تُستدعى حتى أربع مرات للمعرّف الواحد. إضافة إلى ذلك، توجد معرّفان لملفين يشير فيهما FILE_OBJECT  إلى الكائن نفسه FSRegObject عبر المعرّف FSContext2 وهذا يعني احتمال استدعاء FSRegObject::Release  ما يصل إلى ثماني مرات على الكائن نفسه، أربع مرات لكل معرّف. وإذا كان عدد المراجع الأصلي للكائن ثلاثة فقط، فقد ينشأ احتمال لثغرة use-after-free نتيجة كثرة عمليات إلغاء المرجعية. على أي حال، هذا كان مسار تفكيري. وكنت أعلم أن بنية البرنامج ستمنع على الأرجح الوصول إلى الحد النظري الأقصى لعدد عمليات إلغاء المرجعية، لكن ربما ليس بالقدر الكافي. في هذه المرحلة شعرت أنني اقتربت من خيط مهم، فقررت التعمق أكثر في التحقيق.

لقطة شاشة من FSRegObject::Release يمكن استدعاؤها مرتين من FSRendezvousServer::Close

كتلة التعليمات البرمجية 4: يمكن استدعاء FSRegObject::Release مرتين من FSRendezvousServer::Close

بوجه عام، ليس تجاوز عدد عمليات إلغاء المرجعية (dereferences) عدد المراجع (references) على كائن هو الطريقة الوحيدة لحدوث use-after-free. لكن في هذه الحالة، يمكننا الجزم بأنه إذا تم تحرير FSRegObject فإن عدد مراجع هذا الكائن يكون قد انخفض إلى الصفر. آخر مرة يتم فيها الوصول إلى FSRegObject صالح أثناء طلبات IRP_MJ_CLEANUP/CLOSE IRP تكون في استدعاء FSRegObject::Release . لذلك، إذا كان حدوث use-after-free ممكنًا، فإن استدعاء FSRegObject::Release سيحدث دائمًا بعد أن يكون الكائن قد حُرّر بالفعل. وأثناء هذا الاستدعاء، ستتم مرة أخرى عملية إلغاء مرجعية الكائن. ولهذا السبب، يعدّ إحصاء عدد عمليات إلغاء المرجعية مؤشرًا استدلاليًا جيدًا لاكتشاف حالات use-after-free في هذه الحالة تحديدًا.

ولم يبقَ سوى تتبع الحالات المحتملة للبرنامج مع تسجيل مواضع تحرير الكائن ومواضع الوصول إليه. وقمت بذلك عبر محاكاة منطق البرنامج ذهنيًا أثناء طلبات IRP_MJ_CLEANUP/CLOSE ، بحيث يبدأ كل سيناريو بدوال Dispatch المقابلة (كتلة التعليمات البرمجية 2)، لكل حالة محتملة.

يوضح ما يلي الحالات وفقًا للعملية التي تغلق المرجع الأخير لمُعرّف. يمثّل كل إدخال عدد عمليات إلغاء المرجعية (dereferences) لكائن FSContextReg التي تحدث إذا قامت العملية المعنية بإغلاق المُعرّف الأخير. ملاحظة: لا يوجد فرق وظيفي بين HANDLE #1 (initializing handle) وHANDLE #2 (registering handle)، لأن الحقل FileObject->FSContext2 يشير إلى الذاكرة نفسها في كل FILE_OBJECT يمثلهما المُعرّفان المقابلان.

لقطة شاشة لعمليات إلغاء المرجعية لكائن FSContextReg لكل حالة محتملة من حالات IPC في MSKSSRV

عمليات إلغاء المرجعية لكائن FSContextReg لكل حالة محتملة من حالات IPC في MSKSSRV

نجاح! تؤدي الحالة الأخيرة إلى أربع عمليات إلغاء مرجعية: عمليتان من العملية الخارجية وعمليتان من عملية التهيئة (ومن عملية التسجيل أيضًا)، بينما يكون عدد المراجع في البداية ثلاثة فقط؛ ما يعني أن حدوث use-after-free ممكن. وكررت التمرين نفسه مع كائنات FSStreamReg، لكن بسبب خطأ برمجي لتسرب الذاكرة في تعليمات برمجية، لا يمكن فعليًا تحرير كائن FSStreamReg بعد تسجيله.

الثغرة الأمنية

وأثناء تنفيذ التمرين الذهني المشار إليه أعلاه، وجدت المشكلة. إذا كانت العملية هي عملية التهيئة أو عملية التسجيل، تُنفّذ عملية التنظيف المناسبة، ويتم ضبط المؤشر المخزّن في Irp->CurrentStackLocation->FileObject->FsContext2 إلى NULL. توضح كتلة التعليمات البرمجية أدناه موضع حدوث ذلك عندما تكون الجهة المستدعية هي عملية التهيئة:

لقطة شاشة لدالّة FSRegObject::CloseInitProcess وهي تضبط مؤشر FSContext على NULL

كتلة التعليمات البرمجية 5: FSRegObject::CloseInitProcess يضبط مؤشر FSContext على NULL

وهذا يعني أن FSRendezvousClose لن تُستدعى مرة أخرى أثناء إكمال طلب IRP_MJ_CLOSE في DispatchClose (SrvDispatchClose، كتلة التعليمات البرمجية 2).

لكن إذا كانت العملية المستدعية عملية خارجية، فلن يحدث تنظيف، وستُستدعى FSRegObject::Release مرة واحدة قرب نهاية الدالّة. وبما أن FileObject->FsContext2 لا يساوي NULL، تُستدعى FSRendezvousServer::Close مرة أخرى أثناء طلب  IRP_MJ_CLOSE اللاحق، ويحدث استدعاء إضافي لـ FSRegObject::Release.

الآن، إذا تم إغلاق المُعرّف الثاني بواسطة عملية قامت بتهيئة كائن FSContextReg وتسجيله معًا، فسيقوم الكائن بتنظيف موارد العملية المخزنة لديه، ما يجعله فارغًا. يؤدي ذلك إلى استدعاء FSRegObject::Release  مرتين داخل FSRendezvousServer::Close (كتلة التعليمات البرمجية 4). تُستخدم عملية إلغاء المرجعية الإضافية لموازنة مرجع التهيئة الإضافي بعد أن يصبح الكائن فارغًا.

وبذلك يصبح المجموع أربع عمليات إلغاء مرجعية على كائن FSContextReg واحد، ما يشير إلى حدوث use-after-free.

رسم تخطيطي يوضح CVE-2024-30089

الرسم التخطيطي 5: توضيح CVE-2024-30089

قد يتساءل القارئ: لماذا لا يمكن أن تكون عملية خارجية آخر من يغلق المُعرّفين معًا، ما دام ذلك يبدو أنه سيؤدي أيضًا إلى أربع عمليات إلغاء مرجعية؟ قبل تدمير الكائن وتحريره، يتم فصله من قائمة مخزنة في الكائن العام FSRendezvousServer . في بداية FSRendezvousServer::Close يتم التحقق من أن المؤشر في FSContext2 عضو صالح في القائمة. في هذه الحالة، يتم تحرير الكائن عند الاستدعاء الثاني للكود FSRegObject::Release في نهاية الدالّة. أثناء الاستدعاء الرابع للكود FSRendezvousServer::Close، يكون الكائن قد فُصل بالفعل من القائمة، ما يجعله كائنًا غير صالح، وبالتالي لا يمكن استخدامه. لاستغلال الثغرة use-after-free، يجب أن يحدث ذلك بعد استرجاع الكائن والتحقق من صلاحيته في الكود FSRendezvousServer::Close. يوضح مقتطف تعليمات برمجية أدناه ركيزة use-after-free التي يمكن الحصول عليها عبر الثغرة:

لقطة شاشة لمسار ركيزة (UAF)

كتلة التعليمات البرمجية 6: مسار ركيزة UAF

تعقيد الاختراق

في دليل التحديث الأمني لهذه الثغرة الأمنية، تشير درجة CVSS إلى أن "الاستغلال [هو] أكثر احتمالاً" كما أن تعقيد الهجوم لهذه الثغرة "منخفض". ورغم أن Microsoft لا تقدم تفسيرات تفصيلية لدرجاتها، فقد لاحظت بعض الأنماط أثناء مقارنة فروق التصحيحات لثغرات أخرى. ويرجح أن الثغرة حصلت على هذه الدرجة لأنها ناتجة عن خطأ منطقي، ما يجعل استثارتها ممكنًا بصورة موثوقة. ومن خلال اتباع الخطوات الموضحة في الرسم التخطيطي 5، يمكن للمخترق استثارة سيناريو use-after-free الموضح في كتلة التعليمات البرمجية 6 بصورة متكررة. ومع ذلك، لا يعني هذا أن استغلالها عمليًا أمر مباشر. وسيتم تناول شرح تفصيلي لخطوات الاستغلال في الجزء التالي من هذه السلسلة.

مراجعة لاحقة

يُعد فهم كيفية حدوث الخطأ البرمجيّ أمرًا مهمًا لترسيخ نهج استباقي في ممارسات التطوير الآمن. ولتحديد كيفية إدخال الثغرة الأمنية، حلّلت إصدارات سابقة من برنامج التشغيل حصلت عليها من Winbindex، وبحثت عن أي اختلافات منطقية في الدالة FSRendezvousServer::Close .

في قسم الثغرات الأمنية، ذكرت أن السبب النهائي لهذا الخطأ هو عدم ضبط
 

Irp->CurrentStackLocation->FileObject->FsContext2

 
إلى 

NULL

 إذا كانت عملية الاستدعاء خارجية. لدهشتي، رأيت السطر نفسه من التعليمات البرمجية في إصدار مبكر من mskssrv.sys:

لقطة شاشة لتعليمات برمجية من إصدار مبكر من FSRendezvousServer::Close حيث تم ضبط FsContext2 على NULL

كتلة التعليمات البرمجية 7: إصدار مبكر من FSRendezvousServer::Close، حيث تم ضبط FsContext2 على NULL

في كتلة التعليمات البرمجية المعروضة أعلاه، يتم ضبط FileObject->FsContext2   صراحة على NULL ، بصرف النظر عن نتيجة فحوصات معرف العملية السابقة. وهذا يمنع استدعاء FSRendezvousServer::Close مرة أخرى في طلب IRP_MJ_CLOSE ، اللاحق، وبالتالي لا يمكن أن تحدث عملية إلغاء المرجعية الإضافية. هذا غريب—فلماذا أُزيل هذا السطر من التعليمات البرمجية؟ لنلقِ نظرة على إصدار لاحق من الدالة، حيث ظهر الخطأ البرمجيّ للمرة الأولى:

لقطة شاشة لضبط FsContext على NULL ضمن فحص علامة الميزات (feature flag)

كتلة التعليمات البرمجية 8: ضبط FsContext على NULL ضمن فحص علم ميزة

يظهر في كتلة التعليمات البرمجية أعلاه فحص لعلامة الميزة

Feature_Servicing_TeamsUsingMediaFoundationCrashes

.
أعلام الميزات مكوّن في Windows يفعّل أو يعطّل وظائف وتجارب مختلفة، رغم محدودية المعلومات المتاحة عنها علنًا. في هذه التدوينة نناقش كيف استُخدمت أعلام الميزات في تصحيحات الثغرات. تُستخدم أعلام الميزات أحيانًا لاختبار وظيفة قبل اعتمادها رسميًا. في هذه الحالة، إذا كان ملف

Feature_Servicing_TeamsUsingMediaFoundationCrashes

عند تفعيل الميزة، لا يتم ضبط FileObject->FsContext2 على NULL، ما يؤدي إلى حدوث الثغرة. لوحظ أن هذه الميزة مفعّلة افتراضيًا في تثبيتات Windows 10. في Windows 11، وكما يظهر في كتلة التعليمات البرمجية 1، لا يظهر هذا الشرط الخاص بعلم الميزة (feature flag)، ولا يتم ضبط المؤشر على NULL، ما يجعل النظام عرضة للثغرة أيضًا.

 

وبسبب اسم الميزة، بحثت في وظائف Microsoft Teams، وهو برنامج لمؤتمرات الفيديو. وأكدت أن التطبيق يمكنه استخدام وظائف MSKSSRV لمشاركة تدفقات الوسائط عبر العمليات. من المحتمل أن مشاركة مُعرّف الدفق كانت تتسبب في تعطل Teams. ومن الموضوعات المثيرة لمزيد من البحث دراسة كيفية مشاركة Teams لمُعرّفات جهاز MSKSSRV عبر العمليات، ولماذا قد يؤدي تنظيف المؤشرات بصورة صحيحة إلى تعطل التطبيق.

التصحيح

يركز هذا الجزء من السلسلة على الثغرة الأمنية نفسها، بما في ذلك تصحيحها. وكنت مهتمًا على نحو خاص بفحص تصحيح هذا الخطأ البرمجي، لأن الإصلاح الذي اقترحته بدا أنه يتسبب في أعطال داخل Microsoft Teams. ومن المهم التنبيه إلى أنني حتى هذه اللحظة لم أدرس بعد كيفية استخدام تطبيق فعلي لبرنامج التشغيل MSKSSRV عمليًا. وغياب هذا السياق يخلق ثغرات عند محاولة فهم سبب تصميم النظام بهذه الصورة. قد يتطلب التصحيح الكامل لهذا الخطأ البرمجي قدرًا من إعادة هيكلة تعليمات برمجية الأساسية، وقد يكشف مزيدًا من التفاصيل حول كيفية عمل نظام IPC كما هو مقصود. كما كنت آمل استخلاص بعض الرؤى حول ممارسات البرمجة الآمنة من مطوري Microsoft.

لخيبة أملي، لم تتم معالجة الخطأ المنطقي الذي تسبب في الثغرة الأمنية، رغم تصحيحه ضمن تحديثات الأمان لشهر يونيو 2024، بشكل مباشر. بدلاً من ذلك، تمت إضافة فحص رمز مميز قبل مسارات التعليمات البرمجية المعرضة للثغرة. اطّلع على الكود أدناه لطلب initialize context عبر IOCTL، الذي تتولى معالجته الدالة FSRendezvousServer::InitializeContext :

تبدأ لقطة شاشة لوظيفة IOCTL بفحص علامة الميزات وتتحقق مما إذا كانت عملية الاستدعاء عبارة عن خادم إطار

كتلة التعليمات البرمجية 9: تبدأ دالّة IOCTL بفحص علامة الميزات (feature flag)، وتتحقق مما إذا كانت العملية المستدعية خادم إطار (frame server)

تبدأ الدالة أعلاه بالتحقق مما إذا كانت ميزة مّا مفعّلة. من المحتمل أن تكون هذه علامة الميزة المقابلة للتصحيح. إذا كانت الميزة مفعلة، فيجب أن تُعيد KsIsCurrentProcessFrameServer قيمة TRUE، وإلا فتعيد قيمةNTSTATUS  وهي STATUS_ACCESS_DENIED .

لنلقِ نظرة على KsIsCurrentProcessFrameServer :

لقطة شاشة لدالّة KsIsCurrentProcessFrameServer وهي تجري فحص SID على access token الخاص بالخيط المستدعي

كتلة التعليمات البرمجية 10: KsIsCurrentProcessFrameServer يجري فحص SID على access token الخاص بالخيط المستدعي

تتحقق هذه الدالة من الرمز المميز الخاص بالخيط المستدعي بمقارنته مع معرفي أمان محددين (SIDs). وترتبط SIDs برمز مميز في المجموعة NT SERVICE\FrameServer . إذا كان أي من SIDs مفعّلًا في الرمز المميز الخاص بالخيط المستدعي، فيمكن تنفيذ كود الدالة المعرّض للثغرة.

بعد الاطلاع على ذلك، اشتبهت في أن الخطأ البرمجي Administrator to Kernel ما زال قائمًا. وفي النهاية، لم تُعالج مشكلات تلف الذاكرة مطلقًا. وأكدت ذلك عبر إجراء تعديل بسيط على الاستغلال الأصلي: يمكن لمستخدم Administrator تشغيل الخدمة FrameServer ، وفتح مُعرّف للخدمة، ثم إنشاء عملية الاستغلال باستخدام هذا المُعرّف. وتمكنت من الحصول على نسخة أولية كاملة للقراءة والكتابة في نواة على نظام مطبّق عليه جميع التصحيحات.

ورغم أن Microsoft لا تعتبر الانتقال من المسؤول إلى النواة (Administrator to Kernel) حدًا أمنيًا، فقد استخدمت عناصر التهديد أخطاء برمجية مماثلة للحصول على نسخة أولية (primitive) للقراءة والكتابة في نواة، ثم استخدامها في تعمية EDR وعمليات rootkit. إذا كنت مهتمًا بمعرفة نوع الأشياء التي يمكن القيام بها باستخدام هذه النسخة الأولية، راجع محاضرتي في BlackHat مع FuzzySec.

الخلاصة والخطوات التالية

ركّز هذا المنشور على جزء أبحاث الثغرات ضمن مشاركتي في Pwn2Own، والذي تمثل في العثور على ثغرة اليوم الأول في نواة يمكن استغلالها لزيادة الامتيازات. ويعرض هذا المنشور مسار الرحلة: الاستلهام من أبحاث أخرى، والفشل في العثور على خطأ برمجي، واختيار زاوية جديدة، ثم ملاحظة ما يثير الشك، وأخيرًا تحديد موضع الثغرة. الآن بعد تحديد خطأ برمجي ووجود نسخة أولية (primitive) لحالة use-after-free، يفترض أن الباقي سيكون مباشرًا، أليس كذلك؟ يبدو أن Microsoft ترى ذلك، إذ قيّمت هذا الخطأ البرمجي بأنه "Exploitation More Likely" مع تعقيد هجوم "low". هل هم على حق؟ سأتناول ذلك، واستراتيجية الاستغلال، وأكشف معنى عنوان السلسلة في الجزء التالي.

شكر وتقدير

Andréa Piazza، تقديرًا للمخططات الرائعة

Emma Kirkpatrick، لشرح نموذج أمان Windows لي بصبر

Mixture of Experts | 12 ديسمبر، الحلقة 85

فك تشفير الذكاء الاصطناعي: تقرير إخباري أسبوعي

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