
KslDump — لماذا تحضر سكينك الخاص بينما ديفندر قد ترك واحدة في المطبخ؟
أبلغت عن المشكلة لشركة مايكروسوفت في 7 مارس 2026. ومع ذلك، قبل حوالي 20 يوماً، كان مجتمع اختراق الألعاب قد قام بالفعل بعكس هندسة الكود ومناقشته علناً. من جانبي، لا أتابع مشاريعهم ولم أكن على علم بأي من هذا. ومن الواضح أيضاً أن هذين مشروعين منفصلين تماماً وغير مرتبطين.
لماذا تحضر سكينك الخاصة بينما قد ترك Defender بالفعل واحدة في المطبخ؟
يقوم KslDump باستخراج بيانات الاعتماد من LSASS المحمي بـ PPL باستخدام مكونات موقعة من مايكروسوفت فقط. لا يتم نشر أي استغلال. لا يتم تحميل أي برنامج تشغيل. سلسلة الهجوم بأكملها تأتي مثبتة مسبقاً مع Windows Defender. قامت مايكروسوفت بتصحيح الإصدار الجاري (wd\KslD.sys) عن طريق إفراغ MmCopyMemory، لكنها تركت الإصدار القديم الضعيف (drivers\KslD.sys) موجوداً على القرص. المهاجم لا يحضر أي شيء -他只是 يشير الخدمة مرة أخرى إلى ما نسيته مايكروسوفت تنظيفه.
https://github.com/user-attachments/assets/78dfce25-56b3-4eb8-9de2-7c183601e597
KslD.sys هو برنامج تشغيل kernel يتم شحنه مع Microsoft Defender. إنه موقّع من مايكروسوفت، ويتم تحميله كوحدة kernel موثوقة، ويعرض كائن جهاز \\.\KslD يمكن الوصول إليه من وضع المستخدم.
يقبل برنامج التشغيل IOCTL 0x222044 مع أوامر فرعية متعددة توفر وصولاً غير مقيد إلى ذاكرة kernel والذاكرة الفعلية لأي عملية يمكنها فتح مقبض الجهاز.
| SubCmd | الإمكانية | التأثير |
|---|---|---|
| 2 | إرجاع CR3 و IDTR وسجلات تحكم CPU أخرى إلى وضع المستخدم | تجاوز فوري لـ KASLR |
| 12 | استدعاء MmCopyMemory() بعنوان وحجم يتحكم فيهما المهاجم | قراءة عشوائية لذاكرة kernel/الذاكرة الفعلية |
البوابة الوحيدة لمقبض الجهاز هي سلسلة اسم العملية المخزنة في مفتاح سجل (AllowedProcessName) ضمن مفتاح خدمة برنامج التشغيل. هذه القيمة:
الفرق هو سطر واحد في CCommand::Initialize:
// الإصدار 82 كيلوبايت (مصحح) — يمسح المؤشر عمداً:
v3 = MmGetSystemRoutineAddress(L"MmCopyMemory");
if (v3 >= 0) {
*(a1 + 24) = 0; // ← يجعله NULL — الأمر الفرعي 12 ميت
}
// الإصدار 333 كيلوبايت (ضعيف) — يخزن المؤشر:
ptr = MmGetSystemRoutineAddress(L"MmCopyMemory");
if (ptr) {
*(this + 0x18) = ptr; // ← يحتفظ به — الأمر الفرعي 12 يعمل
}
تظهر تحديثات منصة Defender أنها تقوم بإسقاط الإصدار المصحح بحجم 82 كيلوبايت في drivers\wd\ وتشير ImagePath إليه، بينما يبقى الإصدار الأقدم بحجم 333 كيلوبايت في drivers\. على الأنظمة المختبرة، لم يتم حذف الثنائي القديم أبداً. يقوم الاستغلال ببساطة بتبديل ImagePath مرة أخرى إلى الإصدار الضعيف وإعادة تشغيل الخدمة. كلا الثنائيين موقعان من مايكروسوفت وموثوقان من قبل نظام التشغيل.
يظهر التوثيق العام لمايكروسوفت أن KB4052623 يوفر تحديثات منصة Defender، بما في ذلك نقل تاريخي لبرامج تشغيل Defender إلى System32\drivers\wd، بينما تحتفظ خدمة Windows بصيغ مخزنة لمكونات WinSxS عبر الروابط الصلبة NTFS، ولا يتم إزالة إصدارات المكونات السابقة إلا أثناء التنظيف. على النظام المختبر، يفسر هذا سبب وصول KslD.sys الأحدث بحجم 82 كيلوبايت عبر مسار تحديث منصة Defender بينما بقي KslD.sys الأقدم بحجم 333 كيلوبايت في System32\drivers\ كنتسخة مخزنة حالية مدعومة من CBS إلى أن تم استبدالها بإصدار CBS أحدث.
تحتفظ مايكروسوفت بـ قائمة حظر برامج التشغيل الضعيفة (DriverSiPolicy.p7b) خصيصاً لمنع هجمات BYOVD. يتم تطبيق قائمة الحظر هذه عبر HVCI وتمنع تحميل برامج التشغيل الضعيفة الموقعة المعروفة.
من توثيق مايكروسوفت الخاص:
"تم تصميم قائمة حظر برامج التشغيل الضعيفة للمساعدة في تعزيز الأنظمة ضد برامج التشغيل غير المطورة من مايكروسوفت عبر نظام Windows البيئي"
برامج تشغيل مايكروسوفت الخاصة مستبعدة من قائمة الحظر حسب التصميم.
السبب الجذري بسيط: MmCopyMemory لا يحترم PPL.
تم تصميم PPL (عملية محمية خفيفة) لمنع سرقة بيانات الاعتماد عن طريق حظر استدعاءات OpenProcess و ReadProcessMemory ضد LSASS. لكن PPL يحمي فقط مسار واجهة برمجة تطبيقات وضع المستخدم. ليس لديه سلطة على قراءات ذاكرة kernel الفعلية.
يمنح KslD.sys كود وضع المستخدم مساراً مباشراً إلى MmCopyMemory() — واجهة برمجة تطبيقات kernel الخاصة بمايكروسوفت لنسخ الذاكرة حسب العنوان الفعلي أو الافتراضي. يقوم برنامج التشغيل بما يلي:
النتيجة: برنامج تشغيل موقع من مايكروسوفت يوفر تجاوزاً كاملاً لـ PPL مباشرة.
جوهر الثغرة هو الأمر الفرعي 12 — غلاف غير مقيد لـ MmCopyMemory():
IOCTL: 0x222044
Input: struct {
DWORD SubCmd; // 12
DWORD Reserved; // 0
QWORD Address; // الهدف VA أو PA
QWORD Size; // البايتات المراد قراءتها
DWORD Flags; // 1 = فعلي، 2 = افتراضي
DWORD Padding;
}
Output: محتويات الذاكرة الخام (حتى Size بايت)
القراءة الفعلية (Flags = 1) هي الأولية الحاسمة. الوصول إلى الذاكرة الفعلية لا يخضع لمستويات حماية العملية، أو علامات EPROCESS، أو أي قيود لواجهة برمجة تطبيقات وضع المستخدم، وهذا هو ما يتجاوز PPL.
القراءة الافتراضية (Flags = 2) تقرأ عناوين kernel الافتراضية مباشرة، مفيدة لتجوال هياكل kernel (EPROCESS، صادرات ntoskrnl) دون ترجمة يدوية لجدول الصفحات.