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


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

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

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

Модель безопасности Windows

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

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

Модель безопасности включает в себя следующие понятия:

  • Идентификаторы безопасности (SID)
  • Токены доступа
  • Дескрипторы безопасности
  • Списки управления доступом (ACL)
  • Привилегии

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

Идентификатор безопасности (SID, также называемый субъектом) идентифицирует пользователя, группу или сеанс входа. У каждого пользователя есть уникальный идентификатор безопасности, который извлекается операционной системой при входе.

Идентификаторы безопасности выдаются органом, например операционной системой или сервером доменной сети. Некоторые идентификаторы SID хорошо известны и имеют имена, а также идентификаторы. Например, идентификатор SID S-1-1-0 обозначает всех (или весь мир).

Токены доступа

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

По умолчанию система использует основной маркер доступа для процесса всякий раз, когда поток процесса взаимодействует с защищаемым объектом. Однако поток может олицетворить учетную запись клиента. При олицетворении потока он имеет токен олицетворения в дополнение к собственному основному токену. Маркер олицетворения описывает контекст безопасности учетной записи пользователя, которую поток олицетворяет. Имперсонация особенно распространена в обработке удаленного вызова процедур (RPC).

Маркер доступа, описывающий контекст ограниченной безопасности для потока или процесса, называется маркером ограниченного доступа. Идентификаторы безопасности в ограниченном маркере могут быть заданы только для запрета доступа, а не для разрешения доступа к защищаемым объектам. Кроме того, маркер может описать ограниченный набор привилегий на уровне системы. SID и идентификационные данные пользователя остаются неизменными, но права доступа пользователя ограничены, пока процесс использует ограниченный токен. Функция createRestrictedToken создает ограниченный токен.

Дескрипторы безопасности

Каждый именованный объект Windows имеет дескриптор безопасности; некоторые неназванные объекты тоже. Дескриптор безопасности описывает идентификаторы владельца и группы для объекта вместе со списками управления доступом.

Дескриптор безопасности объекта обычно создается функцией, создающей объект. Когда драйвер вызывает IoCreateDevice или IoCreateDeviceSecure для создания объекта устройства, система применяет дескриптор безопасности к созданному объекту устройства и задает ACL для объекта. Для большинства устройств списки управления доступом указываются в информационном файле устройства (INF).

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

Списки управления доступом

Списки управления доступом (ACL) позволяют точно контролировать доступ к объектам. ACL является частью дескриптора безопасности для каждого объекта.

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

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

ACL для объекта устройства можно задать тремя способами:

  • Установите дескриптор безопасности по умолчанию для своего типа устройства.
  • Функцией RtlCreateSecurityDescriptor программно создаётся, а функцией RtlSetDaclSecurityDescriptor устанавливается.
  • Указан в языке определения дескриптора безопасности (SDDL) в INF-файле устройства или вызове процедуры IoCreateDeviceSecure.

Все драйверы должны использовать SDDL в INF-файле, чтобы указать списки управления доступом для своих объектов устройства.

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

Диаграмма, показывающая формат строк SDDL для объектов устройств.

Значение Access указывает тип разрешенного доступа. Значение SID указывает идентификатор безопасности, определяющий, к кому применяется значение Access (например, пользователь или группа).

Например, следующая строка SDDL позволяет системе (SY) получить доступ ко всему и разрешает доступ только для чтения для всех остальных пользователей (WD):

“D:P(A;;GA;;;SY)(A;;GR;;;WD)”

Файл заголовка wdmsec.h также включает набор предопределенных строк SDDL, которые подходят для объектов устройства. Например, файл заголовка определяет SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX следующим образом:

"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)"

Первый сегмент этой строки позволяет полностью контролировать устройство ядром и операционной системой (SY). Второй сегмент позволяет любому пользователю в встроенной группе администраторов (BA) получить доступ ко всему устройству, но не изменять ACL. Третий сегмент позволяет всем (WD) читать или записывать на устройство, а четвертый сегмент предоставляет те же права не доверенному коду (RC). Драйверы могут использовать предварительно определённые строки как есть или как образцы для строк, специфичных для объектов устройств.

Все объекты устройств в стеке должны иметь одинаковые ACL. Изменение списков управления доступом на одном объекте устройства в стеке изменяет списки управления доступом во всем стеке устройств.

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

Подпрограмма IoCreateDeviceSecure поддерживает подмножество строк SDDL, использующих предопределенные идентификаторы SID, такие как WD и SY. API в режиме пользователя и INF-файлы поддерживают полный синтаксис SDDL.

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

Когда процесс запрашивает доступ к объекту, проверки безопасности сравнивают списки управления доступом для объекта с SID в маркере доступа вызывающего процесса.

Система сравнивает ACE в строгом порядке сверху вниз и останавливается на первом соответствующем совпадении. Таким образом, при создании ACL необходимо всегда помещать элементы ACE отказа над соответствующими элементами ACE разрешения. В следующих примерах показано, как выполняется сравнение.

пример 1. Сравнение ACL с маркером доступа

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

пример файла ACL

Разрешение SID Доступ
Разрешать Бухгалтерский учет Запись, удаление
Разрешать Продажи Добавить
Отрицать Юридический Добавление, запись, удаление
Разрешать Каждый Читать

Этот ACL содержит четыре ACE, которые применяются к группам Учет, Продажи, Юридический и Все.

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

Пользователь Джим (S-1-5-21...)

Учет групп (S-1-5-22...)

Group Legal (S-1-5-23...)

Группа «Все» (S-1-1-0)

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

пример 2. Сравнение ACL с ограниченным маркером

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

В примере 2 показано, как система сравнивает список управления доступом (ACL) файла с ограниченным токеном. Предположим, что файл имеет тот же ACL, что и в предыдущей таблице. Однако в этом примере процесс имеет ограниченный маркер, содержащий следующие идентификаторы SID:

Пользователь Джим (S-1-5-21...) Отрицать

Учет групп (S-1-5-22...) Отрицать

Group Legal (S-1-5-23...) Отрицать

Группа Все пользователи (S-1-1-0)

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

Привилегии

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

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

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

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

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

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

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

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

Сценарий модели безопасности Windows: создание файла

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

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

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

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

  1. Приложение в пользовательском режиме вызывает функцию createFile , передав допустимое имя файла Microsoft Win32.
  2. Kernel32.dll пользовательского режима передает запрос в Ntdll.dll, который преобразует имя Win32 в имя файла Microsoft Windows NT.
  3. Ntdll.dll вызывает функцию NtCreateFile с именем файла Windows. В Ntoskrnl.exeдиспетчер ввода-вывода обрабатывает NtCreateFile.
  4. Диспетчер операций ввода-вывода перепаковывает запрос в вызов диспетчера объектов.
  5. Диспетчер объектов обрабатывает символьные ссылки и гарантирует, что пользователь имеет права на выполнение перехода по пути, в котором будет создан файл. Дополнительные сведения см., в разделе проверки безопасности в диспетчере объектов.
  6. Диспетчер объектов вызывает системный компонент, принадлежащий базовому типу объекта, связанному с запросом. Для запроса на создание файла этот компонент является диспетчером ввода-вывода, который владеет объектами устройства.
  7. Диспетчер ввода-вывода сверяет дескриптор безопасности объекта устройства с маркером доступа процесса пользователя, чтобы убедиться, что у пользователя есть необходимый доступ к устройству. Дополнительные сведения см. в разделе "Проверки безопасности" в диспетчере ввода-вывода.
  8. Если у пользовательского процесса есть необходимый доступ, диспетчер ввода-вывода создает дескриптор и отправляет запрос IRP_MJ_CREATE драйверу для устройства или файловой системы.
  9. Драйвер выполняет дополнительные проверки безопасности по мере необходимости. Например, если запрос указывает объект в пространстве имен устройства, драйвер должен убедиться, что вызывающий объект имеет необходимые права доступа. Дополнительные сведения см. в разделе проверки безопасности драйвера.

Проверка безопасности в диспетчере объектов

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

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

Проверка безопасности в диспетчере ввода-вывода

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

Если дескриптор дублируется, права можно удалить из копии, но не добавить к ней.

Когда диспетчер ввода-вывода создает объект, он преобразует универсальные режимы доступа Win32 в права конкретного объекта. Например, следующие права применяются к файлам и каталогам:

Режим доступа Win32 Права конкретного объекта
GENERIC_READ ReadData
GENERIC_WRITE ЗаписатьДанные
GENERIC_EXECUTE ReadAttributes
GENERIC_ALL Все

Чтобы создать файл, процесс должен иметь права на обход родительских каталогов в целевом пути. Например, чтобы создать \Device\CDROM0\Directory\File.txt, процесс должен иметь право пройти по \Device, \Device\CDROM0 и \Device\CDROM0\Directory. Диспетчер операций ввода-вывода проверяет только права обхода для этих каталогов.

Диспетчер операций ввода-вывода проверяет права обхода при анализе имени файла. Если имя файла является символьной ссылкой, диспетчер ввода-вывода преобразует её в полный путь, а затем проверяет права на обход, начиная с корневого каталога. Например, предположим, что символьная ссылка \DosDevices\D сопоставляется с именем устройства Windows NT \Device\CDROM0. Процесс должен иметь права обхода к каталогу \Device.

Дополнительные сведения см. в разделе Object Handles and Object Security.

Проверка безопасности в драйвере

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

При использовании драйверов WDM диспетчер ввода-вывода не выполняет проверки безопасности в пространстве имен, если объект устройства не был создан, указав FILE_DEVICE_SECURE_OPEN. Если FILE_DEVICE_SECURE_OPEN не задано, драйвер отвечает за безопасность своего пространства имен. Дополнительные сведения см. в Контроль доступа к пространству имен устройств и Обеспечение безопасности объектов устройств.

Для драйверов WDF всегда устанавливается флаг FILE_DEVICE_SECURE_OPEN, поэтому перед предоставлением приложению доступа к любым именам в пространстве имен устройства будет проверяться дескриптор безопасности устройства. Дополнительные сведения см. в статье Управление доступом к устройству в драйверах KMDF.

Границы безопасности Windows

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

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

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

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

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

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

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

Путь (2) — это более низкий путь риска, так как приложение работает с правами администратора и вызывается непосредственно в драйвер ядра. Администратор уже представляет собой довольно высокий уровень привилегий в системе, поэтому область атаки от администратора к ядру менее интересна как цель для злоумышленников, но всё же остаётся значимой границей доверия.

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

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

Рекомендации по модели безопасности Windows

  • Задайте строгие списки управления доступом по умолчанию при вызове подпрограммы IoCreateDeviceSecure.
  • Укажите списки управления доступом в INF-файле для каждого устройства. При необходимости эти списки управления доступом могут ослаблять жесткие списки управления доступом по умолчанию.
  • Задайте FILE_DEVICE_SECURE_OPEN характеристику, чтобы применить параметры безопасности объекта устройства к пространству имен устройства.
  • Не определяйте IOCTLs, разрешающие FILE_ANY_ACCESS, если нельзя гарантировать, что такой доступ не будет использован злоумышленниками.
  • Используйте процедуру IoValidateDeviceIoControlAccess для повышения безопасности существующих IOCTLS, допускающих FILE_ANY_ACCESS.
  • Создайте модель угроз, чтобы изучить границы безопасности и искать непреднамеренные пути. Дополнительные сведения см. в статье Моделирование угроз для драйверов.
  • Смотрите контрольный список безопасности драйверов для дополнительных рекомендаций по безопасности водителя в разделе.

См. также

Обеспечение безопасности объектов устройств

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