Modèle de sécurité Windows pour les développeurs de pilotes

Le modèle de sécurité Windows est basé sur des objets sécurisables. Chaque composant du système d’exploitation doit garantir la sécurité des objets dont il est responsable. Les pilotes doivent donc protéger la sécurité de leurs appareils et objets d’appareil.

Cette rubrique résume la façon dont le modèle de sécurité Windows s’applique aux pilotes en mode noyau.

Modèle de sécurité Windows

Le modèle de sécurité Windows est principalement basé sur les droits par objet, avec un petit nombre de privilèges à l’échelle du système. Les objets qui peuvent être sécurisés incluent, sans s’y limiter, les processus, les threads, les événements et autres objets de synchronisation, ainsi que les fichiers, les répertoires et les appareils.

Pour chaque type d’objet, les droits génériques de lecture, d’écriture et d’exécution sont mappés en droits détaillés spécifiques à l’objet. Par exemple, pour les fichiers et les répertoires, les droits possibles incluent le droit de lire ou d’écrire le fichier ou le répertoire, le droit de lire ou d’écrire des attributs de fichier étendus, le droit de parcourir un répertoire et le droit d’écrire le descripteur de sécurité d’un objet.

Le modèle de sécurité implique les concepts suivants :

  • Identificateurs de sécurité (SID)
  • Jetons d’accès
  • Descripteurs de sécurité
  • Listes de contrôle d’accès (ACL)
  • Privilèges

Identificateurs de sécurité (SID)

Un identificateur de sécurité (SID, également appelé principal) identifie un utilisateur, un groupe ou une session d’ouverture de session. Chaque utilisateur a un SID unique, qui est récupéré par le système d’exploitation lors de l’ouverture de session.

Les SID sont émis par une autorité telle que le système d’exploitation ou un serveur de domaine. Certains SID sont connus et ont des noms ainsi que des identificateurs. Par exemple, le SID S-1-1-0 identifie Tout le monde (ou monde).

Jetons d’accès

Chaque processus a un jeton d’accès. Le jeton d’accès décrit le contexte de sécurité complet du processus. Il contient le SID de l’utilisateur, le SID des groupes auxquels l’utilisateur appartient et le SID de la session d’ouverture de session, ainsi qu’une liste des privilèges à l’échelle du système accordés à l’utilisateur.

Par défaut, le système utilise le jeton d’accès principal pour un processus chaque fois qu’un thread du processus interagit avec un objet sécurisable. Toutefois, un thread peut emprunter l’identité d’un compte client. Lorsqu’un thread emprunte l’identité, il a un jeton d’emprunt d’identité en plus de son propre jeton principal. Le jeton d’emprunt d’identité décrit le contexte de sécurité du compte d’utilisateur que le thread emprunte l’identité. L’emprunt d’identité est particulièrement courant dans la gestion des appels de procédure distante (RPC).

Un jeton d’accès qui décrit un contexte de sécurité restreint pour un thread ou un processus est appelé jeton restreint. Les SID d’un jeton restreint peuvent être définis uniquement pour refuser l’accès, et non pour autoriser l’accès, aux objets sécurisables. En outre, le jeton peut décrire un ensemble limité de privilèges à l’échelle du système. Le SID et l’identité de l’utilisateur restent les mêmes, mais les droits d’accès de l’utilisateur sont limités pendant que le processus utilise le jeton restreint. La fonction CreateRestrictedToken crée un jeton restreint.

Descripteurs de sécurité

Chaque objet Windows nommé a un descripteur de sécurité ; certains objets sans nom le font aussi. Le descripteur de sécurité décrit les SID de propriétaire et de groupe de l’objet, ainsi que ses listes de contrôle d’accès.

Le descripteur de sécurité d’un objet est généralement créé par la fonction qui crée l’objet. Lorsqu’un pilote appelle la routine IoCreateDevice ou IoCreateDeviceSecure pour créer un objet d’appareil, le système applique un descripteur de sécurité à l’objet d’appareil créé et définit des listes de contrôle d’accès pour l’objet. Pour la plupart des appareils, les listes de contrôle d’accès sont spécifiées dans le fichier d’informations sur l’appareil (INF).

Pour plus d’informations sur les descripteurs de sécurité dans la documentation du pilote du noyau.

Listes de contrôle d’accès

Access Control Listes permettent un contrôle affiné de l’accès aux objets. Une liste de contrôle d’accès fait partie du descripteur de sécurité pour chaque objet.

Chaque liste de contrôle d’accès contient au moins zéro entrée Access Control (ACE). Chaque ACE, à son tour, contient un seul SID qui identifie un utilisateur, un groupe ou un ordinateur et une liste de droits qui sont refusés ou autorisés pour ce SID.

Listes de contrôle d’accès pour les objets d’appareil

La liste de contrôle d’accès d’un objet d’appareil peut être définie de trois manières :

  • Défini dans le descripteur de sécurité par défaut pour son type d’appareil.
  • Créé par programmation par la fonction RtlCreateSecurityDescriptor et défini par la fonction RtlSetDaclSecurityDescriptor .
  • Spécifié dans le langage SDDL (Security Descriptor Definition Language) dans le fichier INF de l’appareil ou dans un appel à la routine IoCreateDeviceSecure .

Tous les pilotes doivent utiliser SDDL dans le fichier INF pour spécifier des listes de contrôle d’accès pour leurs objets d’appareil.

SDDL est un langage de description extensible qui permet aux composants de créer des listes de contrôle d’accès dans un format de chaîne. SDDL est utilisé à la fois par le code en mode utilisateur et en mode noyau. La figure suivante montre le format des chaînes SDDL pour les objets d’appareil.

Diagramme montrant le format des chaînes SDDL pour les objets d’appareil.

La valeur Access spécifie le type d’accès autorisé. La valeur SID spécifie un identificateur de sécurité qui détermine à qui la valeur Access s’applique (par exemple, un utilisateur ou un groupe).

Par exemple, la chaîne SDDL suivante autorise l’accès système (SY) à tout et autorise tout le monde (WD) à un accès en lecture uniquement :

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

Le fichier d’en-tête wdmsec.h inclut également un ensemble de chaînes SDDL prédéfinies qui conviennent aux objets d’appareil. Par exemple, le fichier d’en-tête définit SDDL_DEVOBJ_SYS_ALL_ADM_RWX_WORLD_RWX_RES_RWX comme suit :

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

Le premier segment de cette chaîne permet au noyau et au système d’exploitation (SY) de contrôler complètement l’appareil. Le deuxième segment permet à toute personne du groupe Administrateurs intégré (BA) d’accéder à l’ensemble de l’appareil, mais pas de modifier la liste de contrôle d’accès. Le troisième segment permet à tout le monde (WD) de lire ou d’écrire sur l’appareil, et le quatrième segment accorde les mêmes droits au code non approuvé (RC). Les pilotes peuvent utiliser les chaînes prédéfinies en l’état ou en tant que modèles pour des chaînes spécifiques à l’objet d’appareil.

Tous les objets d’appareil d’une pile doivent avoir les mêmes listes de contrôle d’accès. La modification des listes de contrôle d’accès sur un objet d’appareil dans la pile modifie les listes de contrôle d’accès sur l’ensemble de la pile d’appareils.

Toutefois, l’ajout d’un nouvel objet d’appareil à la pile ne modifie pas les listes de contrôle d’accès, ni celles du nouvel objet d’appareil (s’il a des listes de contrôle d’accès) ni celles des objets d’appareil existants dans la pile. Lorsqu’un pilote crée un objet d’appareil et l’attache au haut de la pile, il doit copier les listes de contrôle d’accès de la pile dans le nouvel objet d’appareil en copiant le champ DeviceObject.Characteristics du pilote inférieur suivant.

La routine IoCreateDeviceSecure prend en charge un sous-ensemble de chaînes SDDL qui utilisent des SID prédéfinis tels que WD et SY. Les API en mode utilisateur et les fichiers INF prennent en charge la syntaxe SDDL complète.

Vérifications de sécurité à l’aide de listes de contrôle d’accès

Lorsqu’un processus demande l’accès à un objet, les vérifications de sécurité comparent les listes de contrôle d’accès de l’objet aux SID dans le jeton d’accès de l’appelant.

Le système compare les ACE dans un ordre supérieur strict et s’arrête à la première correspondance pertinente. Par conséquent, lors de la création d’une liste de contrôle d’accès, vous devez toujours placer les AIC de déni au-dessus des aces d’octroi correspondants. Les exemples suivants illustrent le déroulement de la comparaison.

Exemple 1 : Comparaison d’une liste de contrôle d’accès à un jeton d’accès

L’exemple 1 montre comment le système compare une liste de contrôle d’accès au jeton d’accès pour le processus d’un appelant. Supposons que l’appelant souhaite ouvrir un fichier qui a la liste de contrôle d’accès indiquée dans le tableau suivant.

Exemple de liste de contrôle d’accès de fichier

Autorisation SID Access
Autoriser Comptabilité Écrire, supprimer
Autoriser Sales Ajouter (Append)
Deny Informations juridiques Ajouter, écrire, supprimer
Autoriser Tout le monde Lire

Cette liste de contrôle d’accès a quatre AE, qui s’appliquent spécifiquement aux groupes Comptabilité, Ventes, Juridiques et Tout le monde.

Ensuite, supposons que le jeton d’accès du processus de demande contient des SID pour un utilisateur et trois groupes, dans l’ordre suivant :

Utilisateur Jim (S-1-5-21...)

Comptabilité de groupe (S-1-5-22...)

Groupe Juridique (S-1-5-23...)

Groupe tout le monde (S-1-1-0)

Lors de la comparaison d’une liste de contrôle d’accès de fichier à un jeton d’accès, le système recherche d’abord un ACE pour l’utilisateur Jim dans la liste de contrôle d’accès du fichier. Aucun n’apparaît. Ensuite, il recherche un ACE pour le groupe Comptabilité. Comme indiqué dans le tableau précédent, un ACE pour le groupe Comptabilité apparaît en tant que première entrée dans la liste de contrôle d’accès du fichier, de sorte que le processus de Jim se voit accorder le droit d’écrire ou de supprimer le fichier et la comparaison s’arrête. Si l’ACE du groupe Juridique précède plutôt l’ACE pour le groupe Comptabilité dans la liste de contrôle d’accès, l’accès en écriture, ajout et suppression au fichier est refusé au processus.

Exemple 2 : comparaison d’une liste de contrôle d’accès à un jeton restreint

Le système compare une liste de contrôle d’accès à un jeton restreint de la même façon qu’il compare ceux d’un jeton qui n’est pas restreint. Toutefois, un SID de refus dans un jeton restreint ne peut correspondre qu’à un ace de refus dans une liste de contrôle d’accès.

L’exemple 2 montre comment le système compare la liste de contrôle d’accès d’un fichier avec un jeton restreint. Supposons que le fichier possède la même liste de contrôle d’accès que celle indiquée dans le tableau précédent. Dans cet exemple, toutefois, le processus a un jeton restreint qui contient les SID suivants :

Utilisateur Jim (S-1-5-21...) Nier

Comptabilité de groupe (S-1-5-22...) Nier

Groupe Juridique (S-1-5-23...) Nier

Groupe tout le monde (S-1-1-0)

L’ACL du fichier ne répertorie pas le SID de Jim, de sorte que le système passe au SID du groupe Comptabilité. Bien que la liste de contrôle d’accès du fichier ait une ACE pour le groupe Comptabilité, cette ACE autorise l’accès ; par conséquent, il ne correspond pas au SID dans le jeton restreint du processus, qui refuse l’accès. Par conséquent, le système passe au SID du groupe Juridique. La liste de contrôle d’accès du fichier contient un ACE pour le groupe Juridique qui refuse l’accès, de sorte que le processus ne peut pas écrire, ajouter ou supprimer le fichier.

Privilèges

Un privilège est le droit pour un utilisateur d’effectuer une opération liée au système sur l’ordinateur local, telle que le chargement d’un pilote, la modification de l’heure ou l’arrêt du système.

Les privilèges sont différents des droits d’accès, car ils s’appliquent aux tâches et ressources liées au système plutôt qu’aux objets, et parce qu’ils sont attribués à un utilisateur ou à un groupe par un administrateur système, plutôt que par le système d’exploitation.

Le jeton d’accès pour chaque processus contient une liste des privilèges accordés au processus. Les privilèges doivent être spécifiquement activés avant d’être utilisés. Pour plus d’informations sur les privilèges, consultez Privilèges dans la documentation du pilote du noyau.

Scénario de modèle de sécurité Windows : Création d’un fichier

Le système utilise les constructions de sécurité décrites dans le modèle de sécurité Windows chaque fois qu’un processus crée un handle pour un fichier ou un objet.

Le diagramme suivant montre les actions liées à la sécurité qui sont déclenchées lorsqu’un processus en mode utilisateur tente de créer un fichier.

Organigramme illustrant les actions liées à la sécurité lorsqu’un processus en mode utilisateur tente de créer un fichier.

Le diagramme précédent montre comment le système répond lorsqu’une application en mode utilisateur appelle la fonction CreateFile . Les notes suivantes font référence aux nombres cerclé dans la figure :

  1. Une application en mode utilisateur appelle la fonction CreateFile , en passant un nom de fichier Microsoft Win32 valide.
  2. Le Kernel32.dll en mode utilisateur transmet la demande à Ntdll.dll, qui convertit le nom Win32 en nom de fichier Microsoft Windows NT.
  3. Ntdll.dll appelle la fonction NtCreateFile avec le nom de fichier Windows. Dans Ntoskrnl.exe, le Gestionnaire d’E/S gère NtCreateFile.
  4. Le Gestionnaire d’E/S repackage la demande dans un appel du Gestionnaire d’objets.
  5. Le Gestionnaire d’objets résout les liens symboliques et garantit que l’utilisateur dispose de droits de traversée pour le chemin d’accès dans lequel le fichier sera créé. Pour plus d’informations, consultez Vérifications de sécurité dans le Gestionnaire d’objets.
  6. Le Gestionnaire d’objets appelle le composant système qui possède le type d’objet sous-jacent associé à la requête. Pour une demande de création de fichier, ce composant est le Gestionnaire d’E/S, qui possède les objets d’appareil.
  7. Le Gestionnaire d’E/S vérifie le descripteur de sécurité de l’objet d’appareil par rapport au jeton d’accès pour le processus de l’utilisateur afin de s’assurer que l’utilisateur dispose de l’accès requis à l’appareil. Pour plus d’informations, consultez Vérifications de sécurité dans le Gestionnaire d’E/S.
  8. Si le processus utilisateur dispose de l’accès requis, le Gestionnaire d’E/S crée un handle et envoie une demande de IRP_MJ_CREATE au pilote pour le périphérique ou le système de fichiers.
  9. Le pilote effectue des vérifications de sécurité supplémentaires en fonction des besoins. Par exemple, si la demande spécifie un objet dans l’espace de noms de l’appareil, le pilote doit s’assurer que l’appelant dispose des droits d’accès requis. Pour plus d’informations, consultez Vérifications de sécurité dans le pilote.

Contrôles de sécurité dans le Gestionnaire d’objets

La responsabilité de la vérification des droits d’accès appartient au composant de niveau supérieur qui peut effectuer ces vérifications. Si le Gestionnaire d’objets peut vérifier les droits d’accès de l’appelant, il le fait. Si ce n’est pas le cas, le Gestionnaire d’objets transmet la requête au composant responsable du type d’objet sous-jacent. Ce composant, à son tour, vérifie l’accès, s’il le peut ; si ce n’est pas le cas, il transmet la demande à un composant encore inférieur, tel qu’un pilote.

Le Gestionnaire d’objets vérifie les ACL pour les types d’objets simples, tels que les événements et les verrous mutex. Pour les objets qui ont un espace de noms, le propriétaire du type effectue des vérifications de sécurité. Par exemple, le Gestionnaire d’E/S est considéré comme le propriétaire de type pour les objets d’appareil et les objets fichier. Si le Gestionnaire d’objets trouve le nom d’un objet d’appareil ou d’un objet fichier lors de l’analyse d’un nom, il remet le nom au Gestionnaire d’E/S, comme dans le scénario de création de fichiers présenté ci-dessus. Le gestionnaire d’E/S vérifie ensuite les droits d’accès s’il le peut. Si le nom spécifie un objet dans un espace de noms d’appareil, le Gestionnaire d’E/S dans remet le nom au pilote de périphérique (ou de système de fichiers), et ce pilote est responsable de la validation de l’accès demandé.

Contrôles de sécurité dans le Gestionnaire d’E/S

Lorsque le Gestionnaire d’E/S crée un handle, il vérifie les droits de l’objet par rapport au jeton d’accès de processus, puis stocke les droits accordés à l’utilisateur avec le handle. Lorsque des demandes d’E/S ultérieures arrivent, le Gestionnaire d’E/S vérifie les droits associés au handle pour s’assurer que le processus a le droit d’effectuer l’opération d’E/S demandée. Par exemple, si le processus demande ultérieurement une opération d’écriture, le Gestionnaire d’E/S vérifie les droits associés au handle pour s’assurer que l’appelant dispose d’un accès en écriture à l’objet.

Si le handle est dupliqué, les droits peuvent être supprimés de la copie, mais pas ajoutés à celle-ci.

Lorsque le Gestionnaire d’E/S crée un objet, il convertit les modes d’accès Win32 génériques en droits spécifiques à l’objet. Par exemple, les droits suivants s’appliquent aux fichiers et répertoires :

Mode d’accès Win32 Droits spécifiques à l’objet
GENERIC_READ ReadData
GENERIC_WRITE WriteData
GENERIC_EXECUTE ReadAttributes
GENERIC_ALL Tous

Pour créer un fichier, un processus doit avoir des droits de traversée sur les répertoires parents dans le chemin d’accès cible. Par exemple, pour créer \Device\CDROM0\Directory\File.txt, un processus doit avoir le droit de parcourir \Device, \Device\CDROM0 et \Device\CDROM0\Directory. Le Gestionnaire d’E/S vérifie uniquement les droits de traversée pour ces répertoires.

Le Gestionnaire d’E/S vérifie les droits de traversée lorsqu’il analyse le nom de fichier. Si le nom de fichier est un lien symbolique, le Gestionnaire d’E/S le résout en chemin d’accès complet, puis vérifie les droits de traversée, en commençant par la racine. Par exemple, supposons que le lien symbolique \DosDevices\D correspond au nom d’appareil Windows NT \Device\CDROM0. Le processus doit avoir des droits de traversée sur le répertoire \Device.

Pour plus d’informations, consultez Descripteurs d’objets et Sécurité des objets.

Contrôles de sécurité dans le pilote

Le noyau du système d’exploitation traite en effet chaque pilote comme un système de fichiers avec son propre espace de noms. Par conséquent, lorsqu’un appelant tente de créer un objet dans l’espace de noms de l’appareil, le Gestionnaire d’E/S vérifie que le processus dispose de droits de traversée sur les répertoires dans le chemin d’accès.

Avec les pilotes WDM, le Gestionnaire d’E/S n’effectue pas de vérifications de sécurité sur l’espace de noms, sauf si l’objet device a été créé en spécifiant FILE_DEVICE_SECURE_OPEN. Lorsque FILE_DEVICE_SECURE_OPEN n’est pas défini, le pilote est chargé de garantir la sécurité de son espace de noms. Pour plus d’informations, consultez Contrôle de l’accès à l’espace de noms d’appareil et Sécurisation des objets d’appareil.

Pour les pilotes WDF, l’indicateur de FILE_DEVICE_SECURE_OPEN est toujours défini, afin qu’il y ait une case activée du descripteur de sécurité de l’appareil avant d’autoriser une application à accéder aux noms de l’espace de noms de l’appareil. Pour plus d’informations, consultez Contrôle de l’accès des appareils dans les pilotes KMDF.

Limites de sécurité Windows

Les pilotes qui communiquent entre eux et avec des appelants en mode utilisateur de différents niveaux de privilèges peuvent être considérés comme franchissant une limite d’approbation. Une limite d’approbation est tout chemin d’exécution de code qui passe d’un processus à privilèges inférieurs à un processus à privilèges plus élevés.

Plus la disparité des niveaux de privilèges est élevée, plus la limite est intéressante pour les attaquants qui souhaitent effectuer des attaques telles qu’une attaque par escalade de privilèges contre le pilote ou le processus ciblé.

Une partie du processus de création d’un modèle de menace consiste à examiner les limites de sécurité et à rechercher des chemins d’accès imprévus. Pour plus d’informations, consultez Modélisation des menaces pour les pilotes.

Toutes les données qui franchissent une limite d’approbation ne sont pas approuvées et doivent être validées.

Ce diagramme montre trois pilotes de noyau et deux applications, un dans un conteneur d’application et une application qui s’exécute avec des droits d’administrateur. Les lignes rouges indiquent des exemples de limites d’approbation.

Diagramme illustrant la surface d’attaque du pilote avec trois pilotes de noyau, une application dans un conteneur d’application et une application avec des droits d’administrateur.

Étant donné que le conteneur d’application peut fournir des contraintes supplémentaires et qu’il ne s’exécute pas au niveau de l’administrateur, le chemin d’accès (1) est un chemin d’accès à risque plus élevé pour une attaque d’escalade, car la limite de confiance se trouve entre un conteneur d’application (processus à privilèges très faible) et un pilote de noyau.

Le chemin d’accès (2) est un chemin à risque inférieur, car l’application s’exécute avec des droits d’administrateur et appelle directement le pilote du noyau. Administration est déjà un privilège assez élevé sur le système, de sorte que la surface d’attaque de l’administrateur au noyau est moins une cible intéressante pour les attaquants, mais toujours une limite de confiance notable.

Path (3) est un exemple de chemin d’exécution de code qui franchit plusieurs limites d’approbation qui peuvent être manquées si aucun modèle de menace n’est créé. Dans cet exemple, il existe une limite d’approbation entre le pilote 1 et le pilote 3, car le pilote 1 prend l’entrée de l’application en mode utilisateur et la transmet directement au pilote 3.

Toutes les entrées entrantes dans le pilote à partir du mode utilisateur ne sont pas approuvées et doivent être validées. Les entrées provenant d’autres pilotes peuvent également être non approuvées selon que le pilote précédent n’était qu’un simple pass-through (par exemple, les données ont été reçues par le pilote 1 à partir de l’application 1 , le pilote 1 n’a pas fait de validation sur les données et les a simplement transmises au pilote 3). Veillez à identifier toutes les surfaces d’attaque et les limites d’approbation et à valider toutes les données qui les traversent, en créant un modèle de menace complet.

Recommandations de modèle Sécurité Windows

  • Définissez des listes de contrôle d’accès par défaut fortes dans les appels à la routine IoCreateDeviceSecure .
  • Spécifiez des listes de contrôle d’accès dans le fichier INF pour chaque appareil. Ces listes de contrôle d’accès peuvent desserrer des listes de contrôle d’accès par défaut étroites si nécessaire.
  • Définissez la caractéristique FILE_DEVICE_SECURE_OPEN pour appliquer les paramètres de sécurité des objets d’appareil à l’espace de noms de l’appareil.
  • Ne définissez pas d’IOCTL qui autorisent FILE_ANY_ACCESS sauf si un tel accès ne peut pas être exploité de manière malveillante.
  • Utilisez la routine IoValidateDeviceIoControlAccess pour renforcer la sécurité sur les IOCTLS existants qui autorisent FILE_ANY_ACCESS.
  • Créez un modèle de menace pour examiner les limites de sécurité et rechercher des chemins imprévus. Pour plus d’informations, consultez Modélisation des menaces pour les pilotes.
  • Pour obtenir des recommandations supplémentaires en matière de sécurité des pilotes, consultez Liste de contrôle de sécurité des pilotes.

Voir aussi

Sécurisation des objets d’appareil

Liste de contrôle de sécurité des pilotes