Partager via


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 de leurs 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, mais qui ne sont pas limités à , les processus, les threads, les événements et d’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 se transforment 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 de connexion. Chaque utilisateur a un SID unique, qui est récupéré par le système d’exploitation au niveau 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 appartient l’utilisateur 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 usurpe une identité, il possède un jeton d’usurpation en plus de son propre jeton principal. Le jeton d’emprunt d’identité décrit le contexte de sécurité du compte d’utilisateur dont 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 non nommés font aussi. Le descripteur de sécurité décrit les SID de propriétaire et de groupe de l’objet ainsi que ses ACL.

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 en savoir plus sur les descripteurs de sécurité, consultez la documentation du pilote du noyau.

Listes de contrôle d’accès

Les listes de contrôle d’accès (ACL) permettent un contrôle précis sur 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 zéro ou plusieurs entrées de contrôle d’accès (ACE). Chaque ACE contient à son tour un SEUL SID qui identifie un utilisateur, un groupe ou un ordinateur et une liste de droits 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 façons :

  • Définie 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 de définition du descripteur de sécurité (SDDL) 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 au format de chaîne. SDDL est utilisé 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 permet au système (SY) d’accéder à tout et autorise tout le monde (WD) à accéder uniquement en lecture :

“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 telles qu’elles sont ou en tant que modèles pour les 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, soit celles du nouvel objet d’appareil (s’il a des listes de contrôle d’accès) ou celles d’objets d’appareil existants dans la pile. Lorsqu’un pilote crée un objet d’appareil et l’attache au haut de la pile, le pilote doit copier les listes de contrôle d’accès de la pile vers le nouvel objet de périphérique 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 des ACL

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 à celles des SID dans le jeton d’accès de l’appelant.

Le système compare les ACE dans un ordre descendant strict et s’arrête sur 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 AE de refus au-dessus des AE d’octroi correspondantes. Les exemples suivants montrent comment la comparaison se poursuit.

Exemple 1 : comparaison d'une ACL à un jeton d'accès

L'exemple 1 montre comment le système compare un ACL au jeton d'accès du processus d'un appelant. Supposons que l’appelant souhaite ouvrir un fichier dont la liste de contrôle d’accès est affichée dans le tableau suivant.

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

Autorisation SID Access
Autoriser Comptabilité Écrire, supprimer
Autoriser Ventes Ajouter
Deny Informations juridiques Ajouter, écrire, supprimer
Autoriser Tout le monde Lire

Cette liste de contrôle d’accès comprend quatre ACL, qui s’appliquent spécifiquement aux groupes Comptabilité, Vente, Informations juridiques et Tout le monde.

Ensuite, supposons que le jeton d’accès pour le processus demandeur 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 Informations juridiques (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. Aucune n’apparaît. Par conséquent, il recherche une ACE pour le groupe Comptabilité. Comme indiqué dans le tableau précédent, un ACE pour le groupe comptabilité apparaît comme la première entrée dans la liste de contrôle d’accès du fichier. Le processus de Jim est donc autorisé à écrire ou à supprimer le fichier et la comparaison s’arrête. Si l'ACE pour le groupe Juridique précède plutôt l'ACE du groupe Comptabilité dans la liste de contrôle d'accès, le processus se verra refuser les accès d'écriture, d'ajout et de suppression au fichier.

Exemple 2 : Comparaison entre une liste de contrôle d’accès et 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 celles d’un jeton qui n’est pas restreint. Toutefois, un SID de refus dans un jeton restreint ne peut correspondre qu’à une 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 à un jeton restreint. Supposons que le fichier a la même liste de contrôle d’accès affiché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...) Refus

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

Groupe Informations juridiques (S-1-5-23...) Refus

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

La liste de contrôle d’accès du fichier ne répertorie pas le SID de Jim. Par conséquent, le système passe au SID du groupe Comptabilité. Bien que la liste de contrôle d’accès du fichier dispose d’une ACE pour le groupe Comptabilité, cette ACE autorise l’accès ; par conséquent, elle ne correspond pas au SID dans le jeton restreint du processus, qui refuse l’accès. Le système passe donc au SID du groupe Informations juridiques. 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, par exemple 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 affecté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 l’utilisation. Pour en savoir plus sur les privilèges, consultez les Privilèges dans la documentation du pilote du noyau.

L'extension !acl formate et affiche le contenu d'une liste de contrôle d'accès (ACL). Pour plus d’informations, consultez Détermination de la liste de contrôle d’accès (ACL) d’un objet et !acl.

L’extension !token affiche une vue mise en forme d’un objet de jeton de sécurité. Pour plus d’informations, consultez  !token.

L’extension !tokenfields affiche les noms et les décalages des champs dans l’objet de jeton d’accès (structure TOKEN). Pour plus d’informations, consultez la section !tokenfields.

L’extension !sid affiche l’identificateur de sécurité (SID) à l’adresse spécifiée. Pour plus d’informations, consultez !sid.

L’extension !sd affiche le descripteur de sécurité à l’adresse spécifiée. Pour plus d’informations, consultez !sd.

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 dans 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 mode utilisateur Kernel32.dll transmet la requête à 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 requête 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 en savoir plus, consultez Vérifications de sécurité dans le gestionnaire d’objets.
  6. Le Gestionnaire d’objets appelle le composant système propriétaire du 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 des objets d’appareil.
  7. Le Gestionnaire d’E/S vérifie le descripteur de sécurité de l’objet de l’appareil par rapport au jeton d’accès du processus de l’utilisateur pour s’assurer que l’utilisateur a 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 a 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 si nécessaire. 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 en savoir plus, consultez Vérifications de sécurité dans le pilote.

Vérifications de sécurité dans le Gestionnaire d’objets

La responsabilité de vérifier les 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 demande au composant responsable du type d’objet sous-jacent. Ce composant vérifie à son tour l’accès, s’il le peut ; s’il ne peut pas, il transmet la requête à un composant toujours 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 de fichier. Si le Gestionnaire d’objets trouve le nom d’un objet d’appareil ou d’un objet de 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 fichier 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 au sein d’un espace de noms d’appareil, le Gestionnaire d’E/S désactive le nom du pilote d’appareil (ou de système de fichiers) et ce pilote est chargé de valider l’accès demandé.

Vérifications 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 sur le jeton d’accès du processus, puis stocke les droits accordés à l’utilisateur ainsi que 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 a accès en écriture à l’objet.

Si la poignée est dupliquée, les droits peuvent être retirés de la copie, mais pas ajoutés.

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 disposer de droits de traversée vers 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 du 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 est mappé au nom de l’appareil Windows NT \Device\CDROM0. Le processus doit disposer de droits de traversée vers le répertoire \Device.

Pour en savoir plus, consultez Handles d’objets et Sécurité des objets.

Vérifications de sécurité dans le pilote logiciel

Le noyau du système d’exploitation traite chaque pilote, en effet, en tant que 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 a des droits de traversée vers 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 responsable de la sécurité de son espace de noms. Pour plus d'informations, consultez Contrôle de l'accès aux espaces 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 vérification du descripteur de sécurité de l’appareil avant d’autoriser une application à accéder à tous les noms dans l’espace de noms de l’appareil. Pour en savoir plus, consulter Contrôle de l’accès des appareils dans les pilotes KMDF.

Limites de sécurité Windows

Les pilotes qui communiquent entre eux et les appelants en mode utilisateur de différents niveaux de privilège peuvent être considérés comme franchissant une limite d’approbation. Une limite d’approbation est n’importe quel chemin d’exécution de code qui traverse un processus privilégié inférieur dans un processus privilégié supérieur.

Plus la disparité est élevée dans les niveaux de privilèges, plus la limite est intéressante pour les attaquants qui souhaitent effectuer des attaques telles qu’une attaque d’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 imprévus. Pour plus d'informations, consultez la 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, une dans un conteneur d’applications et une application qui s’exécute avec des droits d’administrateur. Les lignes rouges indiquent des exemples de limites de confiance.

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

Comme le conteneur d’applications peut fournir des contraintes supplémentaires et ne s’exécute pas au niveau de l’administrateur, le chemin d’accès (1) est un chemin à risque plus élevé pour une attaque d’escalade, car la limite d’approbation est entre un conteneur d’application (un processus de privilège 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 dans le pilote du noyau. L’administrateur est déjà un privilège assez élevé sur le système, de sorte que la surface d’attaque entre l’administrateur et le noyau est moins intéressante pour les attaquants, mais reste une frontière de confiance notable.

Le chemin d’accès (3) est un exemple de chemin d’exécution de code qui franchit plusieurs frontières de confiance et qui pourraient passer inaperçues si un modèle de menace n’est pas créé. Dans cet exemple, il existe une limite de confiance entre le pilote 1 et le pilote 3, parce que 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 ne pas être fiables, dans la mesure où le pilote précédent n’était qu’un simple pass-through (par exemple, le pilote 1 a reçu des données de l’application 1, le pilote 1 n’a procédé à aucune validation des 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 relatives au modèle de 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 assouplir les listes de contrôle d'accès par défaut strictes 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 les IOCTL qui autorisent FILE_ANY_ACCESS à moins que ce type d’accès ne puisse ê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 en savoir plus, consultez Modélisation des menaces pour les pilotes.
  • Consultez liste de contrôle de sécurité des pilotes pour obtenir des recommandations supplémentaires sur la sécurité des pilotes.

Voir aussi

sécurisation des objets de périphérique

liste de contrôle de sécurité du pilote