1. Introduction▲
La connexion d'un utilisateur est un processus complexe dans le monde Windows. Mais au bout du compte et quelle que soit la méthode d'authentification utilisée (local, domaine, réseau, Terminal Service…), l'utilisateur se voit attribué un jeton d'authentification (appelé aussi token dans la littérature anglaise).
Ce jeton contient plusieurs informations :
- l'identifiant de sécurité de l'utilisateur appelé aussi Secury IDentifier ou SID dans la littérature anglaise ;
- le ou les SID des groupes auxquels appartient cet utilisateur ;
- un SID de session (logon SID) qui sert à identifier la session de l'utilisateur ;
- la liste des privilèges de l'utilisateur ;
- l'identification de la source du jeton. Cette identification permet de reconnaitre le type de session : Session Manager, LAN Manager, RPC Server…
- une variable permettant de savoir s'il s'agit d'un jeton principal (primary Token) ou d'un jeton modifié (Impersonation Token) ;
- et beaucoup d'autres choses encore.
Cet article s'intéresse exclusivement aux privilèges Windows donnés par le système et inscrits dans ce jeton d'authentification.
Cet article est plus particulièrement destiné aux administrateurs de systèmes Windows, aux développeurs d'applications orientées « système » et aussi aux personnes curieuses de connaitre un peu mieux le fonctionnement interne de Windows.
2. Les privilèges▲
2-1. Droit ou privilège ?▲
Il est facile de faire la confusion entre ces deux mots, une clarification est donc nécessaire.
Un droit est appliqué à un objet d'une arborescence (fichier, répertoire, clé de registre…) pour un ou plusieurs utilisateurs ou un ou plusieurs groupes d'utilisateurs. Ainsi on parlera du droit de lecture, d'écriture, d'exécution, de parcours et d'autres droits encore liés à la gestion d'une arborescence.
Un privilège s'applique à un ou plusieurs utilisateurs ou à un ou plusieurs groupes d'utilisateurs et il concerne une opération spécifique possible sur le noyau ou le système. Ainsi, on parlera du privilège d'arrêter le système, du privilège de modifier l'heure du système…
2-2. Attribution et portée des privilèges▲
Au niveau du système, il existe une base de données, la base LSA (Local Security Authority), qui contient, entre autres, la liste des privilèges attribués à chaque utilisateur ou groupe d'utilisateurs.
Les privilèges s'appliquent donc au niveau local et ne sont pas transmis au travers du réseau vers une autre machine. Il est ainsi tout à fait possible et normal d'avoir certains privilèges sur une machine et d'autres privilèges sur d'autres machines avec le même nom d'utilisateur.
La plupart des privilèges, même s'ils sont attribués à un utilisateur, sont désactivés par défaut. C'est au programme qui souhaite les utiliser de les activer si nécessaire.
Quand le système tente d'effectuer une opération qui nécessite certains privilèges, il vérifie que l'utilisateur possède bien ce privilège et si oui, il vérifie que ce privilège est bien activé. Si l'un de ces deux tests échoue, le système refuse d'effectuer l'opération demandée.
Au niveau du noyau, chaque privilège est associé à un LUID (Local Unique IDentifier). Cet identifiant, comme son nom l'indique, est local et unique pour chacune des machines (il semblerait même que cet identifiant de privilège soit différent d'une connexion à l'autre). C'est aussi pour cette raison qu'un privilège ne peut être transmis à une autre machine, car au niveau du noyau, la seule chose qui est associée au jeton d'identification d'un utilisateur, c'est une liste de LUID de privilèges et pas une liste de noms de privilèges.
2-3. La liste des privilèges▲
Sous Windows, la liste des privilèges disponibles se trouve dans le tableau ci-dessous. Ce tableau a été établi à l'aide de MSDN « Account Rights Constants » et « Privilege Constants » et aussi l'aide en ligne disponible sur un système Windows Seven Professionnal.
Ce tableau contient quatre colonnes :
- la colonne 1 « Nom/Constante » est l'identifiant du privilège (tel que défini dans le fichier winnt.h) et la chaine de caractères identifiant le privilège. Un développeur ne doit utiliser que l'identifiant du privilège, pas la chaine de caractères ;
- la colonne 2 « Description » est une description courte du privilège ;
- la colonne 3 « Explication » contient des informations plus détaillées sur ce privilège ;
- la colonne 4 « Valeur par défaut » enfin donne les valeurs par défaut, c'est-à-dire les groupes à qui sont normalement attribués ces privilèges. Certaines valeurs peuvent être différentes suivant que la machine est une station de travail (identifié par WKS), un serveur (identifié par SRV) ou un contrôleur de domaine (identifié par DC).
Nom/Constante |
Description |
Explication |
Valeur par défaut |
---|---|---|---|
SE_ASSIGNPRIMARYTOKEN_NAME |
Remplacer un jeton de niveau processus |
Ce paramètre de sécurité détermine quels comptes d'utilisateur peuvent appeler l'interface de programmation d'application (API) CreateProcessAsUser() afin qu'un service puisse en démarrer un autre. Le Planificateur de tâches est un exemple de processus utilisant ce droit d'utilisateur. Pour plus d'informations sur le Planificateur de tâches, voir Présentation du Planificateur de tâches. |
Service réseau, Service local. |
SE_AUDIT_NAME |
Générer des audits de sécurité |
Ce paramètre de sécurité détermine quels comptes peuvent être utilisés par un processus pour ajouter des entrées au journal de sécurité. Le journal de sécurité est utilisé pour suivre les accès non autorisés au système. Une utilisation incorrecte de ce droit d'utilisateur peut entraîner la génération de nombreux événements d'audit, masquant ainsi potentiellement les signes d'une attaque ou causant un déni de service si le paramètre de stratégie de sécurité « Audit : arrêter immédiatement le système s'il n'est pas possible de se connecter aux audits de sécurité » est activé. Pour plus d'informations, voir Audit : arrêter immédiatement le système s'il n'est pas possible de se connecter aux audits de sécurité. |
Service local, Service réseau. |
SE_BACKUP_NAME |
Sauvegarder les fichiers et les répertoires |
Ce droit d'utilisateur détermine quels utilisateurs peuvent contourner les autorisations de fichiers et de répertoires, de Registre, et autres autorisations d'objet persistantes à des fins de sauvegarde du système. |
WKS et SRV : Administrateurs, Opérateurs de sauvegarde. |
SE_CHANGE_NOTIFY_NAME |
Contourner la vérification de parcours |
Ce droit d'utilisateur détermine quels utilisateurs peuvent parcourir les arborescences de répertoires même si l'utilisateur ne dispose pas d'autorisations sur le répertoire parcouru. Ce privilège ne permet pas à l'utilisateur d'afficher le contenu d'un répertoire, mais seulement de parcourir des répertoires. Il signifie aussi que l'on peut lire un fichier auquel on a accès même s'il est dans un répertoire auquel on n'a pas accès. |
WKS et SRV : Administrateurs, Opérateurs de sauvegarde, Utilisateurs, Tout le monde, Service local, Service réseau. |
SE_CREATE_GLOBAL_NAME |
Créer des objets globaux |
Ce paramètre de sécurité détermine si les utilisateurs peuvent créer des objets globaux disponibles dans toutes les sessions. Les utilisateurs peuvent toujours créer des objets spécifiques à leurs propres sessions s'ils n'ont pas ce droit d'utilisateur. Les utilisateurs qui peuvent créer des objets globaux peuvent affecter les processus qui s'exécutent sous les sessions d'autres utilisateurs, ce qui pourrait entraîner une défaillance d'une application ou une altération des données. |
Administrateurs, Service local, Service réseau, Service. |
SE_CREATE_PAGEFILE_NAME |
Créer un fichier d'échange |
Ce droit d'utilisateur détermine quels utilisateurs et groupes peuvent appeler une interface de programmation d'application (API) interne pour créer et redimensionner un fichier d'échange. Ce droit d'utilisateur est utilisé en interne par le système d'exploitation et n'a pas besoin d'être affecté à des utilisateurs. |
Administrateurs. |
SE_CREATE_PERMANENT_NAME |
Créer des objets partagés permanents |
Ce droit d'utilisateur détermine quels comptes peuvent être utilisés par des processus pour créer un objet répertoire à l'aide du Gestionnaire d'objets. |
Aucune. |
SE_CREATE_SYMBOLIC_LINK_NAME |
Créer des liens symboliques |
Ce privilège détermine si l'utilisateur peut créer un lien symbolique à partir de l'ordinateur où il a ouvert une session. |
Administrateur. |
SE_CREATE_TOKEN_NAME |
Créer un objet-jeton |
Ce paramètre de sécurité détermine quels comptes peuvent être utilisés par des processus pour créer un jeton pouvant servir à accéder à des ressources locales lorsque le processus utilise une interface de programmation d'application (API) interne pour créer un jeton d'accès. |
Aucune. |
SE_DEBUG_NAME |
Déboguer les programmes |
Ce droit d'utilisateur détermine quels utilisateurs peuvent attacher un débogueur à un processus ou au noyau. Il n'est pas nécessaire d'affecter ce droit d'utilisateur aux développeurs qui déboguent leurs propres applications. Les développeurs qui déboguent de nouveaux composants système auront besoin de ce droit d'utilisateur dans le cadre de cette activité. Ce droit d'utilisateur donne un accès complet à des composants sensibles et critiques du système d'exploitation. |
Administrateurs. |
SE_ENABLE_DELEGATION_NAME |
Permettre à l'ordinateur et aux comptes d'utilisateurs d'être approuvés pour la délégation |
Ce paramètre de sécurité détermine quels utilisateurs peuvent définir le paramètre Approuvé pour la délégation sur un utilisateur ou un objet ordinateur. |
DC : Administrateurs. |
SE_IMPERSONATE_NAME |
Emprunter l'identité d'un client après l'authentification |
L'affectation de ce privilège à un utilisateur permet aux programmes exécutés au nom de cet utilisateur d'emprunter l'identité d'un client. Imposer ce droit d'utilisateur pour ce type d'emprunt d'identité empêche un utilisateur non autorisé de convaincre un client de se connecter (par exemple, par un appel de procédure distante (RPC) ou par canaux nommés) à un service qu'il a créé, puis d'emprunter l'identité de ce client, ce qui peut élever les autorisations de l'utilisateur non autorisé à des niveaux administratifs ou système. |
Administrateurs, Service local, Service réseau, Service. |
SE_INC_BASE_PRIORITY_NAME |
Augmenter la priorité de planification |
Ce paramètre de sécurité détermine quels comptes peuvent utiliser un processus avec un accès Propriété d'écriture à un autre processus pour augmenter la priorité d'exécution affectée à l'autre processus. Un utilisateur doté de ce privilège peut changer la priorité de planification d'un processus par le biais de l'interface utilisateur du Gestionnaire des tâches. |
Administrateurs. |
SE_INCREASE_QUOTA_NAME |
Ajuster les quotas de mémoire pour un processus |
Ce privilège détermine qui peut changer la quantité de mémoire maximale pouvant être consommée par un processus. |
Administrateurs, Service local, Service réseau. |
SE_INC_WORKING_SET_NAME |
Augmenter une plage de travail de processus |
Ce privilège détermine quels comptes d'utilisateurs peuvent augmenter ou diminuer la taille d'une plage de travail d'un processus. |
Utilisateurs. |
SE_LOAD_DRIVER_NAME |
Charger et décharger les pilotes de périphériques |
Ce droit d'utilisateur détermine quels utilisateurs peuvent charger et décharger des pilotes de périphériques ou un autre code en mode noyau. Ce droit d'utilisateur ne s'applique pas aux pilotes de périphériques Plug-and-Play. Il est préférable de ne pas affecter ce privilège à d'autres utilisateurs. |
WKS et SRV : Administrateurs. |
SE_LOCK_MEMORY_NAME |
Verrouiller les pages en mémoire |
Ce paramètre de sécurité détermine quels comptes peuvent utiliser un processus pour conserver les données en mémoire physique, ce qui empêche le système de paginer les données en mémoire virtuelle sur disque. L'exercice de ce privilège peut avoir une incidence significative sur les performances du système en diminuant la quantité de mémoire vive (RAM) disponible. |
Aucune. |
SE_MACHINE_ACCOUNT_NAME |
Ajouter des stations de travail au domaine |
Ce paramètre de sécurité détermine quels groupes ou utilisateurs peuvent ajouter des stations de travail à un domaine. |
Utilisateurs du domaine. |
SE_MANAGE_VOLUME_NAME |
Effectuer les tâches de maintenance de volume |
Ce paramètre de sécurité détermine quels utilisateurs et quels groupes peuvent exécuter des tâches de maintenance sur un volume, telles qu'une défragmentation à distance. |
Administrateurs. |
SE_PROF_SINGLE_PROCESS_NAME |
Processus unique du profil |
Ce paramètre de sécurité détermine quels utilisateurs peuvent utiliser les outils de surveillance des performances pour surveiller les performances de processus non-système. |
Administrateurs, Utilisateurs avec pouvoir. |
SE_RELABEL_NAME |
Modifier un nom d'objet |
Ce privilège détermine les comptes d'utilisateurs qui peuvent modifier le nom d'intégrité d'objets, tels que des fichiers, des clés de Registre ou des processus appartenant à d'autres utilisateurs. Les processus s'exécutant sous un compte d'utilisateur peuvent modifier le nom d'un objet appartenant à cet utilisateur vers un niveau inférieur sans ce privilège. |
Aucune. |
SE_REMOTE_SHUTDOWN_NAME |
Forcer l'arrêt à partir d'un système distant |
Ce paramètre de sécurité détermine quels utilisateurs sont autorisés à arrêter un ordinateur à partir d'un emplacement distant sur le réseau. Une utilisation incorrecte de ce droit d'utilisateur peut entraîner un déni de service. |
WKS et SRV : Administrateurs. |
SE_RESTORE_NAME |
Restaurer les fichiers et les répertoires |
Ce paramètre de sécurité détermine quels utilisateurs peuvent contourner les autorisations de fichiers, de répertoires, de Registre, et autres autorisations d'objets persistantes lors de la restauration de fichiers et de répertoires sauvegardés, et détermine quels utilisateurs peuvent définir une entité de sécurité comme propriétaire d'un objet. |
WKS et SRV : Administrateurs, Opérateurs de sauvegarde. |
SE_SECURITY_NAME |
Gérer le journal d'audit et de sécurité |
Ce paramètre de sécurité détermine quels utilisateurs peuvent spécifier des options d'audit d'accès aux objets pour des ressources individuelles, par exemple des fichiers, des objets Active Directory et des clés de Registre. |
Administrateurs. |
SE_SHUTDOWN_NAME |
Arrêter le système |
Ce paramètre de sécurité détermine quels utilisateurs connectés localement à l'ordinateur peuvent arrêter le système d'exploitation à l'aide de la commande Arrêter. Une utilisation incorrecte de ce droit d'utilisateur peut entraîner un déni de service. |
WKS et SRV : Administrateurs, Opérateurs de sauvegarde. |
SE_SYNC_AGENT_NAME |
Synchroniser les données du service d'annuaire |
Ce paramètre de sécurité détermine quels utilisateurs et quels groupes sont autorisés à synchroniser toutes les données du service d'annuaire. Cette opération est également qualifiée de synchronisation Active Directory. |
Aucune. |
SE_SYSTEM_ENVIRONMENT_NAME |
Modifier les valeurs de l'environnement du microprogramme |
Ce paramètre de sécurité détermine qui peut modifier les valeurs d'environnement de microprogramme. Les variables d'environnement de microprogramme sont des paramètres enregistrés dans la RAM non volatile des ordinateurs non-x86. L'effet de ce paramètre dépend du processeur. |
Administrateurs. |
SE_SYSTEM_PROFILE_NAME |
Performance système du profil |
Ce paramètre de sécurité détermine quels utilisateurs peuvent utiliser des outils de surveillance des performances pour surveiller les performances de processus système. |
Administrateurs. |
SE_SYSTEMTIME_NAME |
Modifier l'heure système |
Ce droit d'utilisateur détermine quels utilisateurs et groupes peuvent changer la date et l'heure sur l'horloge interne de l'ordinateur. Les utilisateurs qui bénéficient de ce droit d'utilisateur peuvent modifier le contenu des journaux d'événements. Si l'heure système est changée, les événements enregistrés reflètent cette nouvelle heure, et non pas l'heure réelle à laquelle les événements se sont produits. |
WKS et SRV : Administrateurs, Service local. |
SE_TAKE_OWNERSHIP_NAME |
Prendre possession de fichiers ou d'autres objets |
Ce paramètre de sécurité détermine quels utilisateurs peuvent prendre possession des objets du système nécessitant une sécurité, notamment les objets Active Directory, les fichiers et les dossiers, les imprimantes, les clés de Registre, les processus et les threads. |
Administrateurs. |
SE_TCB_NAME |
Agir en tant que partie du système d'exploitation |
Ce droit d'utilisateur permet à un processus d'emprunter l'identité d'un utilisateur sans authentification. Le processus peut par conséquent accéder aux mêmes ressources locales que cet utilisateur. |
Aucune. |
SE_TIME_ZONE_NAME |
Changer le fuseau horaire |
Ce droit utilisateur détermine quels utilisateurs et quels groupes peuvent changer le fuseau horaire utilisé par l'ordinateur pour afficher l'heure locale, qui est l'heure système plus le décalage du fuseau horaire. L'heure système est absolue et n'est pas affectée par un changement de fuseau horaire. |
Administrateurs, Utilisateurs. |
SE_TRUSTED_CREDMAN_ACCESS_NAME |
Accéder au gestionnaire d'informations d'identification en tant qu'appelant approuvé |
Ce paramètre est utilisé par le gestionnaire d'informations d'identification pendant la sauvegarde/restauration. Aucun compte ne doit avoir ce privilège, car il est uniquement affecté à Winlogon. Les informations d'identification enregistrées par les utilisateurs risquent d'être compromises si ce privilège est attribué à d'autres entités. |
Aucune. |
SE_UNDOCK_NAME |
Retirer l'ordinateur de la station d'accueil |
Ce paramètre de sécurité détermine si un utilisateur peut retirer un ordinateur portable de sa station d'accueil sans ouvrir de session. |
Administrateurs, Utilisateurs avec pouvoir, Utilisateurs. |
SE_UNSOLICITED_INPUT_NAME |
Pas d'information. |
Pas d'information. |
Pas d'information. |
SE_BATCH_LOGON_NAME |
Ouvrir une session en tant que tâche |
Ce paramètre de sécurité permet à un utilisateur d'ouvrir une session au moyen d'une fonction de file d'attente de tâches. Il n'existe que pour assurer la compatibilité avec les versions antérieures de Windows. |
Administrateurs, Opérateurs de sauvegarde. |
SE_DENY_BATCH_LOGON_NAME |
Interdire l'ouverture de session en tant que tâche |
Ce paramètre de stratégie détermine quels comptes ne peuvent pas ouvrir une session en tant que tâche. Ce paramètre de stratégie prévaut sur le paramètre de stratégie Ouvrir une session en tant que tâche si un compte d'utilisateur est soumis aux deux stratégies. |
Aucune. |
SE_DENY_INTERACTIVE_LOGON_NAME |
Interdire l'ouverture d'une session locale |
Ce paramètre de sécurité détermine quels utilisateurs ne peuvent pas se connecter sur l'ordinateur. Ce paramètre de stratégie prévaut sur le paramètre de stratégie Permettre l'ouverture d'une session locale si un compte est soumis aux deux stratégies. |
Aucune. |
SE_DENY_NETWORK_LOGON_NAME |
Interdire l'accès à cet ordinateur à partir du réseau |
Ce paramètre de sécurité détermine quels utilisateurs ne peuvent pas accéder à un ordinateur sur le réseau. Ce paramètre de stratégie prévaut sur le paramètre de stratégie Accéder à cet ordinateur à partir du réseau si un compte d'utilisateur est soumis aux deux stratégies. |
Invité. |
SE_DENY_REMOTE_INTERACTIVE_LOGON_NAME |
Interdire l'ouverture de session par les services Bureau à distance |
Ce paramètre de stratégie détermine quels utilisateurs et quels groupes ne peuvent pas ouvrir une session en tant que client des services Bureau à distance. |
Aucune. |
SE_DENY_SERVICE_LOGON_NAME |
Interdire l'ouverture de session en tant que service |
Ce paramètre de stratégie détermine quels comptes de service ne peuvent pas inscrire un processus en tant que service. Ce paramètre de stratégie prévaut sur le paramètre de stratégie Ouvrir une session en tant que service si un compte est soumis aux deux stratégies. |
Aucune. |
SE_INTERACTIVE_LOGON_NAME |
Permettre l'ouverture d'une session locale |
Détermine quels utilisateurs peuvent se connecter à l'ordinateur. |
WKS et SRV Administrateurs, Opérateurs de sauvegarde, Utilisateurs avec pouvoir, Utilisateurs et Invité. |
SE_NETWORK_LOGON_NAME |
Accéder à cet ordinateur à partir du réseau |
Ce droit d'utilisateur détermine quels utilisateurs et groupes sont autorisés à se connecter à l'ordinateur sur le réseau. Les services Bureau à distance ne sont pas affectés par ce droit d'utilisateur. |
WKS et SRV : Administrateurs, Opérateurs de sauvegarde, Utilisateurs, Tout le monde. |
SE_REMOTE_INTERACTIVE_LOGON_NAME |
Autoriser l'ouverture de session par les services Bureau à distance |
Ce paramètre de sécurité détermine quels utilisateurs ou groupes sont autorisés à se connecter comme client des services Bureau à distance. |
WKS et SRV : Administrateurs, Utilisateurs du Bureau à distance. |
SE_SERVICE_LOGON_NAME |
Ouvrir une session en tant que service |
Ce paramètre de sécurité permet à une entité de sécurité d'ouvrir une session en tant que service. Les services peuvent être configurés pour s'exécuter sous les comptes Système local, Service local ou Service réseau, qui possèdent un droit intégré d'ouvrir une session en tant que service. Il faut affecter ce droit à tout service qui s'exécute sous un compte d'utilisateur distinct. |
Aucune. |
Vous avez des précisions à apporter au sujet de ces privilèges, un lien ou une traduction concernant leurs descriptions, n'hésitez pas à les signaler dans la discussion dédiée (10 commentaires), cet article sera mis à jour.
3. La gestion des privilèges▲
3-1. Gestion des privilèges graphique▲
La gestion des privilèges se fait à l'aide d'un plug-in lancé par une MMC (Microsoft Management Console) se trouvant dans le panneau de configuration, dans les outils d'administration et qui s'appelle « Stratégie de sécurité locale » (du moins sur un système Windows Seven Professionnel français).
Ce plug-in peut aussi être lancé directement par la ligne de commande suivante : « %windir%\system32\secpol.msc /s »
Il semble que ce plug-in n'existe pas par défaut sur les versions familiales de Microsoft Windows.
La gestion des privilèges se trouve dans la section « Stratégies locales » / « Attribution des droits d'utilisateur » de la partie gauche de l'arbre.
Il est possible de modifier l'affectation des privilèges pour un utilisateur ou un groupe d'utilisateurs. Pour cela, il suffit de sélectionner un des privilèges affichés et ensuite, de faire un clic droit et de sélectionner l'option « Propriétés ».
3-2. Gestion des privilèges à la console▲
La gestion des privilèges peut aussi se faire à la console. Il suffit pour cela d'installer l'outil NtRights.exe qui fait partie du « Windows Server 2003 Resource Kit Tools ». Ce « Resource Kit Tools » peut être téléchargé ici.
4. Un petit programme de démonstration▲
4-1. But du programme▲
Le programme présenté dans cet article est relativement simple, il se propose :
- d'inventorier les privilèges détenus par l'utilisateur courant ;
- de tenter de prendre un privilège non détenu par le jeton d'authentification de l'utilisateur (le privilège SE_TCB_NAME) ;
- d'activer un des privilèges détenus par le jeton d'authentification de l'utilisateur (le privilège SE_SHUTDOWN_NAME) ;
- d'inventorier à nouveau les privilèges détenus par l'utilisateur courant.
4-2. Environnement de développement▲
Le programme de test a été développé avec l'environnement suivant :
- Microsoft Windows Seven Profesionnel avec tous les correctifs de sécurité appliqués au jour de la rédaction de l'article (15 septembre 2009) ;
- Visual Studio 2005 ;
- programme en mode console compilé en Unicode ;
- la gestion des erreurs est ultrasimpliste ;
- le programme est écrit volontairement en C afin que d'autres langages puissent utiliser les idées développées dans ce code.
Pour les plus impatients, le binaire peut être téléchargé ici et le projet complet (au format Visual Studio 2005) peut être téléchargé ici.
Si une erreur se produit lors du lancement du programme Privileges.exe, il faut installer les redistribuables VS 2005. Ce setup peut être téléchargé ici.
4-3. Les fonctions utilisées▲
Ce paragraphe liste les fonctions spécifiques à la gestion des privilèges Microsoft et utilisées par le programme de démonstration :
- la fonction OpenProcessToken() permet d'obtenir un jeton sur un processus quelconque. Ce jeton contient, entre autres, toutes les informations concernant les privilèges détenus et leurs états ;
- la fonction GetTokenInformation() permet de récupérer un ensemble d'information concernant le jeton passé en paramètre. Parmi ces informations, on peut récupérer la liste des privilèges ainsi que leur état actif ou non ;
- la fonction LookupPrivilegeValue() permet de récupérer le Local Unique Identifier (LUID) associé à un privilège dont on spécifie le nom ;
- la fonction LookupPrivilegeName() permet de récupérer le nom d'un privilège associé à un Local Unique Identifier (LUID) ;
- la fonction LookupPrivilegeDisplayName() permet de récupérer le nom affiché pour un privilège donné. C'est ce nom qui est utilisé dans la console de gestion des privilèges secpol.msc ;
- la fonction AdjustTokenPrivileges() permet de modifier l'état (activé ou désactivé) des privilèges possédés par le jeton passé en paramètre ;
- la fonction EnumeratePrivilegeName() : cette fonction n'existe pas, Microsoft n'a rien prévu dans son API pour énumérer tous les privilèges connus et disponibles.
4-4. Le résultat généré▲
Le résultat de l'exécution de la version Release du programme de démonstration sur un poste Windows Seven professionnel produit le résultat suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
D:\Raymond\Developpement\Programmes\Privileges\Release>Privileges.exe
Affichage des privilèges d'un jeton
"SeShutdownPrivilege" (Arrêter le système)
Privilège désactivé
"SeChangeNotifyPrivilege" (Contourner la vérification de parcours)
Privilège activé par défaut
Privilège activé
"SeUndockPrivilege" (Retirer l'ordinateur de la station d'accueil)
Privilège désactivé
"SeIncreaseWorkingSetPrivilege" (Augmenter une plage de travail de processus)
Privilège désactivé
"SeTimeZonePrivilege" (Changer le fuseau horaire)
Privilège désactivé
Tentative de prise du privilège SeTcbPrivilege
Erreur AdjustTokenPrivileges() : L'appelant ne bénéficie pas de tous les privilèges ou groupes référencés.
Tentative de prise du privilège SeShutdownPrivilege
==> OK
Affichage des privilèges d'un jeton
"SeShutdownPrivilege" (Arrêter le système)
Privilège activé
"SeChangeNotifyPrivilege" (Contourner la vérification de parcours)
Privilège activé par défaut
Privilège activé
"SeUndockPrivilege" (Retirer l'ordinateur de la station d'accueil)
Privilège désactivé
"SeIncreaseWorkingSetPrivilege" (Augmenter une plage de travail de processus)
Privilège désactivé
"SeTimeZonePrivilege" (Changer le fuseau horaire)
Privilège désactivé
D:\Raymond\Developpement\Programmes\Privileges\Release>
Le même programme lancé dans un shell avec les privilèges d'administrateur donne beaucoup plus de privilèges (et c'est normal) :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
D:\Raymond\Developpement\Programmes\Privileges\Release>Privileges.exe
Affichage des privilèges d'un jeton
"SeIncreaseQuotaPrivilege" (Ajuster les quotas de mémoire pour un processus)
Privilège désactivé
"SeSecurityPrivilege" (Gérer le journal d'audit et de sécurité)
Privilège désactivé
"SeTakeOwnershipPrivilege" (Prendre possession de fichiers ou d'autres objets)
Privilège désactivé
"SeLoadDriverPrivilege" (Charger et décharger les pilotes de périphériques)
Privilège désactivé
"SeSystemProfilePrivilege" (Performance système du profil)
Privilège désactivé
"SeSystemtimePrivilege" (Modifier l'heure système)
Privilège désactivé
"SeProfileSingleProcessPrivilege" (Processus unique du profil)
Privilège désactivé
"SeIncreaseBasePriorityPrivilege" (Augmenter la priorité de planification)
Privilège désactivé
"SeCreatePagefilePrivilege" (Créer un fichier d'échange)
Privilège désactivé
"SeBackupPrivilege" (Sauvegarder les fichiers et les répertoires)
Privilège désactivé
"SeRestorePrivilege" (Restaurer les fichiers et les répertoires)
Privilège désactivé
"SeShutdownPrivilege" (Arrêter le système)
Privilège désactivé
"SeDebugPrivilege" (Déboguer les programmes)
Privilège désactivé
"SeSystemEnvironmentPrivilege" (Modifier les valeurs de l'environnement du microprogramme)
Privilège désactivé
"SeChangeNotifyPrivilege" (Contourner la vérification de parcours)
Privilège activé par défaut
Privilège activé
"SeRemoteShutdownPrivilege" (Forcer l'arrêt à partir d'un système distant)
Privilège désactivé
"SeUndockPrivilege" (Retirer l'ordinateur de la station d'accueil)
Privilège désactivé
"SeManageVolumePrivilege" (Effectuer les tâches de maintenance de volume)
Privilège désactivé
"SeImpersonatePrivilege" (Emprunter l'identité d'un client après l'authentification)
Privilège activé par défaut
Privilège activé
"SeCreateGlobalPrivilege" (Créer des objets globaux)
Privilège activé par défaut
Privilège activé
"SeIncreaseWorkingSetPrivilege" (Augmenter une plage de travail de processus)
Privilège désactivé
"SeTimeZonePrivilege" (Changer le fuseau horaire)
Privilège désactivé
"SeCreateSymbolicLinkPrivilege" (Créer des liens symboliques)
Privilège désactivé
Tentative de prise du privilège SeTcbPrivilege
Erreur AdjustTokenPrivileges() : L'appelant ne bénéficie pas de tous les privilèges ou groupes référencés.
Tentative de prise du privilège SeShutdownPrivilege
==> OK
Affichage des privilèges d'un jeton
"SeIncreaseQuotaPrivilege" (Ajuster les quotas de mémoire pour un processus)
Privilège désactivé
"SeSecurityPrivilege" (Gérer le journal d'audit et de sécurité)
Privilège désactivé
"SeTakeOwnershipPrivilege" (Prendre possession de fichiers ou d'autres objets)
Privilège désactivé
"SeLoadDriverPrivilege" (Charger et décharger les pilotes de périphériques)
Privilège désactivé
"SeSystemProfilePrivilege" (Performance système du profil)
Privilège désactivé
"SeSystemtimePrivilege" (Modifier l'heure système)
Privilège désactivé
"SeProfileSingleProcessPrivilege" (Processus unique du profil)
Privilège désactivé
"SeIncreaseBasePriorityPrivilege" (Augmenter la priorité de planification)
Privilège désactivé
"SeCreatePagefilePrivilege" (Créer un fichier d'échange)
Privilège désactivé
"SeBackupPrivilege" (Sauvegarder les fichiers et les répertoires)
Privilège désactivé
"SeRestorePrivilege" (Restaurer les fichiers et les répertoires)
Privilège désactivé
"SeShutdownPrivilege" (Arrêter le système)
Privilège activé
"SeDebugPrivilege" (Déboguer les programmes)
Privilège désactivé
"SeSystemEnvironmentPrivilege" (Modifier les valeurs de l'environnement du microprogramme)
Privilège désactivé
"SeChangeNotifyPrivilege" (Contourner la vérification de parcours)
Privilège activé par défaut
Privilège activé
"SeRemoteShutdownPrivilege" (Forcer l'arrêt à partir d'un système distant)
Privilège désactivé
"SeUndockPrivilege" (Retirer l'ordinateur de la station d'accueil)
Privilège désactivé
"SeManageVolumePrivilege" (Effectuer les tâches de maintenance de volume)
Privilège désactivé
"SeImpersonatePrivilege" (Emprunter l'identité d'un client après l'authentification)
Privilège activé par défaut
Privilège activé
"SeCreateGlobalPrivilege" (Créer des objets globaux)
Privilège activé par défaut
Privilège activé
"SeIncreaseWorkingSetPrivilege" (Augmenter une plage de travail de processus)
Privilège désactivé
"SeTimeZonePrivilege" (Changer le fuseau horaire)
Privilège désactivé
"SeCreateSymbolicLinkPrivilege" (Créer des liens symboliques)
Privilège désactivé
D:\Raymond\Developpement\Programmes\Privileges\Release>
Certains privilèges ne possèdent pas de correspondance en utilisant la fonction LookupPrivilegeDisplayName(). La raison de ceci est inconnue et si vous avez des précisions à apporter sur ce point, n'hésitez pas à les signaler dans la discussion dédiée (10 commentaires), cet article sera mis à jour.
4-5. Le code du programme▲
Le code du programme de démonstration est le suivant :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif
#include <tchar.h>
#include <locale.h>
#include <stdio.h>
#include <windows.h>
#include <ntsecapi.h>
#define HEAPALLOC(size) HeapAlloc(GetProcessHeap(), 0, (size))
#define HEAPFREE(memory) HeapFree(GetProcessHeap(), 0, (memory)), (memory) = NULL
static
void
DisplayError
(
LPCTSTR message)
{
LPTSTR buffer =
NULL
;
if
(
message ==
NULL
){
message =
_T
(
"
Error
"
);}
if
(
FormatMessage
(
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL
, GetLastError
(
), 0
, (
LPTSTR)&
buffer, 0
, NULL
) ==
0
)
{
if
(
GetLastError
(
) ==
ERROR_NOT_ENOUGH_MEMORY)
{
_ftprintf
(
stderr, _T
(
"
%s : not enough memory
\n
"
), message);
}
else
{
_ftprintf
(
stderr, _T
(
"
FormatMessage() failed : %lu
\n
"
), GetLastError
(
));
}
}
else
{
_ftprintf
(
stderr, _T
(
"
%s : %s
"
), message, buffer);
LocalFree
(
buffer), buffer =
NULL
;
}
}
static
LPVOID GetAllocatedTokenInformation
(
HANDLE token, TOKEN_INFORMATION_CLASS tokenInformationClass)
{
LPVOID tokenInformation =
NULL
;
DWORD length =
0
;
GetTokenInformation
(
token, tokenInformationClass, NULL
, 0
, &
length); /* it must fail, we just want the good size */
if
(
GetLastError
(
) ==
ERROR_INSUFFICIENT_BUFFER)
{
SetLastError
(
ERROR_SUCCESS);
tokenInformation =
HEAPALLOC
(
length);
if
(
tokenInformation !=
NULL
&&
GetTokenInformation
(
token, TokenPrivileges, tokenInformation, length, &
length) ==
FALSE)
{
DWORD lastError =
GetLastError
(
);
HEAPFREE
(
tokenInformation);
SetLastError
(
lastError);
}
}
return
tokenInformation;
}
static
LPTSTR LookupAllocatedPrivilegeName
(
LPCTSTR systemName, PLUID luid)
{
LPTSTR privilegeName =
NULL
;
DWORD length =
0
;
LookupPrivilegeName
(
systemName, luid, NULL
, &
length); /* it must fail, we just want the good size */
if
(
GetLastError
(
) ==
ERROR_INSUFFICIENT_BUFFER)
{
privilegeName =
(
LPTSTR)HEAPALLOC
((
length +
1
) *
sizeof
*
privilegeName);
if
(
privilegeName !=
NULL
&&
LookupPrivilegeName
(
systemName, luid, privilegeName, &
length) ==
FALSE)
{
DWORD lastError =
GetLastError
(
);
HEAPFREE
(
privilegeName);
SetLastError
(
lastError);
}
}
return
privilegeName;
}
static
LPTSTR LookupAllocatedPrivilegeDisplayName
(
LPCTSTR systemName, LPCTSTR privilegeName, LPDWORD languageId)
{
LPTSTR privilegeDisplayName =
NULL
;
DWORD length =
0
;
LookupPrivilegeDisplayName
(
systemName, privilegeName, NULL
, &
length, languageId); /* it must fail, we just want the good size */
if
(
GetLastError
(
) ==
ERROR_INSUFFICIENT_BUFFER)
{
privilegeDisplayName =
(
LPTSTR)HEAPALLOC
((
length +
1
) *
sizeof
*
privilegeDisplayName);
if
(
privilegeDisplayName !=
NULL
&&
LookupPrivilegeDisplayName
(
systemName, privilegeName, privilegeDisplayName, &
length, languageId) ==
FALSE)
{
DWORD lastError =
GetLastError
(
);
HEAPFREE
(
privilegeDisplayName);
SetLastError
(
lastError);
}
}
return
privilegeDisplayName;
}
static
BOOL DisplayTokenPrivileges
(
HANDLE token)
{
BOOL ret =
TRUE;
PTOKEN_PRIVILEGES tokenPrivileges =
(
PTOKEN_PRIVILEGES)GetAllocatedTokenInformation
(
token, TokenPrivileges);
_putts
(
_T
(
"
Affichage des privilèges d'un jeton
"
));
if
(
tokenPrivileges ==
NULL
) /* obtention des privileges du token */
{
DisplayError
(
_T
(
"
Erreur GetTokenInformation()
"
));
ret =
FALSE;
}
else
{
DWORD i =
0
;
LUID_AND_ATTRIBUTES *
privileges =
tokenPrivileges->
Privileges;
for
(
; i !=
tokenPrivileges->
PrivilegeCount &&
ret ==
TRUE; i++
) /* enumération de tous les LUID de privilèges */
{
LPTSTR privilegeName =
LookupAllocatedPrivilegeName
(
NULL
, &
privileges[i].Luid);
if
(
privilegeName ==
NULL
)
{
DisplayError
(
_T
(
"
Erreur LookupPrivilegeName()
"
));
ret =
FALSE;
}
else
{
DWORD LangId;
LPTSTR privilegeDisplayName =
LookupAllocatedPrivilegeDisplayName
(
NULL
, privilegeName, &
LangId);
if
(
privilegeDisplayName ==
NULL
)
{
DisplayError
(
_T
(
"
Erreur LookupPrivilegeDisplayName()
"
));
ret =
FALSE;
}
else
{
_tprintf
(
_T
(
"
\"
%s
\"
(%s)
\n
"
), privilegeName, privilegeDisplayName);
if
(
privileges[i].Attributes &
SE_PRIVILEGE_ENABLED_BY_DEFAULT)
{
_putts
(
_T
(
"
\t
Privilège activé par défaut
"
));
}
if
(
privileges[i].Attributes &
SE_PRIVILEGE_ENABLED)
{
_putts
(
_T
(
"
\t
Privilège activé
"
));
}
else
{
_putts
(
_T
(
"
\t
Privilège désactivé
"
));
}
/* cet attribut n'est pas utilisé par la fonction GetTokenInformation().
* Par contre, il peut être positionné par la fonction PrivilegeCheck() */
if
(
privileges[i].Attributes &
SE_PRIVILEGE_USED_FOR_ACCESS)
{
_putts
(
_T
(
"
\t
Utilisé pour vérifier l'accès
"
));
}
HEAPFREE
(
privilegeDisplayName);
}
HEAPFREE
(
privilegeName);
}
}
HEAPFREE
(
tokenPrivileges);
}
return
ret;
}
static
BOOL SetTokenPrivilege
(
HANDLE token, LPCTSTR privilege, BOOL enablePrivilege)
{
LUID luid;
BOOL ret =
LookupPrivilegeValue
(
NULL
, privilege, &
luid); /* transforme le nom de privilege en LUID */
if
(
ret ==
FALSE)
{
DisplayError
(
_T
(
"
\t
Erreur LookupPrivilegeValue()
"
));
}
else
{
TOKEN_PRIVILEGES tp =
{
0
}
;
tp.PrivilegeCount =
1
;
tp.Privileges[0
].Luid =
luid;
tp.Privileges[0
].Attributes =
(
enablePrivilege ==
TRUE) ? SE_PRIVILEGE_ENABLED : 0
;
ret =
AdjustTokenPrivileges
(
token, FALSE, &
tp, sizeof
(
tp), NULL
, NULL
);
if
(
ret ==
FALSE ||
GetLastError
(
) ==
ERROR_NOT_ALL_ASSIGNED)
{
DisplayError
(
_T
(
"
\t
Erreur AdjustTokenPrivileges()
"
));
ret =
FALSE;
}
}
return
ret;
}
int
_tmain
(
)
{
HANDLE currentProcessToken;
_tsetlocale
(
LC_ALL, _T
(
""
));
if
(
OpenProcessToken
(
GetCurrentProcess
(
), TOKEN_ALL_ACCESS, &
currentProcessToken) ==
FALSE)
{
DisplayError
(
_T
(
"
Erreur OpenProcessToken()
"
));
}
else
{
if
(
DisplayTokenPrivileges
(
currentProcessToken) !=
FALSE)
{
_putts
(
_T
(
""
));
_tprintf
(
_T
(
"
Tentative de prise du privilège %s
\n
"
), SE_TCB_NAME);
/* modification des privilèges du token
* on va tenter de s'autoriser le privilège SE_TCB_NAME ce qui devrait produire une erreur */
if
(
SetTokenPrivilege
(
currentProcessToken, SE_TCB_NAME, TRUE) ==
TRUE)
{
_putts
(
_T
(
"
\t
==>OK
\n
"
));
}
/* on va s'autoriser le privilège SE_SHUTDOWN_NAME qui est autorisé mais pas activé */
_putts
(
_T
(
""
));
_tprintf
(
_T
(
"
Tentative de prise du privilège %s
\n
"
), SE_SHUTDOWN_NAME);
if
(
SetTokenPrivilege
(
currentProcessToken, SE_SHUTDOWN_NAME, TRUE) ==
TRUE)
{
_putts
(
_T
(
"
\t
==> OK
"
));
}
/* affichage des privilèges du nouveau token
* ici, on devrait voir une modification dans le privilège SE_SHUTDOWN_NAME, maintenant, il doit être activé */
_putts
(
_T
(
""
));
DisplayTokenPrivileges
(
currentProcessToken);
}
CloseHandle
(
currentProcessToken);
}
return
0
;
}
5. Conclusion▲
Ce rapide tour d'horizon concernant les privilèges dans l'environnement Microsoft Windows est maintenant terminé, à vous de jouer et n'oubliez pas qu'en termes de sécurité, l'abus de privilèges est dangereux. N'hésitez pas à commenter cet article ou à apporter des précisions dans la discussion prévue à cet effet : 10 commentaires
Je tiens à remercier Djug et Benj. pour leurs conseils avisés lors de la relecture de cet article.
Je tiens aussi à remercier nicolas.sitbon qui a entièrement repris le code de l'exemple afin de le remettre « d'aplomb ».