Поделиться через


Контрольный список безопасности драйвера

В этой статье содержится контрольный список безопасности драйверов для разработчиков драйверов, помогающих снизить риск компрометации драйверов.

Общие сведения о безопасности драйверов

Недостаток безопасности — это любой недостаток, который позволяет злоумышленнику вызвать неисправность драйвера таким образом, чтобы она приводила к сбою системы или неиспользуемой. Кроме того, уязвимости в коде драйвера могут позволить злоумышленнику получить доступ к ядру, создав возможность компрометации всей ОС. Когда большинство разработчиков работают над своим драйвером, их основное внимание уделяется получению драйвера для правильной работы, а не о том, будет ли злоумышленник пытаться использовать уязвимости в коде.

Однако после освобождения драйвера злоумышленники могут попытаться провести проверку и выявить недостатки безопасности. Разработчики должны рассмотреть эти проблемы на этапе проектирования и реализации, чтобы свести к минимуму вероятность таких уязвимостей. Цель заключается в устранении всех известных недостатков безопасности перед освобождением драйвера.

Для создания более безопасных драйверов требуется сотрудничество системного архитектора (сознательно думая о потенциальных угрозах для драйвера), разработчике, реализующем код (оборонительные кодирование распространенных операций, которые могут быть источником эксплойтов), и тестовой команде (упреждающей попытке найти слабость и уязвимости). Благодаря правильной координации всех этих действий безопасность водителя значительно улучшается.

Помимо предотвращения проблем, связанных с атакой драйвера, многие из описанных шагов, таких как более точное использование памяти ядра, повышают надежность драйвера. Это приведет к снижению затрат на поддержку и повышению удовлетворенности клиентов вашим продуктом. Выполнение задач в контрольном списке ниже поможет достичь всех этих целей.

Контрольный список безопасности. Выполните задачу безопасности, описанную в каждом из этих разделов.

Флажок без знака, представляющий элемент в контрольном списке безопасности.Убедитесь, что требуется драйвер ядра

Флажок без знака, представляющий элемент в контрольном списке безопасности.Использование платформ драйверов

Флажок без знака, представляющий элемент в контрольном списке безопасности.Управление доступом только к драйверам программного обеспечения

Флажок без знака, представляющий элемент в контрольном списке безопасности.Не тестовый код драйвера для рабочего знака

Флажок без знака, представляющий элемент в контрольном списке безопасности.Выполнение анализа угроз

Флажок без знака, представляющий элемент в контрольном списке безопасности.Следуйте рекомендациям по безопасному написанию кода драйвера

Флажок без знака, представляющий элемент в контрольном списке безопасности.Реализация совместимого кода HVCI

Флажок без знака, представляющий элемент в контрольном списке безопасности.Следуйте рекомендациям по конкретному коду технологии

Флажок без знака, представляющий элемент в контрольном списке безопасности.Выполнение проверки однорангового кода

Флажок без знака, представляющий элемент в контрольном списке безопасности.Управление доступом к драйверу

Флажок без знака, представляющий элемент в контрольном списке безопасности.Повышение безопасности установки устройств

Флажок без знака, представляющий элемент в контрольном списке безопасности.Выполнение правильной подписи драйвера выпуска

Флажок без знака, представляющий элемент в контрольном списке безопасности.Использование CodeQL для проверки кода драйвера

Флажок без знака, представляющий элемент в контрольном списке безопасности.Добавление заметок SAL в код драйвера

Флажок без знака, представляющий элемент в контрольном списке безопасности.Проверка уязвимостей с помощью средства проверки драйверов

Флажок без знака, представляющий элемент в контрольном списке безопасности.Проверка кода с помощью двоичного анализатора BinSkim

Флажок без знака, представляющий элемент в контрольном списке безопасности.Проверка кода с помощью тестов программы совместимости оборудования

Флажок без знака, представляющий элемент в контрольном списке безопасности.Просмотр методов и расширений отладчика

Флажок без знака, представляющий элемент в контрольном списке безопасности.Узнайте, как сообщается о драйверах с помощью Центра отчетов о уязвимом и вредоносном драйвере Майкрософт

Флажок без знака, представляющий элемент в контрольном списке безопасности.Проверка защищенных ресурсов программирования

Флажок без знака, представляющий элемент в контрольном списке безопасности. Просмотрите сводку по ключевым выводам

Убедитесь, что требуется драйвер ядра

Элемент контрольного списка безопасности #1. Убедитесь, что драйвер ядра является обязательным и что более низкий подход к риску, например служба Windows или приложение, не является лучшим вариантом.

Драйверы живут в ядре Windows и возникают проблемы при выполнении в ядре, предоставляя всю операционную систему. Если доступен любой другой вариант, скорее всего, это будет меньше затрат и меньше риска, чем создание нового драйвера ядра. Дополнительные сведения об использовании встроенных драйверов Windows см. в статье "Нужно ли писать драйвер?".

Сведения об использовании фоновых задач см. в статье "Поддержка приложения с фоновыми задачами".

Сведения об использовании служб Windows см. в разделе "Службы".

Использование платформ драйверов

Элемент контрольного списка безопасности #2. Используйте платформы драйверов для уменьшения размера кода и повышения надежности и безопасности.

Используйте платформы Windows Driver Framework для уменьшения размера кода и повышения надежности и безопасности. Чтобы приступить к работе, ознакомьтесь с помощью WDF для разработки драйвера. Дополнительные сведения об использовании драйвера платформы пользовательского режима более низкого риска (UMDF) см. в разделе "Выбор модели драйвера".

Написание устаревшего драйвера Windows Driver Model (WDM) занимает больше времени, затратно и почти всегда включает в себя воссоздание кода, доступного в платформах драйверов.

Исходный код Windows Driver Framework открытый код и доступен на GitHub. Это тот же исходный код, из которого создается библиотека среды выполнения WDF, которая поставляется в Windows 10. Вы можете эффективнее отлаживать драйвер, когда можно отслеживать взаимодействие между драйвером и WDF. Скачайте его из https://github.com/Microsoft/Windows-Driver-Frameworks.

Управление доступом только к драйверам программного обеспечения

Элемент контрольного списка безопасности #3. Если будет создан драйвер только для программного обеспечения, необходимо реализовать дополнительный контроль доступа.

Драйверы ядра только для программного обеспечения не используют подключаемый модуль и воспроизведение (PnP) для связи с определенными аппаратными идентификаторами и могут работать на любом компьютере. Такой драйвер можно использовать для целей, отличных от первоначально предполагаемого, создания вектора атаки.

Так как драйверы ядра только для программного обеспечения содержат дополнительный риск, они должны быть ограничены для выполнения на определенном оборудовании (например, с помощью уникального идентификатора PnP для включения создания драйвера PnP или проверки таблицы SMBIOS на наличие определенного оборудования).

Например, представьте, что OEM Fabrikam хочет распределить драйвер, который включает служебную программу блокировки для своих систем. Если этот драйвер только для программного обеспечения был выполнен в системе из другого изготовителя оборудования, нестабильности системы или повреждения может привести к повреждению. Системы Fabrikam должны включать уникальный идентификатор PnP, чтобы включить создание драйвера PnP, который также обновляется через Обновл. Windows. Если это невозможно, и Fabrikam авторов устаревшего драйвера, этот драйвер должен найти другой метод, чтобы убедиться, что он выполняется в системе Fabrikam (например, путем изучения таблицы SMBIOS перед включением любых возможностей).

Не рабочая проверка кода подписи

Контрольный список безопасности #4. Не следует разрабатывать, тестировать и производственный код драйвера ядра.

Код драйвера ядра, используемый для разработки, тестирования или производства, может включать опасные возможности, которые представляют угрозу безопасности. Этот опасный код никогда не должен быть подписан сертификатом, доверенным Windows. Правильный механизм выполнения опасного кода драйвера — отключить безопасную загрузку UEFI, включить BCD TESTSIGNING и подписать код разработки, тестирования и производства с помощью недоверенного сертификата (например, созданного makecert.exe).

Код, подписанный доверенным сертификатом издателей программного обеспечения (SPC) или подписью Windows Hardware Quality Labs (WHQL), не должен способствовать обходу технологий целостности и безопасности кода Windows. Прежде чем код подписан доверенной подписью SPC или WHQL, сначала убедитесь, что он соответствует рекомендациям по созданию драйверов в режиме надежного ядра. Кроме того, код не должен содержать опасных действий, описанных ниже. Дополнительные сведения о подписывание драйвера см . в разделе "Драйвер выпуска" далее в этой статье.

Ниже приведены примеры опасного поведения.

  • Предоставление возможности сопоставления произвольного ядра, физической или памяти устройства с пользовательским режимом.
  • Предоставление возможности чтения или записи произвольного ядра, физической или памяти устройства, включая входные и выходные данные порта (ввода-вывода).
  • Предоставление доступа к хранилищу, которое проходит управление доступом к Windows.
  • Предоставление возможности изменять оборудование или встроенное ПО, которое драйвер не предназначен для управления.

Выполнение анализа угроз

Элемент контрольного списка безопасности #5. Измените существующую модель угроз драйвера или создайте пользовательскую модель угроз для драйвера.

При рассмотрении безопасности общая методология заключается в создании конкретных моделей угроз, которые пытаются описать типы атак, которые могут быть возможны. Этот метод полезен при разработке драйвера, так как он заставляет разработчика заранее рассмотреть потенциальные векторы атак против драйвера. После выявления потенциальных угроз разработчик драйвера может рассмотреть возможность защиты от этих угроз, чтобы повысить общую безопасность компонента драйвера.

В этой статье приводятся рекомендации по созданию упрощенной модели угроз: моделирование угроз для драйверов. В этой статье приведен пример схемы модели угроз драйвера, которая может использоваться в качестве отправной точки для драйвера.

Пример схемы потока данных, иллюстрирующая гипотетический драйвер режима ядра.

Рекомендации по жизненному циклу разработки безопасности (SDL) и связанные средства можно использовать IHV и OEM для повышения безопасности своих продуктов. Дополнительные сведения см . в рекомендациях по SDL для изготовителей оборудования.

Следуйте рекомендациям по безопасному написанию кода драйвера

Элемент контрольного списка безопасности #6. Просмотрите код и удалите все известные уязвимости кода.

Основное действие создания безопасных драйверов — определение областей в коде, которые необходимо изменить, чтобы избежать известных уязвимостей программного обеспечения. Многие из этих известных уязвимостей программного обеспечения имеют строгое отслеживание использования памяти, чтобы избежать проблем с другими пользователями, перезаписывающими или в противном случае состоящими из расположений памяти, используемых драйвером.

Средства сканирования кода, такие как CodeQL и определенные тесты драйвера, можно использовать для поиска некоторых, но не всех этих уязвимостей. Эти средства и тесты описаны далее в этом разделе.

Буферы памяти

  • Всегда проверяйте размеры входных и выходных буферов, чтобы убедиться, что буферы могут содержать все запрошенные данные. Дополнительные сведения см. в разделе "Сбой проверки размера буферов".

  • Правильно инициализировать все выходные буферы с нулями, прежде чем возвращать их вызывающему объекту. Дополнительные сведения см. в разделе "Сбой инициализации выходных буферов".

  • Проверьте буферы переменной длины. Дополнительные сведения см. в разделе "Сбой проверки буферов переменной длины". Дополнительные сведения о работе с буферами и использовании ProbeForRead и ProbeForWrite для проверки адреса буфера см. в разделе "Обработка буферов".

Используйте подходящий метод для доступа к буферам данных с помощью ioCTLs

Одной из основных обязанностей драйвера Windows является передача данных между приложениями в пользовательском режиме и устройствами системы. Три метода доступа к буферам данных показаны в следующей таблице.

Тип буфера IOCTL Итоги Для получения дополнительных сведений
METHOD_BUFFERED Рекомендуется для большинства сидеть Использование буферизованного ввода-вывода
METHOD_IN_DIRECT или METHOD_OUT_DIRECT Используется в некоторых высокоскоростных ввода-выводах HW Использование прямых операций ввода-вывода
METHOD_NEITHER Избегайте, если это возможно Использование не буферизованного и прямого ввода-вывода

В общем буферизованном ввод-выводе рекомендуется, так как он предоставляет наиболее безопасные методы буферизации. Но даже при использовании буферизованного ввода-вывода существуют риски, такие как внедренные указатели, которые должны быть устранены.

Дополнительные сведения о работе с буферами в ioCTLs см. в статье "Методы доступа к буферам данных".

Ошибки при использовании буферизованного ввода-вывода iOCTL

  • Проверьте размер связанных буферов IOCTL. Дополнительные сведения см. в разделе "Сбой проверки размера буферов".

  • Правильно инициализировать выходные буферы. Дополнительные сведения см. в разделе "Сбой инициализации выходных буферов".

  • Правильно проверьте буферы переменной длины. Дополнительные сведения см. в разделе "Сбой проверки буферов переменной длины".

  • При использовании буферизованного ввода-вывода убедитесь, что в поле сведений о структуре IO_STATUS_BLOCK возвращается соответствующая длина выходных данных OutputBuffer. Не просто возвращайте длину непосредственно из запроса READ. Например, рассмотрим ситуацию, когда возвращенные данные из пользовательского пространства указывают на наличие буфера 4K. Если драйвер фактически должен вернуть только 200 байт, но вместо этого просто возвращает 4K в поле "Информация", произошла уязвимость раскрытия информации. Эта проблема возникает, так как в более ранних версиях Windows буфер, который используется диспетчером операций ввода-вывода для буферизованного ввода-вывода, не равен нулю. Таким образом, пользовательское приложение возвращает исходные 200 байт данных плюс 4K-200 байтов из буфера (содержимое нестраничного пула). Этот сценарий может происходить со всеми использованием буферизованного ввода-вывода, а не только с ioCTLs.

Ошибки прямого ввода-вывода в IOCTL

Правильно обрабатывать буферы нулевой длины. Дополнительные сведения см. в разделе об ошибках в прямых ввода-выводах.

Ошибки при ссылке на адреса пространства пользователя

  • Проверьте указатели, внедренные в буферные запросы ввода-вывода. Дополнительные сведения см. в разделе об ошибках в ссылках на адреса пользовательского пространства.

  • Проверьте любой адрес в пространстве пользователя, прежде чем пытаться использовать его, используя API, такие как ProbeForRead и ProbeForWrite при необходимости.

Регистры, связанные с моделью MSR, считывают и записывают

Встроенные компоненты компилятора, такие как __readmsr и __writemsr , можно использовать для доступа к регистрам, зависящим от модели. Если этот доступ необходим, драйвер должен всегда проверять, что регистр для чтения или записи ограничен ожидаемым индексом или диапазоном.

Дополнительные сведения и примеры кода см. в статье "Предоставление возможности чтения и записи MSR в рекомендациях по обеспечению безопасности разработки для разработчиков драйверов Windows".

Уязвимости TOCTOU

Существует потенциальное время проверки уязвимости (TOCTOU) при использовании прямых операций ввода-вывода (для операций ввода-вывода или операций чтения и записи). Помните, что драйвер получает доступ к буферу данных пользователя, пользователь может одновременно получить к нему доступ.

Чтобы управлять этим риском, скопируйте все параметры, которые необходимо проверить из буфера данных пользователя в память, доступную исключительно из режима ядра (например, стека или пула). Затем после того, как данные не смогут получить доступ к пользовательскому приложению, проверьте и затем запустите данные, переданные в систему.

Код драйвера должен правильно использовать память

  • Все выделения пула драйверов должны находиться в пуле, отличном от исполняемого (NX). Использование пулов памяти NX по сути является более безопасным, чем использование исполняемых пулов, нестраничных (NP), и обеспечивает лучшую защиту от атак переполнения.

  • Драйверы устройств должны правильно обрабатывать различные пользовательские режимы, а также ядра для операций ввода-вывода ядра, запросов.

Чтобы драйверы могли поддерживать виртуализацию HVCI, существуют дополнительные требования к памяти. Дополнительные сведения см. в разделе "Реализация совместимого кода HVCI" далее в этой статье.

Дескрипторы

Объекты устройства

IRPs

WDF и IRP

Одним из преимуществ использования WDF является то, что драйверы WDF обычно не обращаются напрямую к IRPs. Например, платформа преобразует irps WDM, которые представляют операции управления чтением, записью и устройством ввода-вывода в платформу запросов объектов, которые KMDF/UMDF получают в очередях ввода-вывода.

Если вы пишете драйвер WDM, ознакомьтесь со следующими рекомендациями.

Правильное управление буферами ввода-вывода IRP

В следующих статьях содержатся сведения о проверке входных значений IRP:

DispatchReadWrite Using Buffered I/O

Ошибки в буферизованном ввод-выводе

DispatchReadWrite Using Direct I/O

Ошибки в прямых ввода-выводах

Проблемы безопасности для кодов элементов управления ввода-вывода

Рассмотрите возможность проверки значений, связанных с IRP, таких как адреса буфера и длины.

Если вы решили использовать ни одно из операций ввода-вывода, помните, что в отличие от операций чтения и записи, а в отличие от буферных операций ввода-вывода и прямого ввода-вывода, то при использовании указателей и длины буфера не проверяются диспетчером операций ввода-вывода.

Правильно обрабатывать операции завершения IRP

Драйвер никогда не должен завершить IRP со значением состояния STATUS_SUCCESS, если он фактически не поддерживает и обрабатывает IRP. Сведения о правильных способах обработки операций завершения IRP см. в разделе "Завершение операций IRP".

Управление состоянием ожидания IRP драйвера

Драйвер должен пометить ожидающий IRP перед сохранением IRP и должен рассмотреть возможность включения вызова IoMarkIrpPending и назначения в заблокированной последовательности. Дополнительные сведения см. в разделе "Сбой проверки состояния драйвера" и хранения входящих irps при приостановке устройства.

Правильно обрабатывать операции отмены IRP

Операции отмены могут быть сложными для правильного кода, так как обычно они выполняются асинхронно. Проблемы в коде, который обрабатывает операции отмены, могут быть незамеченными в течение длительного времени, так как этот код обычно не выполняется часто в работающей системе. Не забудьте прочитать и понять все сведения, предоставленные в разделе "Отмена irPs". Обратите особое внимание на синхронизацию отмены и точек IRP, которые следует учитывать при отмене IRP.

Один из рекомендуемых способов свести к минимуму проблемы синхронизации, связанные с операциями отмены, — реализовать очередь IRP с безопасностью отмены.

Правильно обрабатывать операции очистки и закрытия IRP

Убедитесь, что вы понимаете разницу между IRP_MJ_CLEANUP и IRP_MJ_CLOSE запросами. Запросы очистки прибывают после закрытия всех дескрипторов в объекте файла, но иногда до завершения всех запросов ввода-вывода. Закрыть запросы прибывают после завершения или отмены всех запросов ввода-вывода для объекта файла. Дополнительные сведения см. в следующих статьях:

Подпрограммы DispatchCreate, DispatchClose и DispatchCreateClose

Подпрограммы DispatchCleanup

Ошибки при обработке операций очистки и закрытия

Дополнительные сведения о правильной обработке IRP см. в разделе "Дополнительные ошибки в обработке IRP".

Другие проблемы безопасности

  • Используйте блокировку или переблокированную последовательность, чтобы предотвратить условия гонки. Дополнительные сведения см. в разделе Об ошибках в многопроцессорной среде.

  • Убедитесь, что драйверы устройств правильно обрабатывают различные пользовательские режимы, а также ядра для запросов ввода-вывода ядра.

  • Убедитесь, что фильтры TDI или LSPs не устанавливаются драйвером или связанными пакетами программного обеспечения во время установки или использования.

Использование безопасных функций

Дополнительные уязвимости кода

Помимо возможных уязвимостей, описанных здесь, в этой статье содержатся дополнительные сведения о повышении безопасности кода драйвера в режиме ядра: создание драйверов в режиме надежного ядра.

Дополнительные сведения о безопасном кодировании C и C++ см . в разделе "Безопасный код " в конце этой статьи.

Управление доступом к драйверу

Элемент контрольного списка безопасности #7. Проверьте драйвер, чтобы убедиться, что вы правильно управляете доступом.

Управление доступом к драйверу — WDF

Драйверы должны работать, чтобы запретить пользователям неуместный доступ к устройствам и файлам компьютера. Чтобы предотвратить несанкционированный доступ к устройствам и файлам, необходимо:

  • При необходимости назовите объекты устройства. Именованные объекты устройств обычно необходимы только для устаревших причин, например, если у вас есть приложение, которое ожидает открытия устройства с использованием определенного имени или если вы используете устройство, отличное от PNP, или устройство управления. Обратите внимание, что драйверы WDF не должны называть их FDO устройства PnP, чтобы создать символьную ссылку с помощью WdfDeviceCreateSymbolicLink.

  • Безопасный доступ к объектам и интерфейсам устройства.

Чтобы разрешить приложениям или другим драйверам WDF доступ к PDO устройства PnP, следует использовать интерфейсы устройств. Дополнительные сведения см. в разделе "Использование интерфейсов устройств". Интерфейс устройства служит символьной ссылкой на PDO стека устройств.

Одним из лучших способов управления доступом к PDO является указание строки SDDL в INF. Если строка SDDL не находится в INF-файле, Windows будет применять дескриптор безопасности по умолчанию. Дополнительные сведения см. в разделе "Защита объектов устройств" и SDDL для объектов устройств.

Дополнительные сведения об управлении доступом см. в следующих статьях:

Управление доступом к устройству в драйверах KMDF

Имена, дескрипторы безопасности и классы устройств — обеспечение доступности объектов устройств... и SAFE с января 2017 г. Информационный бюллетень NT Insider, опубликованный OSR.

Управление доступом к драйверу — WDM

Если вы работаете с драйвером WDM и использовали именованный объект устройства, вы можете использовать IoCreateDeviceSecure и указать SDDL для его защиты. При реализации IoCreateDeviceSecure всегда укажите GUID пользовательского класса для DeviceClassGuid. Здесь не следует указывать существующий GUID класса. Это может привести к разрыву параметров безопасности или совместимости для других устройств, принадлежащих к данному классу. Дополнительные сведения см. в разделе WdmlibIoCreateDeviceSecure.

Дополнительные сведения см. в следующих статьях:

Управление доступом к устройству

Управление доступом к пространству имен устройств

Модель безопасности Windows для разработчиков драйверов

Иерархия рисков идентификаторов безопасности (SID)

В следующем разделе описывается иерархия рисков распространенных идентификаторов SID, используемых в коде драйвера. Общие сведения о SDDL см. в разделе SDDL для объектов устройств, строк безопасности и синтаксиса строки SDDL.

Важно понимать, что если вызывающие абоненты с низким уровнем привилегий могут получить доступ к ядру, риск кода увеличивается. На этой сводной схеме риск увеличивается, так как вы разрешаете доступ к функциям драйвера с более низким уровнем привилегий.

SY (System)
\/
BA (Built-in Administrators)
\/
LS (Local Service)
\/
BU (Built-in User)
\/
AC (Application Container)

Следуя общему принципу безопасности наименьших привилегий, настройте только минимальный уровень доступа, необходимый для работы драйвера.

Контроль безопасности WDM Granular IOCTL

Для дальнейшего управления безопасностью при отправке вызовов ioCTLs вызывающими пользователями код драйвера может включать функцию IoValidateDeviceIoControlAccess . Эта функция позволяет драйверу проверять права доступа. При получении IOCTL драйвер может вызвать IoValidateDeviceIoControlAccess, указав FILE_READ_ACCESS, FILE_WRITE_ACCESS или обоих.

Реализация детализированного элемента управления безопасностью IOCTL не заменяет необходимость управления доступом драйверов с помощью описанных выше методов.

Дополнительные сведения см. в следующих статьях:

Определение кодов элементов управления ввода-вывода

Реализация совместимого кода HVCI

Элемент контрольного списка безопасности #8. Проверьте, использует ли драйвер память, чтобы она была совместима с HVCI.

Совместимость использования памяти и HVCI

HVCI использует аппаратные технологии и виртуализацию для изоляции функции принятия решений по целостности кода (CI) от остальной части операционной системы. При использовании безопасности на основе виртуализации для изоляции CI единственным способом, который может стать исполняемым памятью ядра, является проверка CI. Это означает, что страницы памяти ядра никогда не могут быть записываемыми и исполняемыми (W+X) и исполняемым кодом нельзя напрямую изменять.

Чтобы реализовать совместимый код HVCI, убедитесь, что код драйвера выполняет следующие действия:

  • По умолчанию выбирает NX
  • Использует NX API-интерфейсы и флаги для выделения памяти (NonPagedPoolNx)
  • Не использует разделы, которые являются записываемыми и исполняемыми
  • Не пытается напрямую изменить исполняемую системную память
  • Не использует динамический код в ядре
  • Не загружает файлы данных в виде исполняемого файла
  • Выравнивание разделов — это несколько 0x1000 (PAGE_SIZE). Например, DRIVER_ALIGNMENT=0x1000

Дополнительные сведения об использовании средства и списке несовместимых вызовов памяти см. в разделе "Реализация совместимого кода HVCI".

Дополнительные сведения о проверке безопасности связанных системных фундаментальных принципов см. в статье о проверке готовности к целостности кода HyperVisor и защищенном гипервизором коде (HVCI).

Следуйте рекомендациям по использованию кода для конкретных технологий

Контрольный список безопасности #9. Ознакомьтесь со следующими рекомендациями по использованию технологии для драйвера.

Файловые системы

Дополнительные сведения о безопасности драйвера файловой системы см. в следующих статьях:

Общие сведения о безопасности файловой системы

Проблемы с безопасностью файловой системы

Функции безопасности файловой системы

Сосуществование с другими драйверами фильтров файловой системы

NDIS — сеть

Сведения о безопасности драйверов NDIS см. в разделе "Проблемы безопасности для сетевых драйверов".

Отображать

Сведения о безопасности драйвера отображения см. в разделе <"Ожидание> содержимого".

Printers

Сведения, связанные с безопасностью драйвера принтера, см. в разделе "Вопросы безопасности драйвера принтера версии 4".

Проблемы с безопасностью драйверов приобретения образов Windows (WIA)

Сведения о безопасности WIA см. в разделе "Проблемы безопасности" для драйверов приобретения образов Windows (WIA).

Повышение безопасности установки устройств

Контрольный список безопасности #10. Ознакомьтесь с инструкциями по созданию и установке драйвера, чтобы убедиться, что вы выполните следующие рекомендации.

При создании кода, устанавливающего драйвер, необходимо убедиться, что установка устройства всегда будет выполняться безопасно. Установка безопасного устройства — это одна из следующих действий:

  • Ограничивает доступ к устройству и его классам интерфейса устройства
  • Ограничивает доступ к службам драйверов, созданным для устройства.
  • Защита файлов драйверов от изменения или удаления
  • Ограничивает доступ к записям реестра устройства
  • Ограничивает доступ к классам WMI устройства
  • Правильно использует функции SetupAPI

Дополнительные сведения см. в следующих статьях:

Создание безопасных установок устройств

Рекомендации по использованию SetupAPI

Использование функций установки устройств

Дополнительные разделы по установке устройств и драйверов

Выполнение проверки однорангового кода

Элемент контрольного списка безопасности #11: проверка однорангового кода, чтобы искать проблемы, не связанные с другими инструментами и процессами

Поиск рецензентов кода, которые могут возникнуть, искать проблемы, которые вы могли пропустить. Второй набор глаз часто увидит проблемы, которые у вас могут быть пропущены.

Если у вас нет подходящих сотрудников для внутреннего просмотра кода, рассмотрите возможность привлечения внешних справки для этой цели.

Выполнение правильной подписи драйвера выпуска

Контрольный список безопасности #12. Используйте портал партнеров Windows, чтобы правильно подписать драйвер для распространения.

Перед выпуском пакета драйвера в общедоступную версию рекомендуется отправить пакет для сертификации. Дополнительные сведения см. в статье "Тестирование производительности и совместимости", "Начало работы с программой оборудования", службами панели мониторинга оборудования и аттестацией, подписываемой драйвером ядра для общедоступного выпуска.

Использование CodeQL для проверки кода драйвера

Контрольный список безопасности #13. Используйте CodeQL для проверки уязвимостей в коде драйвера.

CodeQL, GitHub, — это механизм анализа семантического кода, а также сочетание обширного набора запросов безопасности, а также надежной платформы, что делает его бесценным инструментом для защиты кода драйвера. Дополнительные сведения см. в разделе CodeQL и тест логотипа статических инструментов.

Добавление заметок SAL в код драйвера

Контрольный список безопасности #14. Добавьте заметки SAL в код драйвера.

Язык заметки исходного кода (SAL) предоставляет набор заметок, которые можно использовать для описания того, как функция использует свои параметры, предположения о них и гарантии того, что она делает после завершения. Заметки определяются в файле sal.hзаголовка. Анализ кода Visual Studio для C++ использует заметки SAL для изменения его анализа функций. Дополнительные сведения о разработке драйверов ДЛЯ WINDOWS SAL 2.0 см . в заметках SAL 2.0 для драйверов Windows и использовании заметок SAL для уменьшения дефектов кода C/C++.

Общие сведения о SAL см. в этой статье, доступной в OSR. https://www.osr.com/blog/2015/02/23/sal-annotations-dont-hate-im-beautiful/

Проверка уязвимостей с помощью средства проверки драйверов

Элемент контрольного списка безопасности #15. Используйте средство проверки драйверов для проверки уязвимостей в коде драйвера.

Средство проверки драйверов использует набор правил интерфейса и модель операционной системы, чтобы определить, правильно ли работает драйвер с операционной системой Windows. DV находит дефекты в коде драйвера, которые могут указывать на потенциальные ошибки в драйверах.

Средство проверки драйверов позволяет выполнять динамическое тестирование драйвера. Средство проверки драйверов отслеживает драйверы в режиме ядра Windows и графические драйверы для обнаружения незаконных вызовов функций или действий, которые могут повредить систему. Средство проверки драйверов может подвергать драйверам Windows различные стрессы и тесты, чтобы найти неправильное поведение. Дополнительные сведения см. в разделе "Проверка драйверов".

Обратите внимание, что для DV поддерживаются только определенные типы драйверов. Дополнительные сведения о драйверах, которые можно проверить, см. в разделе "Поддерживаемые драйверы". Дополнительные сведения о тестах DV, доступных для типа драйвера, с которым вы работаете, см. на следующих страницах.

Чтобы ознакомиться с DV, можно использовать один из примеров драйверов (например, рекомендуемый пример тостера: https://github.com/Microsoft/Windows-driver-samples/tree/main/general/toaster/toastDrv/kmdf/func/featured).

Проверка кода с помощью двоичного анализатора BinSkim

Элемент контрольного списка безопасности #16. Выполните следующие действия, чтобы использовать BinSkim для двойной проверки того, что параметры компиляции и сборки настроены для минимизации известных проблем безопасности.

Используйте BinSkim для изучения двоичных файлов, чтобы определить методики кодирования и построения, которые могут потенциально отрисовки двоичного файла уязвимы.

BinSkim проверяет наличие:

  • Использование устаревших наборов средств компилятора. Двоичные файлы должны компилироваться в самых последних наборах средств компилятора, где это возможно, чтобы максимально повысить эффективность использования текущих средств компилятора и устранения рисков безопасности, предоставляемых ОС.
  • Небезопасные параметры компиляции. Двоичные файлы должны быть скомпилированы с наиболее безопасными параметрами, чтобы обеспечить устранение рисков безопасности, максимально увеличить число ошибок компилятора и отчеты с действиями, помимо прочего.
  • Проблемы с подписыванием. Подписанные двоичные файлы должны быть подписаны с помощью криптографически надежных алгоритмов.

BinSkim — это средство открытый код и создает выходные файлы, использующие формат обмена статическими результатами анализа (SARIF). BinSkim заменяет прежнее средство BinScope .

Дополнительные сведения о BinSkim см. в руководстве пользователя BinSkim.

Выполните следующие действия, чтобы убедиться, что параметры компиляции безопасности правильно настроены в коде, который вы отправляете.

  1. Скачайте и установите кроссплатформенный пакет SDK для .NET Core.

  2. Убедитесь, что Visual Studio установлен. Сведения о скачивании и установке Visual Studio см. в статье "Установка Visual Studio".

  3. Существует ряд вариантов скачивания BinSkim, например пакета NuGet. В этом примере мы будем использовать параметр клонирования git, чтобы скачать здесь: https://github.com/microsoft/binskim и установить его на 64-разрядном компьютере с Windows.

  4. Откройте окно командной строки разработчика Visual Studio и создайте каталог, например C:\binskim-master.

    C:\> Md \binskim-master
    
  5. Перейдите к только что созданному каталогу.

    C:\> Cd \binskim-master
    
  6. Используйте команду клонирования Git, чтобы скачать все необходимые файлы.

    C:\binskim-master> git clone --recurse-submodules https://github.com/microsoft/binskim.git
    
  7. Перейдите к новому binskim диктору, созданному командой клонирования.

    C:\> Cd \binskim-master\binskim
    
  8. Запустите BuildAndTest.cmd , чтобы убедиться, что сборка выпуска выполнена успешно, и все тесты проходят.

    C:\binskim-master\binskim> BuildAndTest.cmd
    
    Welcome to .NET Core 3.1!
    ---------------------
    SDK Version: 3.1.101
    
    ...
    
    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64\BinSkim.Sdk.dll
    1 File(s) copied
    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\linux-x64\BinSkim.Sdk.dll
    1 File(s) copied
    
    ...
    
    
  9. Процесс сборки создает набор каталогов с исполняемыми файлами BinSkim. Перейдите в выходной каталог сборки win-x64.

    C:\binskim-master\binskim> Cd \binskim-master\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64>
    
  10. Отображение справки по параметру анализа.

C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim help analyze

BinSkim PE/MSIL Analysis Driver 1.6.0.0

--sympath                      Symbols path value, e.g., SRV*http://msdl.microsoft.com/download/symbols or Cache*d:\symbols;Srv*http://symweb. See
                              https://learn.microsoft.com/windows-hardware/drivers/debugger/advanced-symsrv-use for syntax information. Note that BinSkim will clear the
                              _NT_SYMBOL_PATH environment variable at runtime. Use this argument for symbol information instead.

--local-symbol-directories     A set of semicolon-delimited local directory paths that will be examined when attempting to locate PDBs.

-o, --output                   File path to which analysis output will be written.

--verbose                      Emit verbose output. The resulting comprehensive report is designed to provide appropriate evidence for compliance scenarios.

...

Задание пути символа

Если вы создаете весь код, который вы анализируете на одном компьютере, на котором выполняется BinSkim, обычно не нужно задавать путь к символам. Это связано с тем, что файлы символов доступны в локальном поле, в котором вы скомпилировали. Если вы используете более сложную систему сборки или перенаправляете символы в другое расположение (а не вместе с скомпилированным двоичным файлом), используйте --local-symbol-directories для добавления этих расположений в поиск файлов символов. Если код ссылается на скомпилированный двоичный файл, который не является частью кода, то для получения символов можно использовать отладчик окон для проверки безопасности этих зависимостей кода. Если в этих зависимостях возникла проблема, возможно, вы не сможете устранить их. Но это может быть полезно знать о любых возможных рисках безопасности, которые вы принимаете, принимая эти зависимости.

Совет

При добавлении пути символа (который ссылается на сетевой сервер символов), добавьте расположение локального кэша, чтобы указать локальный путь для кэширования символов. Не делать это может значительно скомпрометации производительности BinSkim. В следующем примере указывается локальный кэш в d:\symbols. --sympath Cache*d:\symbols;Srv*http://symweb Дополнительные сведения о путь символов для отладчиков Windows см. в разделе "Путь к символам".

  1. Выполните следующую команду, чтобы проанализировать скомпилированный двоичный файл драйвера. Обновите целевой путь, чтобы указать на соответствующий файл драйвера .sys.

    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim analyze "C:\Samples\KMDF_Echo_Driver\echo.sys"
    
  2. Для получения дополнительных сведений добавьте подробный параметр, как показано ниже.

    C:\binskim-master\binskim\bld\bin\AnyCPU_Release\Publish\netcoreapp2.0\win-x64> BinSkim analyze "C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys" --verbose
    

    Примечание.

    Параметр --verbose будет создавать явные результаты передачи или сбоя для каждой проверки. Если вы не предоставляете подробные сведения, вы увидите только дефекты, обнаруженные BinSkim. Вариант --verbose обычно не рекомендуется для фактических систем автоматизации из-за увеличения размера файлов журналов, так как это затрудняет получение отдельных сбоев при их возникновении, так как они будут внедрены в разгар большого количества результатов "pass".

  3. Просмотрите выходные данные команды, чтобы найти возможные проблемы. В этом примере выходных данных показаны три пройденных теста. Дополнительные сведения о правилах, таких как BA2002, доступны в руководстве пользователя BinSkim.

    Analyzing...
    Analyzing 'osrusbfx2.sys'...
    ...
    
    C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys\Debug\osrusbfx2.sys: pass BA2002: 'osrusbfx2.sys' does not incorporate any known vulnerable dependencies, as configured by current policy.
    C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: pass BA2005: 'osrusbfx2.sys' is not known to be an obsolete binary that is vulnerable to one or more security problems.
    C:\Samples\KMDF_Echo_Driver\osrusbfx2.sys: pass BA2006: All linked modules of 'osrusbfx2.sys' generated by the Microsoft front-end satisfy configured policy (compiler minimum version 17.0.65501.17013).
    
  4. В этом выходных данных показано, что тест BA3001 не выполняется в качестве средства, указывает, что драйвер не является двоичным файлом ELF.

    ...
    C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: notapplicable BA3001: 'osrusbfx2.sys' was not evaluated for check 'EnablePositionIndependentExecutable' as the analysis is not relevant based on observed metadata: image is not an ELF binary.
    
  5. В этом выходных данных показана ошибка теста BA2007.

    ...
    
    C:\Samples\KMDF_Echo_Driver\Debug\osrusbfx2.sys: error BA2007: 'osrusbfx2.sys' disables compiler warning(s) which are required by policy.
    A compiler warning is typically required if it has a high likelihood of flagging memory corruption, information disclosure, or double-free vulnerabilities.
    To resolve this issue, enable the indicated warning(s) by removing /Wxxxx switches (where xxxx is a warning id indicated here) from your command line, and resolve any warnings subsequently raised during compilation.
    

Чтобы включить эти предупреждения в Visual Studio, в разделе C/C++ на страницах свойств проекта удалите значения, которые не нужно исключить в разделе "Отключить определенные предупреждения".

Снимок экрана: диалоговое окно для отключения определенных предупреждений в Visual Studio 2019.

Параметры компиляции по умолчанию в Visual Studio для проектов драйверов могут отключить такие предупреждения, как показано ниже. Эти предупреждения будут сообщены BinSkim.

C4603 — "name": макрос не определен или определение отличается после использования предварительно компилированного заголовка

C4627 — "description": пропущено при поиске предварительно скомпилированного заголовка

C4986 — "объявление": спецификация исключения не соответствует предыдущему объявлению

Дополнительные сведения о предупреждениях компилятора см. в разделе "Предупреждения компилятора" по версии компилятора.

Проверка кода с помощью тестов программы совместимости оборудования

Контрольный список безопасности #17. Используйте тесты программы совместимости оборудования, связанные с безопасностью, чтобы проверить наличие проблем с безопасностью.

Программа совместимости оборудования включает тесты, связанные с безопасностью, можно использовать для поиска уязвимостей кода. Программа совместимости оборудования Windows использует тесты в комплекте аппаратных лабораторий Windows (HLK). Тесты основы устройств HLK можно использовать в командной строке для выполнения кода драйвера и проверки уязвимости. Общие сведения об основных тестах устройства и программе совместимости оборудования см . в комплекте лабораторий оборудования Windows.

Ниже приведены примеры тестов, которые могут быть полезны для проверки кода драйвера для некоторых действий, связанных с уязвимостями кода:

DF — нечеткий случайный тест IOCTL (надежность)

DF — нечеткий вложенный тест (надежность)

DF — тест FSCTL с нулевой длиной нечетких длин (надежность)

DF — нечеткий случайный тест FSCTL (надежность)

DF — тест API нечетких ошибок (надежность)

Кроме того, можно использовать задержку задержки синхронизации ядра, включенную в средство проверки драйверов.

Тесты CHAOS (параллельное оборудование и операционная система) выполняют различные тесты драйверов PnP, тесты нечетких драйверов устройств и тесты системы питания одновременно. Дополнительные сведения см. в разделе "Тесты CHAOS" (основы устройств).

Тесты на проникновение на основе устройств выполняют различные формы входных атак, которые являются критически важным компонентом тестирования безопасности. Тестирование атак и проникновений может помочь выявить уязвимости в программных интерфейсах. Дополнительные сведения см. в разделе "Тесты на проникновение" (основы устройств).

Используйте Device Guard — тест соответствия требованиям, а также другие средства, описанные в этой статье, чтобы убедиться, что драйвер совместим с HVCI.

Пользовательские и доменные средства тестирования

Рассмотрите возможность разработки тестов безопасности для конкретного домена. Чтобы разработать дополнительные тесты, соберите входные данные от оригинальных конструкторов программного обеспечения, а также несвязанные ресурсы разработки, знакомые с определенным типом драйвера, и один или несколько людей, знакомых с анализом вторжений и предотвращением вторжений в безопасность.

Просмотр методов и расширений отладчика

Контрольный список безопасности #18. Просмотрите эти средства отладчика и рассмотрите их использование в рабочем процессе отладки разработки.

Форматы расширений !acl и содержимое списка управления доступом (ACL). Дополнительные сведения см. в разделе "Определение ACL" объекта и объекта !acl.

Расширение !token отображает форматное представление объекта маркера безопасности. Дополнительные сведения см. в разделе !token.

Расширение !tokenfields отображает имена и смещения полей в объекте маркера доступа (структура TOKEN). Дополнительные сведения см. в разделе !tokenfields.

Расширение !sid отображает идентификатор безопасности (SID) по указанному адресу. Дополнительные сведения см. в разделе !sid.

Расширение !sd отображает дескриптор безопасности по указанному адресу. Дополнительные сведения см. в статье !sd.

Центр отчетов об уязвимостях и вредоносных драйверах Майкрософт

Любой пользователь может отправить сомнительным драйвером с помощью Центра отчетов о уязвимом и вредоносном драйвере Майкрософт. Дополнительные сведения о том, как драйверы отправляются для анализа, см. в этой записи блога. Повышение безопасности ядра с помощью нового Центра отчетов о уязвимом и вредоносном драйвере Майкрософт

Центр отчетов может сканировать и анализировать драйверы Windows, созданные для архитектур x86 и x64. Уязвимые и вредоносные отсканированные драйверы помечаются для анализа и расследования группой уязвимых драйверов Майкрософт. После подтверждения уязвимых драйверов соответствующее уведомление будет добавлено в список блокировки уязвимых драйверов. Дополнительные сведения об этом см . в рекомендуемых правилах блокировки драйверов Майкрософт. Эти правила применяются по умолчанию к устройствам с поддержкой безопасности гипервизора (HVCI) и Windows 10 в режиме S.

Проверка защищенных ресурсов программирования

Контрольный список безопасности #19. Просмотрите эти ресурсы, чтобы расширить понимание рекомендаций по безопасному написанию кода, применимых к разработчикам драйверов.

Ознакомьтесь с этими ресурсами, чтобы узнать больше о безопасности драйверов

Рекомендации по программированию драйвера в режиме безопасного ядра

Создание драйверов в режиме надежного ядра

Безопасные организации программирования

Carnegie Mellon University SEI CERT

Carnegie Mellon University SEI CERT C Coding Standard: правила разработки безопасных, надежных и безопасных систем (выпуск 2016).

MITRE — слабые места, устраненные стандартом безопасного кода CERT C

Построение безопасности в модели зрелости (BSIMM) — https://www.bsimm.com/

SAFECode — https://safecode.org/

Ресурсы CISA

OSR

OSR предоставляет услуги по разработке драйверов и консультационных услуг. Эти статьи из бюллетеня OSR выделяют проблемы с безопасностью драйвера.

Имена, дескрипторы безопасности и классы устройств — обеспечение доступности объектов устройств... и SAFE

У вас есть защита— внутри драйвера и безопасности устройств

Блокировка драйверов — опрос методов

Плавуна и Spectre: Что о драйверах?

Пример использования

От оповещения до уязвимости драйвера: анализ ATP в Microsoft Defender расследует недостатки повышения привилегий

Книги

24 смертельных грехов безопасности программного обеспечения: программирование недостатков и как исправить их Майкл Говард, Дэвид LeBlanc и Джон Viega

Искусство оценки безопасности программного обеспечения: выявление и предотвращение уязвимостей программного обеспечения, Марк Доуд, Джон Макдональд и Джастин Шух

Написание secure Software Second Edition, Майкл Говард и Дэвид LeBlanc

Искусство оценки безопасности программного обеспечения: выявление и предотвращение уязвимостей программного обеспечения, Марк Доуд и Джон Макдональд

Безопасный код в C и C++ (серия SEI в программной инженерии) 2-го выпуска, Роберт C. Seacord

Программирование модели драйверов Microsoft Windows (2-го выпуска), Уолтер Oney

Разработка драйверов с помощью Windows Driver Foundation (справочник разработчика), Пенни Орвик и Гай Смит

Обучение

Учебный курс для драйвера Windows доступен от поставщиков, таких как:

Безопасное программирование онлайн-обучения доступно из различных источников. Например, этот курс доступен из coursera на:

Определение уязвимостей безопасности в программировании на C/C++.

SAFECode предлагает бесплатный учебный курс, а также:

SAFECode.org/training

Профессиональная сертификация

CERT предлагает сертификацию для специалистов по безопасному кодированию.

Сводка по ключевым выводам

Безопасность драйверов является сложной задачей, содержащей множество элементов, но вот несколько ключевых моментов, которые следует рассмотреть:

  • Драйверы живут в ядре Windows и возникают проблемы при выполнении в ядре, предоставляя всю операционную систему. Из-за этого обратите внимание на безопасность драйверов и проектирование с учетом безопасности.

  • Примените принцип наименьших привилегий:

    a. Использование строгой строки SDDL для ограничения доступа к драйверу

    b. Дальнейшее ограничение отдельных IOCTL

  • Создайте модель угроз для идентификации векторов атак и рассмотрите возможность дальнейшего ограничения.

  • Будьте осторожны с учетом внедренных указателей, передаваемых из пользовательского режима. Они должны быть проверены, доступ к которым осуществляется только в рамках пробы, и они подвержены времени проверки времени использования (ToCToU), если только значение буфера не фиксируется и не сравнивается.

  • Если вы не уверены, используйте METHOD_BUFFERED в качестве метода буферизации IOCTL.

  • Используйте служебные программы сканирования кода, чтобы искать известные уязвимости кода и устранять все выявленные проблемы.

  • Поиск рецензентов кода, которые могут возникнуть, искать проблемы, которые вы могли пропустить.

  • Используйте средства проверки драйверов и протестируйте драйвер с несколькими входными данными, включая угловые варианты.