Опасные 3rd-party драйверы в вашей системе или LOLDrivers
А вы знали, что вполне легитимный драйвер может дать злоумышленнику возможность прописаться в вашей системе надолго, оставаясь внутри даже после ее переустановки? Или превратить ваш компьютер в кирпич? Например, некоторые безобидные на вид доверенные (подписанные) драйверы являются попутно инструментами для перезаписи BIOS. После такой атаки спасет лишь программатор.
В ОC Windows существуют доверенные приложения/скрипты/библиотеки с дополнительной интересной опасной функциональностью вроде исполнения произвольного кода, загрузки файлов, обхода UAC и т.п. Если подобная дополнительная функциональность встречается у компонента ядра, становится еще интереснее.
Начиная с Windows Vista x64, действует политика Driver Signature Enforcement (DSE) – все драйверы уровня ядра должны быть подписаны. Если злоумышленник (с правами пользователя/администратора) после проникновения в систему жаждет получить максимальный уровень доступа (установить kernel rootkit/bootkit/SMM-rootkit/BIOS-rootkit), ему придется как-то обойти требование подписи для драйвера. Возможность вызова из юзермода некоторых функций или инструкций в режиме ядра может дать злоумышленнику инструмент для повышения привилегий, раскрытия информации или вызова отказа в обслуживании. Назовем такую функциональность функциональностью двойного назначения (в некоторых случаях подобное могут называть уязвимостями или бэкдорами, однако дискуссия на тему корректности определения выходит за рамки этой статьи).
Способы обхода DSE
Давайте рассмотрим, какие вообще варианты есть у злоумышленника для обхода DSE (надо же как-то проникнуть в ring0). В таблице ниже собраны способы обхода DSE с их преимуществами и недостатками (для злоумышленника, а безопасники принимают к сведению). Стоит отметить, что данная информация относится к Windows x64, начиная с Vista.
Как видно по таблице, подписанный драйвер с функциональностю двойного назначения является наиболее привлекательным для атакующего способом обхода DSE.
Опасная функциональность или функциональность двойного назначения
Рассмотрим примеры вредоносных возможностей, которые появляются у злоумышленника при наличии драйвера с опасными функциями двойного назначения.
Исполнение произвольного кода в режиме ядра. Требуется чтение/запись физической памяти и MSR. Смысл заключается в замене адреса (находится в одном из MSR), на который будет осуществлен переход при совершении системного вызова, на адрес расположения кода злоумышленника. Тут можно найти больше информации об этом. Попутно будет мешать PatchGuard, но с ним при желании можно разобраться.
Поскольку драйвер и PatchGuard оба выполняются в Ring 0, ничто не мешает драйверу отключить проверки PatchGuard (до тех пор, конечно, пока Microsoft не прислушается к Intel и не выйдет за рамки модели с двумя кольцами защиты). Разработчики ядра в Microsoft прекрасно осведомлены об этом факте и выполняют различные действия для скрытия расположения этого кода, обфускации его действий и используемых внутренних структур. Иными словами, из-за невозможности помешать вам модифицировать код PatchGuard они пытаются изо всех сил его скрыть.
— Blunden B. The Rootkit arsenal: Escape and evasion in the dark corners of the system.
Given that driver code and PatchGuard code both execute in Ring 0, there’s nothing to prevent a KMD from disabling PatchGuard checks (unless, of course, Microsoft takes a cue from Intel and moves beyond a two-ring privilege model). The kernel engineers at Microsoft are acutely aware of this fact and perform all sorts of programming acrobatics to obfuscate where the code resides, what it does, and the internal data-structures that it manipulates. In other words, they can’t keep you from modifying PatchGuard code, so they’re going to try like hell to hide it.
— Blunden B. The Rootkit arsenal: Escape and evasion in the dark corners of the system.
Если проанализировать различные статьи и заметки о CVE, то можно выделить некоторую классификацию потенциально опасных при доступе из ring3 функций в драйверах. В таблице ниже указаны опасные функции и источники информации о них.
| Выявленные опасные функции | Источники информации о способах нарушения безопасности |
|---|---|
| Чтение/запись регистров MSR | CVE-2018-10711, CVE-2018-18535, CVE-2018-19323, CVE-2007-5633, CVE-2007-5761 |
| Чтение/запись портов ввода/вывода | CVE-2018-10712, CVE-2018-18536, CVE-2018-19322 |
| Чтение/запись физической памяти | CVE-2018-16712, CVE-2018-10710, CVE-2017-15302, CVE-2017-15303, CVE-2018-19321 |
| Чтение/запись управляющих регистров | CVE-2018-10709, Eset — Windows exploitation in 2016 |
| Доступ к счетчикам мониторинга производительности/тактов | Leif Uhsadel, Andy Georges, Ingrid Verbauwhed — Exploiting Hardware Performance Counters |
| Чтение/запись регистра флагов | Wojtczuk R., Rutkowska J. Following the White Rabbit: Software attacks against Intel VT-d technolog |
| Инструкции обращения к кэшу | Cache-Based Side-Channel Attacks Detection through Intel Cache Monitoring Technology and Hardware Performance Counters |
И это далеко не весь список возможных опасных функций. Можно также говорить и о чтении/записи виртуальной памяти ядра, чтении/записи MMIO, доступе к PCI устройствами т.д.
Наибольший интерес, а также наибольшую опасность (и наибольшую вероятность обнаружить драйвер с такими функциями) представляют первые три функции: чтение/запись регистров MSR, чтение/запись портов ввода/вывода, чтение/запись физической памяти. С помощью управляющих регистров можно обойти некоторые механизмы защиты, запись в регистр флагов позволяет включить чтение/запись портов ввода/вывода в ring3 (кстати, упоминается в этой статье на Хабре), успех атак по сторонним каналам (с помощью обращения к кэшу, счетчиков мониторинга производительности/тактов), скорее всего, маловероятен.
В процессе создания данного материала на конференции DEFCON 27 в Лас-Вегасе исследователи Jesse Michael и Mickey Shkatov представили работу «Get off the kernel if you cant drive», в которой также рассказывается о данной проблеме, и мы рекомендуем изучить данный материал для полноты картины. Здесь очень просто и наглядно расписаны сценарии использования подобных драйверов и представлены примеры участков кода, отвечающих за наиболее критичную функциональность. И также представлен код по работе и поиску подобных драйверов.
Вообще стоит отметить, что данная тема уже достаточно давно волнует исследователей безопасности. Еще в 2018 году исследователь Александр Матросов в своей статье «What makes OS drivers dangerous for BIOS?» поднимал данный вопрос и демонстрировал, как достаточно просто можно проэксплотировать BIOS.
Драйверы с функциями двойного назначения
Ниже рассмотрены наиболее известные представители драйверов с функциями двойного назначения.
RwDrv.sys – очень популярный драйвер (поставляется с утилитой RWeverything). Читает и пишет физическую память, I/O порты, MSR и управляющие регистры. Был неоднократно использован в разных PoC’ах, а потом и в настоящем ранее упомянутом рутките Lojax. Для него написан интерфейс на C++, а также он используется в chipsec.
Читает и пишет физическую память, порты и MSR. Есть несколько PoC-утилит с его использованием (здесь и здесь).
pcdsrvc_x64 – драйвер от Dell, за дополнительной информацией обращаться в этот пост. Позволяет читать/писать физическую память и в I/O порты.
AsIO64.sys
Он предоставляет возможность чтения/записи физической памяти и I/O портов, а также вместе с ним идет удобная dll’ка для выполнения этих запросов.
Asmmap64.sys – еще один драйвер от ASUS, позволяющий читать/писать физическую память, I/O порты и MSR. Для злоумышленника он был бы особенно приятен, поскольку доступ к драйверу может быть осуществлен от обычного пользователя без прав администратора. Любопытные могут обратиться к первоисточнику.
ntiolib_x64.sys/winio64.sys – драйверы от MSI, подробно о них рассказано в ранее упомянутой статье. С помощью ntiolib_x64.sys можно читать/писать физическую память, I/O порты и MSR, winio64.sys предоставляет все эти функции, кроме MSR.
Обычно описанные опасные функции признают уязвимостями, если драйвер доступен пользователю без прав администратора (неправильный ACL) или когда позволяет исполнять произвольный код напрямую (как в bandainamcoonline.sys). В остальных случаях это просто функциональность, и раз у пользователя есть права администратора, то он может использовать все функции драйверов и это норма.
Если вы думаете, что подобных драйверов не больше десятка, то сильно ошибаетесь. Можете посмотреть данную подборку интересных драйверов. В этом списке есть драйверы от ASUS, AVAST, Razer, LG, American Megatrends и других известных компаний. Так что их много, нужно просто поискать. А значит, они представляют реальную угрозу.
Данную угрозу понимают и сотрудники Microsoft. И будут признательны за информацию о подобных драйверах 😉
Рекомендации
Производителям же лучше не подписывать такие драйверы. Если пользователю требуется обновить BIOS, проверить систему на наличие уязвимостей (привет, chipsec), измерить производительность или провести еще какие-нибудь манипуляции, требующие установки подобных драйверов, то он вполне может перейти в Test Mode, сделать все это, а после выйти. Usability в таком случае упадет, зато возрастет security.
Выводы
Если что-то подписано, то доверять этому все равно нельзя. Во-первых, подписать так-то можно что угодно, а во-вторых, этим подписанным (даже если оно от доверенного производителя) может воспользоваться злоумышленник.
Специалистам по информационной безопасности не стоит исключать из модели угроз ситуации, когда злоумышленнику для выполнения атаки требуется драйвер с опасным функционалом. Драйверов таких достаточно, сделать это довольно просто. Если же атака будет проведена не с таким попсовым драйвером, как от RwEverything, а с каким-нибудь менее широко известным, то обнаружить ее будет еще сложнее. Так что надо быть начеку, мониторить такие вещи и не позволять каждому драйверу загружаться в систему.
Windows: достучаться до железа
Меня всегда интересовало низкоуровневое программирование – общаться напрямую с оборудованием, жонглировать регистрами, детально разбираться как что устроено. Увы, современные операционные системы максимально изолируют железо от пользователя, и просто так в физическую память или регистры устройств что-то записать нельзя. Точнее я так думал, а на самом деле оказалось, что чуть ли не каждый производитель железа так делает!
В чём суть, капитан?
Режимы работы x86 процессора
В «Ring 3» программам запрещены потенциально опасные действия, такие как доступ к I/O портам и физической памяти. По логике разработчиков, настолько низкоуровневый доступ обычным программам не нужен. Доступ к этим возможностям имеют только операционная система и её компоненты (службы и драйверы). И всё бы ничего, но однажды я наткнулся на программу RW Everything:
RW Everything действительно читает и пишет практически всё
Смотрим последний установленный драйвер через OSR Driver Loader
Прокси-драйвера
В итоге получается обходной манёвр – всё, что программе запрещено делать, разработчик вынес в драйвер, программа устанавливает драйвер в систему и уже через него программа делает, что хочет! Более того – выяснилось, что RW Everything далеко не единственная программа, которая так делает. Таких программ не просто много, они буквально повсюду. У меня возникло ощущение, что каждый уважающий себя производитель железа имеет подобный драйвер:
Софт для обновления BIOS (Asrock, Gigabyte, HP, Dell, AMI, Intel, Insyde…)
Софт для разгона и конфигурации железа (AMD, Intel, ASUS, ASRock, Gigabyte)
Софт для просмотра сведений о железе (CPU-Z, GPU-Z, AIDA64)
Софт для обновления PCI устройств (Nvidia, Asmedia)
Во многих из них практически та же самая модель поведения – драйвер получает команды по типу «считай-ка вот этот физический адрес», а основная логика – в пользовательском софте. Ниже в табличке я собрал некоторые прокси-драйвера и их возможности:
Результаты краткого анализа пары десятков драйверов. Могут быть ошибки!
Mem – чтение / запись физической памяти
PCI – чтение / запись PCI Configuration Space
I/O – чтение / запись портов I/O
Alloc – аллокация и освобождение физической памяти
Map – прямая трансляция физического адреса в вирутальный
MSR – чтение / запись x86 MSR (Model Specific Register)
Жёлтым обозначены возможности, которых явно нет, но их можно использовать через другие (чтение или маппинг памяти). Мой фаворит из этого списка – AsrDrv101 от ASRock. Он устроен наиболее просто и обладает просто огромным списком возможностей, включая даже функцию поиска шаблона по физической памяти (!!)
Неполный перечень возможностей AsrDrv101
Чтение / запись RAM
Чтение / запись PCI Configuration Space
Чтение / запись MSR (Model-Specific Register)
Чтение / запись CR (Control Register)
Чтение TSC (Time Stamp Counter)
Чтение PMC (Performance Monitoring Counter)
Alloc / Free физической памяти
Поиск по физической памяти
Через Python в дебри
Конечно же я захотел сделать свой небольшой «тулкит» для различных исследований и экспериментов на базе такого драйвера. Причём на Python, мне уж очень нравится, как просто выглядит реализация сложных вещей на этом языке.
Первым делом нужно установить драйвер в систему и запустить его. Делаем «как положено» и сначала кладём драйвер (нужной разрядности!) в System32:
Раньше в похожих ситуациях я извращался с папкой %WINDIR%\Sysnative, но почему-то на моей текущей системе такого алиаса не оказалось, хотя Python 32-битный. (по идее, на 64-битных системах обращения 32-битных программ к папке System32 перенаправляются в папку SysWOW64, и чтобы положить файлик именно в System32, нужно обращаться по имени Sysnative).
Затем регистрируем драйвер в системе и запускаем его:
А дальше запущенный драйвер создаёт виртуальный файл (кстати, та самая колонка «имя» в таблице с анализом дров), через запросы к которому и осуществляются дальнейшие действия:
И ещё одна полезная программа для ползания по системе, WinObj
Тоже ничего особенного, открываем файл и делаем ему IoCtl:
В конечном итоге я «подсмотрел», как это делают другие программы. Выяснилось, что большинство либо не заморачиваются, либо просто ищут запущенные процессы с тем же именем. Но одна из исследованных программ имела кардинально другой подход, который я себе и перенял. Вместо того, чтобы переживать по количеству ссылок на файл, просто на каждый запрос открываем и закрываем файл! А если файла нет, значит кто-то остановил драйвер и пытаемся его перезапустить:
А дальше просто реверсим драйвер и реализуем все нужные нам вызовы:
Легко и непринуждённо в пару команд читаем физическую память
PCI Express Config Space
Чтение и запись PCI Config Space
Но через этот метод доступны только 0x100 байт конфигурационного пространства, в то время как в стандарте PCI Express размер Config Space у устройств может быть достигать 0x1000 байт! И полноценно вычитать их можно только обращением к PCI Extended Config Space, которая замаплена где-то в адресном пространстве, обычно чуть пониже BIOS:
Адресное пространство современного x86 компа, 0-4 ГБ
На чипсетах Intel (ну, в их большинстве) указатель на эту область адресного пространства можно взять из конфига PCI устройства 0:0:0 по смещению 0x60, подробнее описано в даташитах:
У AMD я такого не нашёл (наверняка есть, плохо искал), но сам факт неуниверсальности пнул меня в сторону поиска другого решения. Погуглив стандарты, я обнаружил, что указатель на эту область передаётся системе через ACPI таблицу MCFG
А сами ACPI таблицы можно найти через запись RSDP, поискав её сигнатуру по адресам 0xE0000-0xFFFFF, а затем распарсив табличку RSDT. Отлично, здесь нам и пригодится функционал поиска по памяти. Получаем нечто такое:
На всякий случай оставляем вариант для чипсетов Intel
Всё, теперь осталось при необходимости заменить чтение PCI Express Config Space через драйвер на чтение через память. Теперь-то разгуляемся!
Читаем BIOS
В качестве примера применения нашего «тулкита», попробуем набросать скрипт чтения BIOS. Он должен быть «замаплен» где-то в конце 32-битного адресного пространства, потому что компьютер начинает его исполнение с адреса 0xFFFFFFF0. Обычно в ПК стоит флеш-память объёмом 4-16 МБ, поэтому будем «сканировать» адресное пространство с адреса 0xFF000000, как только найдём что-нибудь непустое, будем считать, что тут начался BIOS:
В результате получаем:
Вот так в 10 строчек мы считали BIOS
Но подождите-ка, получилось всего 6 мегабайт, а должно быть 4 или 8 что-то не сходится. А вот так, у чипсетов Intel в адресное пространство мапится не вся флешка BIOS, а только один её регион. И чтобы считать всё остальное, нужно уже использовать SPI интерфейс.
Не беда, лезем в даташит, выясняем, что SPI интерфейс висит на PCI Express:
И для его использования, нужно взаимодействовать с регистрами в BAR0 MMIO по алгоритму:
Задать адрес для чтения в BIOS_FADDR
Задать параметры команды в BIOS_HSFTS_CTL
Прочитать данные из BIOS_FDATA
Пилим новый скрипт для чтения через чипсет:
Немного помучившись, получаем ответ от SSD на команду идентификации
А если написать свой драйвер?
Зайдя на страницу с кодом драйвера, вы сразу наткнетесь на предупреждение:
Точнее я так думал, до вот этой статьи, глаз зацепился за крайне интересный абзац:
Драйвер из статьи действительно подписан, и действительно неким китайским ключом:
Как оказалось, сведения о подписи можно просто посмотреть в свойствах.. А я в HEX изучал
Немного поиска этого имени в гугле, и я натыкаюсь на вот эту ссылку, откуда узнаю, что:
есть давно утёкшие и отозванные ключи для подписи драйверов
малварщики по всему миру используют это для создания вирусни
Несколько минут мучений с гугл-переводчиком на телефоне, и мне удалось разобраться в этой утилите и подписать драйвер одним из утекших ключей (который довольно легко отыскался в китайском поисковике):
И в самом деле, китайская азбука
И точно так же, как и AsrDrv101, драйвер удалось без проблем запустить!
А вот и наш драйвер запустился
Из чего делаю вывод, что старая идея с написанием своего драйвера вполне себе годная. Как раз не хватает функции маппинга памяти. Но да ладно, оставлю как TODO.
Выводы?
Так вот, при включении этой опции, некоторые драйвера (в том числе RW Everything и китайско-подписанный chipsec_hlpr) перестают запускаться:
Тем не менее, рассмотренный пример утилиты на базе AsrDrv работает:
Хакеры устанавливают на Windows уязвимые драйверы Gigabyte для отключения защиты
Эксперты британской компании Sophos сообщили, что операторы шифровальщика RobbinHood устанавливают на компьютеры уязвимые драйверы Gigabyte (с уязвимостью CVE-2018-19320), которые отключают защитные решения. Этот метод работает с Windows 7, Windows 8 и Windows 10.
Сначала злоумышленники проникают в сеть компании и устанавливают легальный драйвер ядра Gigabyte GDRV.SYS. Затем, используя уязвимость в этом драйвере, они получают доступ к ядру и используют его для временного отключения принудительного использования подписи драйверов в Windows. В этот момент устанавливается вредоносный драйвер ядра RBNL.SYS. Он применяется для отключения или остановки антивирусных и прочих защитных продуктов. Тогда уже на ПК запускается вымогатель RobbinHood, который шифрует файлы.
Как это выглядит: несколько файлов, встроенных в STEEL.EXE, извлекается в C:\WINDOWS\TEMP, а приложение STEEL.EXE удаляет файлы приложений безопасности, сначала развертывая ROBNR.EXE, который устанавливает вредоносный неподписанный драйвер RBNL.SYS, а после установки считывает файл PLIST.TXT и дает указание драйверу удалить любое приложение, указанное в PLIST.TXT и уничтожить связанные с ним процессы. Сторонний GDRV.SYS используется для того, чтобы временно отключить другие драйверы. Когда STEEL.EXE уничтожил все процессы и файлы в списке PLIST.TXT, он завершается. Теперь вымогатель может беспрепятственно зашифровать все файлы в системе.
Исследователи отметили, что существует много других драйверов с аналогичной уязвимостью, например, из VirtualBox (CVE-2008-3431), Novell (CVE-2013-3956), CPU-Z (CVE-2017-15302) или ASUS (CVE-2018-18537). Но сами они наблюдали только злоупотребление драйвером Gigabyte.
Между тем разработка Gigabyte утверждает, что в ее продуктах такой проблемы уязвимости не существует. Даже после публикации PoC-эксплоита для эксплуатации проблемы инженеры просто прекратили поддержку и разработку проблемного драйвера.
В свою очередь, компания Verisign, механизм подписи кода которой использовался для цифровой подписи драйвера, не отозвала свой сертификат. Подпись Authenticode по-прежнему работает, и заведомо уязвимый драйвер в Windows можно загрузить по сей день.
Эксперты порекомендовали использовать такие меры безопасности: многофакторную аутентификацию (MFA); сложные пароли, управляемые через менеджер паролей; ограничение прав доступа; регулярное создание резервных копий и их хранение вне сети; блокировка RDP; использование ограничение скорости, 2FA или VPN, если это нужно; использование защиты от несанкционированного доступа.
Кстати, 6 февраля после окончания периода расширенной поддержки операционной системы Windows 7 Microsoft выпустила последнее бесплатное обновление для ОС. Достаточно объемное по размеру обновление (весит около 40-50 МБ для разных версий ОС) исправляет только одну ошибку в настройках рабочего стола, а именно — теперь применение опции для обоев под названием Stretch («Растянуть») и последующая перезагрузка системы не должна приводить к появлению черного экрана, вместо ранее установленных пользователем обоев.
Между тем пользователи ОС Windows 7 начали жаловаться на новую проблему. Они не могут штатным образом, даже под учетной записью администратора системы, выключить или перезагрузить свои ПК. Операционная система выдает ошибку: «You don’t have permission to shut down this computer» (у вас нет прав на выключение этого компьютера). Пока причина возникновения ошибки не выяснена.






