
KslDump — Зачем приносить собственный нож, если Defender уже оставил один на кухне?
Я сообщил об этой проблеме в Microsoft 7 марта 2026 года. Однако почти на 20 дней раньше сообщество по взлому игр уже реверсировало и публично обсуждало эту уязвимость. Со своей стороны, я не слежу за их проектами и не знал об этом. Также очевидно, что это два совершенно разных и не связанных между собой проекта.
Зачем нести свой нож, если Defender уже оставил один на кухне?
KslDump извлекает учетные данные из защищенного PPL процесса LSASS, используя только компоненты, подписанные Microsoft. Никакой эксплойт не применяется. Никакой драйвер не загружается. Вся цепочка атак поставляется предустановленной вместе с Windows Defender. Microsoft исправила рабочую версию (wd\KslD.sys), обнулив MmCopyMemory, но оставила старую уязвимую версию (drivers\KslD.sys) на диске. Злоумышленнику не нужно ничего приносить — он просто перенаправляет службу обратно на то, что Microsoft забыла удалить.
https://github.com/user-attachments/assets/78dfce25-56b3-4eb8-9de2-7c183601e597
KslD.sys — это драйвер режима ядра, поставляемый с Microsoft Defender. Он подписан Microsoft, загружается как доверенный модуль ядра и предоставляет объект устройства \\.\KslD, доступный из пользовательского режима.
Драйвер принимает IOCTL 0x222044 с несколькими подкомандами, которые предоставляют неограниченный доступ к памяти ядра и физической памяти любому процессу, который может открыть дескриптор устройства.
| SubCmd | Возможность | Влияние |
|---|---|---|
| 2 | Возвращает CR3, IDTR и другие регистры управления ЦП в пользовательский режим | Мгновенный обход KASLR |
| 12 | Вызывает MmCopyMemory() с контролируемыми злоумышленником адресом и размером | Произвольное чтение памяти ядра/физической памяти |
Единственный шлюз к дескриптору устройства — это строка имени процесса, хранящаяся в ключе реестра (AllowedProcessName) в разделе службы драйвера. Это значение:
Разница всего в одной строке в CCommand::Initialize:
// 82 KB version (patched) — deliberately clears the pointer:
v3 = MmGetSystemRoutineAddress(L"MmCopyMemory");
if (v3 >= 0) {
*(a1 + 24) = 0; // ← NULLs it — SubCmd 12 is dead
}
// 333 KB version (vulnerable) — stores the pointer:
ptr = MmGetSystemRoutineAddress(L"MmCopyMemory");
if (ptr) {
*(this + 0x18) = ptr; // ← Keeps it — SubCmd 12 works
}
Похоже, что обновления платформы Defender помещают исправленную версию размером 82 КБ в drivers\wd\ и указывают ImagePath на нее, в то время как старая версия размером 333 КБ остается в drivers\. На протестированных системах старый двоичный файл никогда не удалялся. Эксплойт просто переключает ImagePath обратно на уязвимую версию и перезапускает службу. Оба двоичных файла подписаны Microsoft и доверяются ОС.
Публичная документация Microsoft показывает, что KB4052623 доставляет обновления платформы Defender, включая историческое перемещение драйверов Defender в System32\drivers\wd, в то время как обслуживание Windows хранит файлы хранилища компонентов на основе WinSxS через жесткие ссылки NTFS и удаляет устаревшие версии компонентов только во время очистки. На протестированной системе это объясняет, почему новая версия KslD.sys размером 82 КБ могла появиться через путь обновления платформы Defender, в то время как старая версия System32\drivers\KslD.sys размером 333 КБ оставалась как текущая копия хранилища компонентов на основе CBS до тех пор, пока не была заменена более новой версией CBS.
Microsoft поддерживает Список блокировки уязвимых драйверов (DriverSiPolicy.p7b) специально для предотвращения атак BYOVD. Этот список блокировки применяется через HVCI и блокирует загрузку известных уязвимых подписанных драйверов.
Из собственной документации Microsoft:
«Список блокировки уязвимых драйверов предназначен для помощи в укреплении систем против драйверов, разработанных не Microsoft, во всей экосистеме Windows»
Собственные драйверы Microsoft исключены из списка блокировки по замыслу.
Коренная причина проста: MmCopyMemory не уважает PPL.
PPL (Protected Process Light) был разработан для предотвращения кражи учетных данных путем блокировки вызовов OpenProcess и ReadProcessMemory к LSASS. Но PPL защищает только путь API пользовательского режима. Он не имеет власти над чтениями физической памяти в режиме ядра.
KslD.sys предоставляет коду пользовательского режима прямой путь к MmCopyMemory() — собственному API ядра Microsoft для копирования памяти по физическому или виртуальному адресу. Драйвер выполняет:
Результат: подписанный Microsoft драйвер предоставляет полный обход PPL из коробки.
Ядро уязвимости — SubCmd 12 — неограниченная обертка для MmCopyMemory():
IOCTL: 0x222044
Input: struct {
DWORD SubCmd; // 12
DWORD Reserved; // 0
QWORD Address; // Target VA or PA
QWORD Size; // Bytes to read
DWORD Flags; // 1 = Physical, 2 = Virtual
DWORD Padding;
}
Output: Raw memory contents (up to Size bytes)
Физическое чтение (Flags = 1) является критическим примитивом. Доступ к физической памяти не подчиняется уровням защиты процессов, флагам EPROCESS или каким-либо ограничениям API пользовательского режима — именно это обходит PPL.
Виртуальное чтение (Flags = 2) напрямую читает виртуальные адреса ядра, полезно для обхода структур ядра (EPROCESS, экспорты ntoskrnl) без ручного преобразования таблиц страниц.