
تقرير فني حول واستغلال PoC لـ CVE-2020-11519 و CVE-2020-11520
التاريخ: يونيو 2020
المؤلف: دينيس إلسر (الكود: github)
بالإشارة إلى تمثيلها على الويب، فإن Winmagic SecureDoc "تسمح للشركات بالتعامل مع أمان بيئة تكنولوجيا المعلومات الخاصة بها بكفاءة، مستفيدة من ميزات تشمل: التشفير الكامل للقرص (FDE)، والمصادقة متعددة العوامل، وتشفير حاويات الوسائط القابلة للإزالة (RMCE)، وتشفير الملفات والمجلدات (FFE). تساعد هذه الميزات الشركات على زيادة الأمان، وتخفيف مخاطر الأعمال، وتلبية المتطلبات الحكومية والتنظيمية لتشفير القرص الصلب."
يتأثر منتج Winmagic SecureDoc، المتوفر في إصدارات مستقلة ومؤسسية، بثغرات رفع صلاحيات محلية (CVE-2020-11519 و CVE-2020-11520) في الإصدارات 8.3 و 8.5. بعد الإبلاغ عن الثغرات لشركة Winmagic في أواخر مارس، أصدر البائع تصحيحًا (الإصدار 8.5SR2) في منتصف يونيو 2020. ومع ذلك، وُجد أن هذا التصحيح يعالج الثغرات بشكل غير كافٍ، مما جعل الإصدار 8.5SR2 أيضًا عرضة للثغرات المبلغ عنها. على الرغم من حجب التفاصيل التقنية حول الثغرات لهذا السبب، فقد اعتبرت الثغرات علنية منذ ذلك الحين. وفقًا للبائع، هناك تصحيح آخر قيد الإعداد، بعد حوالي 106 أيام من التقرير الأولي للثغرة لشركة Winmagic. في 15 يوليو، بعد 111 يومًا من التقرير الأولي للثغرة للبائع، أصدرت Winmagic SecureDoc v8.5 SR2 HF1 للعملاء، والذي يُفيد بإصلاح CVE-2020-11519 و CVE-2020-11520. لم يتم اختبار إصدارات SecureDoc الأقدم من 8.3، ولكن يمكن افتراض أنها متأثرة أيضًا، بناءً على كود المكون المتأثر.
سيؤدي الاستغلال الناجح لأي من الثغرات إلى رفع الصلاحيات إلى صلاحيات النظام للمهاجمين المحليين الموثقين.
تؤثر كلتا الثغرات على المكون "SDDisk2k.sys"، وهو برنامج تشغيل Kernel يأتي مع منتج Winmagic SecureDoc. تم تحديد الثغرات الأمنية باستخدام التحليل الثابت اليدوي بمساعدة أداة تفكيك وفك الترجمة Hex-Rays IDA Pro. بأثر رجعي، كان من الممكن اكتشاف نقاط الضعف بجهد أقل بكثير إذا تم تطبيق طرق الاختبار الديناميكية مثل التشويش (fuzzing) بدلاً من ذلك. وذلك لأن برنامج التشغيل يمكن التفاعل معه من تطبيقات وضع المستخدم المحدودة، ويفترض افتراضيًا أن مدخلاتها جيدة الصياغة.
بسبب الإنشاء غير الآمن لبرنامج التشغيل "SDDisk2k.sys" لكائن جهاز "SecureDocDevice" وغياب الكود الذي سيؤسس واصف أمان مناسب، حتى حسابات المستخدمين المحدودة تحصل على القدرة على الحصول على مقبض للجهاز باستخدام دالة API CreateFile(). مع منح برنامج التشغيل لتطبيق وضع المستخدم مقبضًا لكائن جهازه، فإنه يفتح بذلك مسارًا مباشرًا لسطح الهجوم الخاص به في عالم kernel.``` c RtlInitUnicodeString(&DestinationString, L"\Device\SecureDocDevice"); RtlInitUnicodeString(&SymbolicLinkName, L"\DosDevices\SecureDocDevice"); if ( IoCreateDevice(v1, 0xDD8u, &DestinationString, 0x8D1Fu, 0, 0, &DeviceObject) >= 0 ) // <--- unsafe { memset(DeviceObject->DeviceExtension, 0, 0xDD8ui64); DeviceObject->Flags |= 4u; DeviceObject->AlignmentRequirement = 0; if ( IoCreateSymbolicLink(&SymbolicLinkName, &DestinationString) < 0 ) IoDeleteDevice(DeviceObject); IoObject = DeviceObject; }
من خلال الهندسة العكسية لعدد من معالجات خدمة [IOCTL](https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/introduction-to-i-o-control-codes) لبرنامج التشغيل "SDDisk2k.sys"، تم اكتشاف أن أحدها يعرض وظائف حاسوبية لوضع المستخدم، حيث يسمح بعمليات القراءة والكتابة لقطاعات القرص الخام لأي محرك أقراص - حسب التصميم. بالإضافة إلى ذلك، من خلال التفاعل مع هذا الكود نفسه، لوحظ أن برنامج التشغيل يتجاهل أي أقفال حصرية قد تكون تم تعيينها مسبقًا على محرك أقراص. ونتيجة لذلك، أصبحت عمليات القراءة/الكتابة المتزامنة ممكنة، مما يسهل ظروف السباق ويخاطر بفقدان البيانات.
يوضح ما يلي معالج خدمة IOCTL المُفكك لبرنامج التشغيل المسؤول عن معالجة طلبات قراءة قطاعات القرص الخام. يستدعي دالة sub_29CD4() بوسيطة "controlled_buf"، وهي مؤشر لمخزن مؤقت يمكن اختيار محتواه بشكل تعسفي بواسطة أي تطبيق يستدعي من وضع المستخدم:``` c
if ( ioctlcode == 0x8D1F2824 ) // <--- I/O control code for raw disk reading functionality
{
controlled_buf = (unsigned __int8 *)controlled_addr;
mode = 0;
temp_result = sub_29CD4((char *)controlled_buf, v3, mode); // <--- call to raw disk read function
في الواقع، هذه المخزن المؤقت الذي يسيطر عليه المهاجم هو بنية تحتوي حقولها "offset" و"length" و"ptr_buf" على وسائط دالة غير مُتحقق منها بالكامل تم تمريرها إلى استدعاء IoBuildSynchronousFsdRequest(). تقوم الدالة الأخيرة بإعداد حزمة طلب إدخال/إخراج IRP_MJ_READ (IRP) التي ترسلها إلى برنامج تشغيل نظام الملفات الأساسي باستخدام استدعاء IofCallDriver():``` c __int64 __fastcall sub_29CD4(char *controlled_addr, PIRP a2, char mode) { //[...snip...] // extract drive number and type (floppy/hd) from offset 0 devicetype_and_num = (unsigned __int8)*controlled_buf // <--- controllable from user mode
// advance pointer p = controlled_buf + 1;
// build device name if ( (devicetype_and_num & 0x80u) == 0 ) v11 = vsnprintf_wrapper(&device_name, 0x3Fui64, L"\Device\Floppy%d", devicetype_and_num); else v11 = vsnprintf_wrapper(&device_name, 0x3Fui64, L"\Device\Harddisk%d\Partition0", devicetype_and_num & 0x7F); v12 = v11; if ( v11 >= 0 ) { RtlInitUnicodeString(&DestinationString, &device_name);
// get object pointer of drive
if ( IoGetDeviceObjectPointer(&DestinationString, 0x80u, &FileObject, &DeviceObject) >= 0
|| (v12 = sub_2C5D4(&DestinationString, &DeviceObject), v12 >= 0) )
{
// extract further fields from structure
offset = *(_QWORD *)(p + 0x4E); // <--- where to start reading from
length = *(_DWORD *)(p + 0x56); // <--- number of bytes to read
ptr_buf = *(void **)(p + 0x5A); // <--- ptr to destination buffer
devobj = DeviceObject;
StartingOffset.QuadPart = offset << 9;
KeInitializeEvent(&Event, NotificationEvent, 0);
// build request
v17 = IoBuildSynchronousFsdRequest(
(unsigned int)(mode != 0) + IRP_MJ_READ, // <--- issue read request
devobj,
ptr_buf,
length << 9,
&StartingOffset,
&Event,
&IoStatusBlock);
v18 = v17;
if ( v17 )
{
v19 = v17->Tail.Overlay.CurrentStackLocation;
if ( mode )
v19[0xFFFFFFFF].Flags |= 0x10u;
ObfReferenceObject(devobj);
// send request to respective device object (issue read request)
v12 = IofCallDriver(devobj, v18);
//[...snip...] }
تمامًا كما هو الحال مع قراءة قطاعات القرص الخام، فإن كتابة قطاعات القرص من وضع المستخدم تصبح ممكنة عن طريق استدعاء معالج IOCTL 0x8D1F2820، والذي يعالج نفس بنية البيانات ويتم تنفيذه بطريقة مماثلة. نظرًا للتوافق مع بروتوكول هذا المُشغِّل، لا يوجد ما يمنع التطبيقات العشوائية في وضع المستخدم من اختراق نظام التشغيل بالكامل. ما لم يكن محميًا بآلية إقلاع آمنة، فإن هذا يشمل حتى تثبيت برامج يُسمح لها بالعمل في وقت مبكر جدًا أثناء عملية إقلاع النظام (ransomware، bootkits، implants مخصصة...).
### CVE-2020-11520