Modelo de segurança do Windows para desenvolvedores de driver

O modelo de segurança do Windows é baseado em objetos protegíveis. Cada componente do sistema operacional deve garantir a segurança dos objetos pelos quais ele é responsável. Os drivers, portanto, devem proteger a segurança de seus dispositivos e objetos de dispositivo.

Este tópico resume como o modelo de segurança do Windows se aplica aos drivers do modo kernel.

Modelo de segurança do Windows

O modelo de segurança do Windows é baseado principalmente em direitos por objeto, com um pequeno número de privilégios em todo o sistema. Os objetos que podem ser protegidos incluem , mas não se limitam a processos, threads, eventos e outros objetos de sincronização, bem como arquivos, diretórios e dispositivos.

Para cada tipo de objeto, os direitos genéricos de leitura, gravação e execução são mapeados em direitos detalhados específicos do objeto. Por exemplo, para arquivos e diretórios, os direitos possíveis incluem o direito de ler ou gravar o arquivo ou diretório, o direito de ler ou gravar atributos de arquivo estendido, o direito de percorrer um diretório e o direito de gravar o descritor de segurança de um objeto.

O modelo de segurança envolve os seguintes conceitos:

  • SIDs (identificadores de segurança)
  • Tokens de acesso
  • Descritores de segurança
  • ACLs (Listas de Controle de Acesso)
  • Privilégios

SIDs (Identificadores de Segurança)

Um SID (identificador de segurança, também chamado de entidade de segurança) identifica um usuário, um grupo ou uma sessão de logon. Cada usuário tem um SID exclusivo, que é recuperado pelo sistema operacional em logon.

Os SIDs são emitidos por uma autoridade, como o sistema operacional ou um servidor de domínio. Alguns SIDs são bem conhecidos e têm nomes e identificadores. Por exemplo, o SID S-1-1-0 identifica Todos (ou Mundo).

Tokens de acesso

Cada processo tem um token de acesso. O token de acesso descreve o contexto de segurança completo do processo. Ele contém o SID do usuário, o SID dos grupos aos quais o usuário pertence e o SID da sessão de logon, bem como uma lista dos privilégios de todo o sistema concedidos ao usuário.

Por padrão, o sistema usa o token de acesso primário para um processo sempre que um thread do processo interage com um objeto protegível. No entanto, um thread pode representar uma conta cliente. Quando um thread representa, ele tem um token de representação além de seu próprio token primário. O token de representação descreve o contexto de segurança da conta de usuário que o thread está representando. A representação é especialmente comum no tratamento de RPC (Chamada de Procedimento Remoto).

Um token de acesso que descreve um contexto de segurança restrito para um thread ou processo é chamado de token restrito. Os SIDs em um token restrito só podem ser definidos para negar o acesso, não para permitir o acesso, para objetos protegíveis. Além disso, o token pode descrever um conjunto limitado de privilégios em todo o sistema. O SID e a identidade do usuário permanecem os mesmos, mas os direitos de acesso do usuário são limitados enquanto o processo está usando o token restrito. A função CreateRestrictedToken cria um token restrito.

Descritores de segurança

Cada objeto nomeado do Windows tem um descritor de segurança; alguns objetos sem nome também fazem. O descritor de segurança descreve os SIDs do proprietário e do grupo para o objeto juntamente com suas ACLs.

O descritor de segurança de um objeto geralmente é criado pela função que cria o objeto . Quando um driver chama a rotina IoCreateDevice ou IoCreateDeviceSecure para criar um objeto de dispositivo, o sistema aplica um descritor de segurança ao objeto de dispositivo criado e define ACLs para o objeto . Para a maioria dos dispositivos, as ACLs são especificadas no arquivo INF (informações do dispositivo).

Para obter mais informações , descritores de segurança na documentação do driver do kernel.

Listas de Controle de Acesso

Controle de Acesso Listas (ACLs) habilitam o controle refinado sobre o acesso a objetos. Uma ACL faz parte do descritor de segurança para cada objeto.

Cada ACL contém zero ou mais Controle de Acesso Entradas (ACE). Cada ACE, por sua vez, contém um único SID que identifica um usuário, um grupo ou um computador e uma lista de direitos negados ou permitidos para esse SID.

ACLs para objetos de dispositivo

A ACL de um objeto de dispositivo pode ser definida de qualquer uma das três maneiras:

  • Defina no descritor de segurança padrão para seu tipo de dispositivo.
  • Criado programaticamente pela função RtlCreateSecurityDescriptor e definido pela função RtlSetDaclSecurityDescriptor .
  • Especificado em SDDL (Linguagem de Definição de Descritor de Segurança) no arquivo INF do dispositivo ou em uma chamada para a rotina IoCreateDeviceSecure .

Todos os drivers devem usar o SDDL no arquivo INF para especificar ACLs para seus objetos de dispositivo.

O SDDL é uma linguagem de descrição extensível que permite que os componentes criem ACLs em um formato de cadeia de caracteres. O SDDL é usado pelo código do modo de usuário e do modo kernel. A figura a seguir mostra o formato de cadeias de caracteres SDDL para objetos de dispositivo.

Diagrama mostrando o formato de cadeias de caracteres SDDL para objetos de dispositivo.

O valor do Access especifica o tipo de acesso permitido. O valor sid especifica um identificador de segurança que determina a quem o valor do Access se aplica (por exemplo, um usuário ou grupo).

Por exemplo, a cadeia de caracteres SDDL a seguir permite que o Sistema (SY) acesse tudo e permite que todos os outros (WD) só tenham acesso de leitura:

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

O arquivo de cabeçalho wdmsec.h também inclui um conjunto de cadeias de caracteres SDDL predefinidas que são adequadas para objetos de dispositivo. Por exemplo, o arquivo de cabeçalho define SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX da seguinte maneira:

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

O primeiro segmento dessa cadeia de caracteres permite que o kernel e o SY (sistema operacional) controle completo sobre o dispositivo. O segundo segmento permite que qualquer pessoa no ba (grupo de administradores) interno acesse todo o dispositivo, mas não altere a ACL. O terceiro segmento permite que todos (WD) leiam ou escrevam no dispositivo e o quarto segmento concede os mesmos direitos ao RC (código não confiável). Os drivers podem usar as cadeias de caracteres predefinidas como está ou como modelos para cadeias de caracteres específicas do objeto do dispositivo.

Todos os objetos de dispositivo em uma pilha devem ter as mesmas ACLs. Alterar as ACLs em um objeto de dispositivo na pilha altera as ACLs em toda a pilha do dispositivo.

No entanto, adicionar um novo objeto de dispositivo à pilha não altera nenhuma ACL, seja aquelas do novo objeto de dispositivo (se ele tiver ACLs) ou as de qualquer objeto de dispositivo existente na pilha. Quando um driver cria um novo objeto de dispositivo e o anexa à parte superior da pilha, o driver deve copiar as ACLs da pilha para o novo objeto de dispositivo copiando o campo DeviceObject.Characteristics do próximo driver inferior.

A rotina IoCreateDeviceSecure dá suporte a um subconjunto de cadeias de caracteres SDDL que usam SIDs predefinidos, como WD e SY. As APIs do modo de usuário e os arquivos INF dão suporte à sintaxe SDDL completa.

Verificações de segurança usando ACLs

Quando um processo solicita acesso a um objeto, as verificações de segurança comparam as ACLs do objeto com os SIDs no token de acesso do chamador.

O sistema compara os ACEs em uma ordem de cima para baixo estrita e para na primeira correspondência relevante. Portanto, ao criar uma ACL, você sempre deve colocar ACEs de negação acima dos ACEs de concessão correspondentes. Os exemplos a seguir mostram como a comparação prossegue.

Exemplo 1: Comparando uma ACL com um token de acesso

O exemplo 1 mostra como o sistema compara uma ACL com o token de acesso para o processo de um chamador. Suponha que o chamador queira abrir um arquivo que tenha a ACL mostrada na tabela a seguir.

ACL de arquivo de exemplo

Permissão SID Access
Allow Contabilidade Gravar, excluir
Allow Sales Acrescentar
Negar Ofício Acrescentar, gravar, excluir
Allow Todos Ler

Essa ACL tem quatro ACEs, que se aplicam especificamente aos grupos Contabilidade, Vendas, Jurídico e Todos.

Em seguida, suponha que o token de acesso para o processo de solicitação contenha SIDs para um usuário e três grupos, na seguinte ordem:

Usuário Jim (S-1-5-21...)

Contabilidade de Grupo (S-1-5-22...)

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

Agrupar Todos (S-1-1-0)

Ao comparar uma ACL de arquivo com um token de acesso, o sistema primeiro procura um ACE para o usuário Jim na ACL do arquivo. Nenhum aparece, então, em seguida, ele procura um ACE para o grupo Contabilidade. Conforme mostrado na tabela anterior, uma ACE para o grupo Contabilidade aparece como a primeira entrada na ACL do arquivo, portanto, o processo de Jim recebe o direito de gravar ou excluir o arquivo e a comparação é interrompida. Se a ACE para o grupo Jurídico precedesse a ACE para o grupo Contabilidade na ACL, o processo seria negado para gravar, acrescentar e excluir o acesso ao arquivo.

Exemplo 2: comparando uma ACL com um token restrito

O sistema compara uma ACL a um token restrito da mesma forma que compara aqueles em um token que não é restrito. No entanto, um SID de negação em um token restrito pode corresponder apenas a uma NEGAÇÃO ACE em uma ACL.

O exemplo 2 mostra como o sistema compara a ACL de um arquivo com um token restrito. Suponha que o arquivo tenha a mesma ACL mostrada na tabela anterior. Neste exemplo, no entanto, o processo tem um token restrito que contém os seguintes SIDs:

Usuário Jim (S-1-5-21...) Negar

Contabilidade de Grupo (S-1-5-22...) Negar

Grupo Legal (S-1-5-23...) Negar

Agrupar Todos (S-1-1-0)

A ACL do arquivo não lista o SID de Jim, portanto, o sistema prossegue para o SID do grupo de contabilidade. Embora a ACL do arquivo tenha uma ACE para o grupo Contabilidade, essa ACE permite o acesso; portanto, ele não corresponde ao SID no token restrito do processo, o que nega o acesso. Como resultado, o sistema prossegue para o SID do grupo jurídico. A ACL do arquivo contém uma ACE para o grupo Jurídico que nega acesso, portanto, o processo não pode gravar, acrescentar ou excluir o arquivo.

Privilégios

Um privilégio é o direito de um usuário executar uma operação relacionada ao sistema no computador local, como carregar um driver, alterar a hora ou desligar o sistema.

Os privilégios são diferentes dos direitos de acesso porque se aplicam a tarefas e recursos relacionados ao sistema em vez de objetos e porque são atribuídos a um usuário ou grupo por um administrador do sistema, e não pelo sistema operacional.

O token de acesso para cada processo contém uma lista dos privilégios concedidos ao processo. Os privilégios devem ser habilitados especificamente antes do uso. Para obter mais informações sobre privilégios, consulte Privilégios na documentação do driver de kernel.

Cenário de modelo de segurança do Windows: criando um arquivo

O sistema usa os constructos de segurança descritos no modelo de segurança do Windows sempre que um processo cria um identificador para um arquivo ou objeto.

O diagrama a seguir mostra as ações relacionadas à segurança que são disparadas quando um processo de modo de usuário tenta criar um arquivo.

Fluxograma ilustrando as ações relacionadas à segurança quando um processo de modo de usuário tenta criar um arquivo.

O diagrama anterior mostra como o sistema responde quando um aplicativo de modo de usuário chama a função CreateFile . As notas a seguir referem-se aos números circulados na figura:

  1. Um aplicativo de modo de usuário chama a função CreateFile , passando um nome de arquivo válido do Microsoft Win32.
  2. O modo de usuário Kernel32.dll passa a solicitação para Ntdll.dll, que converte o nome Win32 em um nome de arquivo do Microsoft Windows NT.
  3. Ntdll.dll chama a função NtCreateFile com o nome do arquivo do Windows. No Ntoskrnl.exe, o Gerenciador de E/S manipula NtCreateFile.
  4. O Gerenciador de E/S reempacota a solicitação em uma chamada do Gerenciador de Objetos.
  5. O Gerenciador de Objetos resolve links simbólicos e garante que o usuário tenha direitos de passagem para o caminho no qual o arquivo será criado. Para obter mais informações, consulte Verificações de segurança no Gerenciador de Objetos.
  6. O Gerenciador de Objetos chama o componente do sistema que possui o tipo de objeto subjacente associado à solicitação. Para uma solicitação de criação de arquivo, esse componente é o Gerenciador de E/S, que possui objetos de dispositivo.
  7. O Gerenciador de E/S verifica o descritor de segurança do objeto de dispositivo em relação ao token de acesso para o processo do usuário para garantir que o usuário tenha o acesso necessário ao dispositivo. Para obter mais informações, consulte Verificações de segurança no Gerenciador de E/S.
  8. Se o processo do usuário tiver o acesso necessário, o Gerenciador de E/S criará um identificador e enviará uma solicitação de IRP_MJ_CREATE ao driver para o dispositivo ou sistema de arquivos.
  9. O driver executa verificações de segurança adicionais conforme necessário. Por exemplo, se a solicitação especificar um objeto no namespace do dispositivo, o driver deverá garantir que o chamador tenha os direitos de acesso necessários. Para obter mais informações, consulte Verificações de segurança no driver.

Verificações de segurança no Gerenciador de Objetos

A responsabilidade de verificar os direitos de acesso pertence ao componente de nível mais alto que pode executar essas verificações. Se o Gerenciador de Objetos puder verificar os direitos de acesso do chamador, ele o fará. Caso contrário, o Gerenciador de Objetos passa a solicitação para o componente responsável pelo tipo de objeto subjacente. Esse componente, por sua vez, verifica o acesso, se puder; se não puder, ele passará a solicitação para um componente ainda inferior, como um driver.

O Gerenciador de Objetos verifica ACLs para tipos de objeto simples, como eventos e bloqueios mutex. Para objetos que têm um namespace, o proprietário do tipo executa verificações de segurança. Por exemplo, o Gerenciador de E/S é considerado o proprietário do tipo para objetos de dispositivo e objetos de arquivo. Se o Gerenciador de Objetos encontrar o nome de um objeto de dispositivo ou objeto de arquivo ao analisar um nome, ele enviará o nome para o Gerenciador de E/S, como no cenário de criação de arquivo apresentado acima. O Gerenciador de E/S verifica os direitos de acesso, se possível. Se o nome especificar um objeto dentro de um namespace de dispositivo, o Gerenciador de E/S, por sua vez, entregará o nome ao driver do dispositivo (ou sistema de arquivos) e esse driver será responsável por validar o acesso solicitado.

Verificações de segurança no Gerenciador de E/S

Quando o Gerenciador de E/S cria um identificador, ele verifica os direitos do objeto em relação ao token de acesso do processo e armazena os direitos concedidos ao usuário junto com o identificador. Quando as solicitações de E/S posteriores chegam, o Gerenciador de E/S verifica os direitos associados ao identificador para garantir que o processo tenha o direito de executar a operação de E/S solicitada. Por exemplo, se o processo solicitar posteriormente uma operação de gravação, o Gerenciador de E/S verificará os direitos associados ao identificador para garantir que o chamador tenha acesso de gravação ao objeto.

Se o identificador estiver duplicado, os direitos poderão ser removidos da cópia, mas não adicionados a ele.

Quando o Gerenciador de E/S cria um objeto, ele converte modos de acesso Win32 genéricos em direitos específicos do objeto. Por exemplo, os seguintes direitos se aplicam a arquivos e diretórios:

Modo de acesso do Win32 Direitos específicos do objeto
GENERIC_READ ReadData
GENERIC_WRITE WriteData
GENERIC_EXECUTE Readattributes
GENERIC_ALL Tudo

Para criar um arquivo, um processo deve ter direitos de passagem para os diretórios pai no caminho de destino. Por exemplo, para criar \Device\CDROM0\Directory\File.txt, um processo deve ter o direito de percorrer \Device, \Device\CDROM0 e \Device\CDROM0\Directory. O Gerenciador de E/S verifica apenas os direitos de passagem desses diretórios.

O Gerenciador de E/S verifica os direitos de passagem quando analisa o nome do arquivo. Se o nome do arquivo for um link simbólico, o Gerenciador de E/S o resolverá para um caminho completo e verificará os direitos de passagem, começando pela raiz. Por exemplo, suponha que o link simbólico \DosDevices\D mapeia para o Windows NT nome do dispositivo \Device\CDROM0. O processo deve ter direitos de passagem para o diretório \Device.

Para obter mais informações, consulte Identificadores de objeto e Segurança de Objeto.

Verificações de segurança no driver

O kernel do sistema operacional trata cada driver, na verdade, como um sistema de arquivos com seu próprio namespace. Consequentemente, quando um chamador tenta criar um objeto no namespace do dispositivo, o Gerenciador de E/S verifica se o processo tem direitos de passagem para os diretórios no caminho.

Com drivers WDM, o Gerenciador de E/S não executa verificações de segurança no namespace, a menos que o Objeto de Dispositivo tenha sido criado especificando FILE_DEVICE_SECURE_OPEN. Quando FILE_DEVICE_SECURE_OPEN não está definido, o driver é responsável por garantir a segurança de seu namespace. Para obter mais informações, consulte Controlando o acesso ao namespace do dispositivo e Protegendo objetos de dispositivo.

Para drivers WDF, o sinalizador FILE_DEVICE_SECURE_OPEN sempre é definido, para que haja uma marcar do descritor de segurança do dispositivo antes de permitir que um aplicativo acesse quaisquer nomes no namespace do dispositivo. Para obter mais informações, consulte Controlando o acesso ao dispositivo em drivers KMDF.

Limites de segurança do Windows

Os drivers que se comunicam entre si e com chamadores de modo de usuário de diferentes níveis de privilégio podem ser considerados cruzando um limite de confiança. Um limite de confiança é qualquer caminho de execução de código que cruza de um processo com privilégios inferiores para um processo com privilégios mais altos.

Quanto maior a disparidade nos níveis de privilégio, mais interessante é o limite para invasores que desejam executar ataques como um ataque de escalonamento de privilégios contra o driver ou processo de destino.

Parte do processo de criação de um modelo de ameaça é examinar os limites de segurança e procurar caminhos imprevistos. Para obter mais informações, consulte Modelagem de ameaças para drivers.

Todos os dados que cruzam um limite de confiança não são confiáveis e devem ser validados.

Este diagrama mostra três drivers de kernel e dois aplicativos, um em um contêiner de aplicativo e um aplicativo executado com direitos de administrador. As linhas vermelhas indicam limites de confiança de exemplo.

Diagrama ilustrando a superfície de ataque do driver com três drivers de kernel, um aplicativo em um contêiner de aplicativo e um aplicativo com direitos de administrador.

Como o contêiner do aplicativo pode fornecer restrições adicionais e não está em execução no nível do administrador, o caminho (1) é um caminho de risco mais alto para um ataque de escalonamento, pois o limite de confiança está entre um contêiner de aplicativo (um processo de privilégio muito baixo) e um driver de kernel.

O caminho (2) é um caminho de menor risco, pois o aplicativo está em execução com direitos de administrador e está chamando diretamente no driver de kernel. Administração já é um privilégio bastante alto no sistema, portanto, a superfície de ataque de administrador para kernel é menos um alvo interessante para invasores, mas ainda é um limite de confiança notável.

O caminho (3) é um exemplo de um caminho de execução de código que cruza vários limites de confiança que podem ser perdidos se um modelo de ameaça não for criado. Neste exemplo, há um limite de confiança entre o driver 1 e o driver 3, pois o driver 1 recebe a entrada do aplicativo de modo de usuário e o passa diretamente para o driver 3.

Todas as entradas que entram no driver do modo de usuário não são confiáveis e devem ser validadas. As entradas provenientes de outros drivers também podem não ser confiáveis, dependendo se o driver anterior era apenas uma passagem simples (por exemplo, os dados foram recebidos pelo driver 1 do aplicativo 1 , o driver 1 não fez nenhuma validação nos dados e apenas os passou para o driver 3). Identifique todas as superfícies de ataque e os limites de confiança e valide todos os dados que os cruzam criando um modelo de ameaça completo.

Recomendações do modelo de Segurança do Windows

  • Defina ACLs padrão fortes em chamadas para a rotina IoCreateDeviceSecure .
  • Especifique ACLs no arquivo INF para cada dispositivo. Essas ACLs podem afrouxar ACLs padrão rígidas, se necessário.
  • Defina a característica FILE_DEVICE_SECURE_OPEN para aplicar as configurações de segurança do objeto de dispositivo ao namespace do dispositivo.
  • Não defina IOCTLs que permitam FILE_ANY_ACCESS, a menos que esse acesso não possa ser explorado maliciosamente.
  • Use a rotina IoValidateDeviceIoControlAccess para reforçar a segurança no IOCTLS existente que permite FILE_ANY_ACCESS.
  • Crie um modelo de ameaça para examinar os limites de segurança e procurar caminhos imprevistos. Para obter mais informações, consulte Modelagem de ameaças para drivers.
  • Confira Lista de verificação de segurança do driver para obter recomendações adicionais de segurança do driver.

Consulte Também

Protegendo objetos de dispositivo

Lista de verificação de segurança do driver