Lire un graphe de chemins d'attaque Active Directory
Une liste de droits mal placés ne convainc personne. Un graphe qui montre que n'importe quel utilisateur est à un saut de l'administration du domaine clôt la discussion en trois secondes. Voici comment s'écrit un chemin, comment il est noté, et pourquoi la largeur compte plus que la gravité.
Comment s'écrit un chemin
Tous les chemins suivent la même grammaire, et une fois qu'on sait la lire on les lit tous :
Administrateurs du domaine ← Utilisateurs du domaine [GenericAll]
La cible à gauche est ce qui est pris. Le principal à droite est qui peut le prendre. Le droit entre crochets est comment. Lisez-le à voix haute : « les administrateurs du domaine peuvent être pris par les utilisateurs du domaine, via GenericAll. » Cette phrase, c'est tout le constat.
Les droits qui comptent, en clair
| Droit | Ce qu'il permet réellement |
|---|---|
| GenericAll | Contrôle total. Ajouter un membre, réinitialiser un mot de passe, tout changer. |
| WriteDACL | Réécrire les permissions — donc s'accorder GenericAll, puis s'en servir. |
| WriteOwner | Devenir propriétaire, et un propriétaire peut réécrire les permissions. |
| DCSync | Demander à un contrôleur de domaine les empreintes de mots de passe de tout le domaine, krbtgt compris. |
| ForceChangePassword | Réinitialiser le mot de passe du compte sans connaître l'ancien. |
| GenericWrite / WriteProperty | Écrire un attribut — ce qui suffit, sur le bon attribut, à détourner le compte. |
| MemberOf | Pas un droit mais une appartenance : c'est ainsi qu'un chemin s'étend d'un groupe aux personnes qui sont réellement dedans. |
Les trois premiers sont équivalents en pratique. WriteDACL n'est pas « moins grave » que GenericAll — il en est à une commande.
Gravité × largeur
Deux chemins portant le même droit ne sont pas le même problème, et c'est là que la plupart des revues manuelles se trompent. Un chemin est noté sur deux axes :
- La gravité — 2 pour un droit de prise de contrôle (GenericAll, WriteDACL, WriteOwner, Owner, DCSync), 1 pour un droit indirect, 0 pour un droit non typé.
- La largeur — 3 quand le principal est un groupe auquel tout le monde appartient (Tout le monde, Utilisateurs authentifiés, Utilisateurs du domaine, Ordinateurs du domaine), 2 pour un groupe intégré, 1 pour un compte nominatif.
Le score est gravité × largeur. Autrement dit, un GenericAll détenu par les Utilisateurs du domaine vaut 6, alors que le même GenericAll détenu par un administrateur nominatif vaut 2. Même droit, trois fois l'exposition — parce que dans le premier cas l'attaquant n'a besoin de compromettre personne en particulier. N'importe quel point d'appui suffit.
La phrase qui compte en restitution : « N de ces chemins partent d'un principal auquel tout utilisateur du domaine appartient. » Si N est supérieur à zéro, la discussion sur le contrôle à corriger en premier est close.
Lire les trois colonnes
Le graphe se présente en trois colonnes plutôt qu'en deux, et celle du milieu est justement le point. À gauche, les membres effectifs — les comptes réellement contenus dans le groupe qui détient le droit. Au milieu, les principaux qui le détiennent. À droite, les objets critiques visés. Les traits pointillés entre les deux premières colonnes sont les appartenances, résolues en un saut, qui répondent à la question qu'un nom de groupe n'éclaire jamais : qui est-ce, concrètement ?
Les groupes de largeur 3 ne sont volontairement pas dépliés. Lister les neuf mille membres des Utilisateurs du domaine n'apprendrait rien que vous ne sachiez déjà, et enterrerait les chemins qui nomment trois personnes.
La prise de contrôle du domaine
Certains chemins sont signalés à part, et ce sont ceux à lire en premier : un DCSync sur la tête de domaine, ou un droit de prise de contrôle sur un objet de niveau 0 — les groupes d'administration, AdminSDHolder, krbtgt. Ce ne sont pas des étapes d'escalade. C'est la fin de l'escalade.
Du graphe à la remédiation
Le rapport livre un plan dsacls à côté du graphe, avec une propriété qui compte : toutes les commandes modifiantes sont commentées. L'audit est en lecture seule, donc rien ne s'exécute par inadvertance ; un administrateur décommente ce qu'il a décidé de retirer, après l'avoir lu. Les commandes de vérification, elles, sont actives, parce que lire est sans risque.
Les chemins s'exportent aussi en Graphviz et en GraphML, ce qui permet de reprendre le schéma dans yEd ou Gephi avant une présentation. Cela peut paraître cosmétique ; ça ne l'est pas. Ce graphe est généralement la diapositive qui fait accepter le budget de remédiation.
Qu'en faire, dans l'ordre
- Fermer les prises de contrôle du domaine. Il n'y a rien à arbitrer.
- Fermer tout ce qui est de largeur 3 — les droits détenus par des principaux auxquels tout le monde appartient.
- Déplier les groupes restants et regarder qui est réellement dedans. La moitié des constats s'évapore quand le groupe se révèle contenir deux comptes de service dont personne n'avait besoin.
- Relancer l'audit et comparer. Un graphe qui se vide est la preuve de remédiation la plus lisible qui soit.