Le password spraying, c’est une technique connue qui consiste à tester un même mot de passe sur plusieurs comptes, en espérant que ce mot de passe fonctionne pour l’un d’entre eux.
Cette technique est utilisée dans beaucoup de cadres différents : Sur des applications web, du cloud, des services comme SSH, FTP, et bien d’autres. On l’utilise également beaucoup dans des tests d’intrusion au sein d’entreprises utilisant Active Directory.
C’est à ce dernier cas que nous allons nous intéresser, parce que bien que la technique paraisse simple, ce n’est pas évident de la mettre en pratique sans effets de bord.
Introduction
Cet article n’est pas une découverte révolutionnaire, mais plutôt un état de mes recherches sur les politiques de mots de passe dans un environnement Active Directory. En effet, il existe plusieurs moyens de limiter les tentatives d’un attaquant via le blocage de comptes. Ces différents leviers sont très utiles lorsqu’ils sont compris, ce qui n’est pas toujours le cas (et ce n’était pas mon cas il y a quelques semaines).
Cet article permettra, je l’espère, de clarifier ce que permettent les politiques de mot de passe, comment elles sont appliquées, et donc en tant que pentester, comment faire du password spraying en réduisant au mieux les risques de blocage de comptes.
Mécanisme d’authentification
Le password spraying sur un annuaire Active Directory consiste donc à choisir un mot de passe qu’on considère comme très probablement utilisé par au moins un utilisateur, et on le teste sur l’ensemble des utilisateurs du domaine. On ne détaillera pas ici les moyens existants pour tester la validité d’un mot de passe, il en existe beaucoup. Un mot de passe peut être testé via Kerberos ou NTLM, quel que soit le protocole utilisé (SMB, LDAP, …).
Quoiqu’il en soit, lorsque l’authentification est testée, le contrôleur de domaine vérifiera d’abord si le compte est verrouillé par la politique de mots de passe. Le cas contraire, il vérifiera la validité du mot de passe. Enfin, si le mot de passe est valide, le compte sera authentifié, et l’attribut LDAP badPwdCount
de l’utilisateur sera remis à 0
. Si en revanche le mot de passe est erroné, alors badPwdCount
sera incrémenté, et si cet échec entraine un verrouillage du compte, en suivant les critères des politiques de mots de passe, alors le compte sera marqué comme verrouillé. Cela est fait en renseignant la date et l’heure courante dans l’attribut LDAP lockoutTime
de l’utilisateur.
Ca fait déjà un sacré processus de vérification, que j’ai tenté de résumer dans un schéma. Est-ce que ça clarifie les choses ? Je n’en suis pas sûr. Mais le voilà quand même.
Maintenant qu’on a clarifié cette logique, on comprend qu’il reste une inconnue qui semble plutôt importante, c’est la politique de mot de passe. Parce qu’en effet, c’est en suivant la politique de mot de passe appliquée au compte que le contrôleur de domaine est capable de savoir si oui ou non, le compte est verrouillé, ou s’il doit l’être. Voyons alors où se trouve cette politique par défaut, et détaillons les paramètres qui nous intéressent.
La politique de mots de passe par défaut
Lorsqu’on installe un Active Directory, il y a beaucoup de choses qui sont créées et paramétrées par défaut. Parmi elles se trouvent deux GPO : La Default Domain Policy
liée à la racine du domaine, et la Default Domain Controller Policy
liée à l’OU Domain Controllers
.
Dans la Default Domain Policy
, on trouve les paramètres suivants qui permettent de définir les règles de verrouillage des comptes.
- Account lockout duration : Lorsqu’un compte est verrouillé suite à un mot de passe erroné, ce paramètre définit le temps durant lequel ce compte reste verrouillé.
- Account lockout threshold : Détermine le nombre de tentatives erronées autorisées. Si ce paramètre est
3
, alors 3 tentatives erronées verrouilleront le compte. - Allow Administrator account lockout : Quand ce paramètre est activé, cela signifie que même le compte d’administration par défaut (Administrator) est concerné par la politique de mots de passe.
- Reset account lockout counter after : En règle générale, lorsqu’une authentification échoue,
badPwdCount
est incrémenté. Cependant, si la tentative échouée précédente est plus ancienne que le temps paramétré ici, alorsbadPwdCount
est remis à 0. Par exemple, si ce paramètre vaut5 minutes
alors lors d’un premier échec,badPwdCount
vaut 1. Lors d’un 2ème échec quelques secondes après,badPwdCount
vaut 2. Si un 3ème échec survient, mais 5min10 après le 2ème échec,badPwdCount
aura été réinitialisé à 0, et cet échec le passe donc à 1.
Voilà les fameux paramètres qui sont pris en compte par le contrôleur de domaine pour savoir si un compte est verrouillé. Concrètement (et parce que le schéma précédent n’était pas assez complexe bien sûr), ces valeurs sont utilisées de la manière suivante :
Vous voyez donc que pour savoir si le compteur de mauvais mot de passe est calculé en prenant la date du dernier échec, et si le temps définit dans Reset account lockout counter after est passé, alors le compteur est remis à zéro. Sinon, il est incrémenté. Ce compteur est alors comparé à Account lockout threshold. Si c’est égal (ou supérieur), alors le compte est considéré comme verrouillé, et le champ lockoutTime
est rempli. Lors d’une prochaine tentative, si le temps définit dans Account lockout duration est passé (en prenant comme départ la date dans lockoutTime
) alors le compte n’est plus verrouillé, et le mot de passe va être testé.
Si ce n’est toujours pas clair, alors reprenez ces explications depuis le début, et concentrez-vous. Je ne saurai pas mieux expliquer. Il faut que tout ça soit clair pour comprendre la suite. En effet, on a parlé de la politique de mot de passe dans la GPO Default Domain Policy
. Mais on va voir qu’il n’y a pas qu’ici que cette politique peut être définie.
Ordre d’application des GPO
Personnellement, j’aime bien créer une nouvelle GPO à chaque fois que je veux apporter une modification à mon système d’information. Ainsi, pour appliquer une politique de mots de passe, je créerai une GPO dédiée, dans laquelle il n’y aura que des paramètres liés à la politique de mot de passe, et ça fonctionnera très bien. En effet, on a vu que les paramètres étaient présents dans la Default Domain Policy
, mais ils peuvent évidemment être paramétrés dans n’importe quelle GPO.
Ce qui est intéressant à savoir, c’est le comportement suivi quand cette politique de mots de passe est définie dans plusieurs GPO à la racine du domaine.
Il existe en fait un ordre de priorité qui permet de définir quelle GPO prend le dessus en cas de conflit. Dans le gestionnaire de GPO, lorsque vous cliquez sur une OU (ou sur le domaine), vous avez la liste des GPO appliquées dans l’onglet Linked Group Policy Objects
. Vous remarquerez qu’elles sont numérotées, via la colonne Link Order
, ce qui permet de déterminer la priorité de chaque GPO. Concrètement, la dernière GPO de la liste sera d’abord appliquée, puis l’avant dernière, jusqu’à la GPO numéro 1. Ainsi, c’est la GPO numéro 1 qui aura “le dernier mot”. Si elle avait des paramètres qui entraient en conflit avec les autres GPO, ce seront ses paramètres à elle qui seront effectifs.
Dans cet exemple, si jamais une politique de mot de passe est définie dans PASSWORD POLICY
et une autre dans Default Domain Policy
, c’est cette dernière qui sera réellement appliquée.
Il n’y a pas d’attribut qui permet d’avoir le numéro de la GPO dans la liste. En fait, pour chaque unité organisationnelle (et pour l’objet domaine), l’attribut
gpLink
contient la liste des GPO qui sont liées à cet objet, et elles sont enregistrées dans l’ordre d’application, donc dans l’ordre décroissant deLink Order
. Sur l’objethackn.lab
, on trouvera dans cet exemple d’abord la GPOPASSWORD POLICY
, puisLOCKSCREEN
,FIREWALL
et enfinDefault Domain Policy
.
Bien, en listant les GPO qui sont appliquées à la racine du domaine, on est maintenant capable de savoir quelle est la véritable politique de mots de passe appliquée par ce biais.
Mais évidemment, ça ne s’arrête pas là. Comment faire si on souhaite appliquer une politique de mots de passe différente pour nos administrateurs par exemple ? Et oui, on impose une politique à nos utilisateurs, mais on souhaiterait une politique plus forte pour nos administrateurs, et c’est une très bonne pratique !
Politique de mots de passe sur une unité organisationnelle
Avant même de commencer ce chapitre, j’annonce que ça ne fonctionnera pas. Il faudra utiliser des PSO pour atteindre cet objectif, ce qu’on verra juste après.
En effet, nous pourrions être tentés par organiser notre Active Directory de telle sorte à ce que nos administrateurs soient dans une unité organisationnelle dédiée, et nous voudrions appliquer une politique de mot de passe spécifique à ces utilisateurs. Pourquoi ne pas créer une GPO dédiée à cette OU, dans laquelle nous définissons nos critères bien robustes de mots de passe sécurisés ?
Prenons cet exemple. Nous avons une GPO PASSWORD POLICY
placée à la racine du domaine, qui autorise de se tromper 10 fois avant verrouillage pendant 10 minutes.
Créons alors une GPO beaucoup plus robuste liée à l’OU Admins
dans laquelle se trouve le compte adm_pixis. Cette GPO devrait bloquer un compte après 2 tentatives échouées, et le compte devrait être bloqué pendant 60 minutes.
Maintenant, nous pouvons essayer de nous connecter avec l’utilisateur adm_pixis, mais nous nous trompons volontairement de mot de passe. Une fois, deux fois, … trois fois, quatre fois. Le compte n’est toujours pas verrouillé.
En revanche, lors du 11ème essai, ça ne rate pas, notre compte est bien verrouillé.
Pourquoi cette magie noire ? Et bien tout simplement parce que ces paramètres qu’on définit par GPO, ils ont pour effet de mettre à jour certains attributs de l’objet auquel ils sont liés, et ces fameux attributs n’existent que sur l’objet domaine, pas sur les unités organisationnelles.
Vous avez ici l’attribut lockoutDuration
qui correspond au paramètre Account lockout duration, lockoutObservationWindow
paramétré par Reset account lockout counter after, ou encore lockoutThreshold
qu’on peut définir avec Account lockout threshold. Ainsi, lorsqu’une politique de mot de passe est définie par GPO liée à une OU, cette politique n’aura aucun effet sur cette unité organisationnelle, donc aucun effet sur les comptes du domaine dans cette OU.
Sachez que si vous appliquez une GPO avec une politique de mots de passe à un OU qui contient des ordinateurs (postes de travail ou serveurs), c’est sans effet sur le domaine, mais pas sur les machines, puisque la politique de mot de passe s’appliquera pour les comptes locaux.
Tout cela signifie alors qu’il semble uniquement possible d’appliquer une politique de mots de passe globale à tous les utilisateurs. Mais comment fait-on pour durcir cette politique pour nos administrateurs ? C’est pour répondre à ce besoin qu’entrent en jeu les PSO, ou Password Settings Objects.
Les PSO
Ah, les PSO. Voici la réponse à nos problèmes (pour de vrai). Ce sont des objets Active Directory qui permettent de définir les mêmes paramètres sur les mots de passe que ceux qu’on trouve dans les GPO, et de les appliquer à des utilisateurs, ou des groupes d’utilisateurs. On est donc en mesure de créer des politiques de mots de passe avec une granularité fine, ou Fine-Grained Password Policies (FGPP).
Ces objets doivent être créés à un endroit bien particulier, dans un conteneur qui s’appelle Password Settings Container, lui-même dans le conteneur System se trouvant à la racine du domaine. Une manière simple de créer des PSO est de passer par l’outil Active Directory Administrative Center et de naviguer dans ce conteneur.
Depuis cette interface, vous pourrez aisément créer des politiques de mots de passe et décider à qui ces politiques doivent s’appliquer. Si on voulait par exemple reprendre notre super politique sécurisée, on pourrait créer une PSO avec ces mêmes paramètres et l’appliquer à tous les membres du groupe Domain Admins.
La même question de priorité que les GPO se pose alors. Déjà, les PSO sont prioritaires par rapport à la politique de mot de passe du domaine. Ensuite, si plusieurs PSO sont créées, et que des utilisateurs sont concernés par différentes PSO, laquelle sera prise en compte ?
C’est le paramètre Precedence
présent dans la PSO, juste après son nom, qui permet de trier les PSO par ordre de priorité. Tout comme le Link Order
pour les GPO, les PSO sont appliquées de la Precedence
la plus haute à la plus basse. Ainsi, les valeurs les plus basses sont prioritaires par rapport aux plus hautes, puisqu’elles ont également le dernier mot.
Si jamais deux PSO ont la même valeur dans
Precedence
, c’est la dernière PSO créée qui sera prioritaire
Descendons un tout petit peu plus dans la technique. On a vu que lorsque des GPO paramètrent la politique de mot de passe, leur ordre de priorité sera suivi et les attributs de l’objet domaine seront mis à jour pour refléter la politique de mots de passe effective. Ces attributs sont accessibles en lecture à tous les utilisateurs authentifiés, donc il suffit d’aller lire ces attributs sur le domaine pour connaitre la politique de mots de passe appliquée au domaine.
Qu’en est-il des PSO ? Comment savoir si un utilisateur est affecté par telle ou telle PSO ? Les PSO ne peuvent pas modifier les attributs du domaine, puisque par nature, elles sont là pour avoir des politiques de mots de passe différentes. En fait, chaque PSO étant un objet Active Directory, les politiques de mots de passe sont enregistrées dans les attributs de leur objet.
Les attributs n’ont pas exactement le même nom que sur le domaine, ça serait trop simple, mais on s’y retrouve quand même. Toujours dans notre objectif de password spraying, on sera notamment intéressés par msDS-LockoutThreshold
et msDS-LockoutObservationWindow
.
Un autre attribut qui nous intéresse fortement est msDS-PSOAppliesTo
. Il contient la liste des utilisateurs et/ou groupes auxquels s’applique la PSO.
Problème de droits sur le conteneur des PSO
On pourrait alors penser qu’à ce stade, nous avons tous les éléments en main pour connaitre la politique de mot de passe effective appliquée à chaque utilisateur.
Par défaut, on prend par défaut, pour chaque utilisateur, la politique de mot de passe du domaine en regardant les attributs sur l’objet domaine. Ensuite on liste toutes les PSO, qu’on analyse dans le bon ordre de priorité, on liste les utilisateurs dans les groupes sur lesquels sont appliqués chaque PSO, et on peut ainsi déduire pour chaque utilisateur la PSO qui est appliquée, et donc sa politique de mots de passe.
En théorie, ça fonctionnerait, mais il y a un petit hic dans cette démarche.
Vous voyez le problème ? Non ? Par défaut, seuls les administrateurs ont le droit de lister les PSO, ainsi que voir leur contenu. Ainsi, en tant qu’utilisateur lambda, on n’a aucun moyen de lister le contenu du conteneur Password Settings Container, et donc de voir les PSO, les politiques appliquées, et à qui elles sont appliquées.
Dans notre optique de password spraying, c’est assez dangereux. Ca signifie qu’on ne peut jamais être certain d’avoir les politiques de mot de passe effectives sur les différents utilisateurs du domaine, puisqu’on n’est pas à l’abri qu’une PSO (qu’on ne peut pas voir ni lire), s’applique sur un ou plusieurs utilisateurs.
Constructed Attributes & Backlinks
C’est en faisant face à ce mur que j’ai découvert les attributs construits, ou constructed attributes. Vous savez sûrement que quand on ajoute un utilisateur dans un groupe, l’attribut LDAP member
du groupe est mis à jour, en ajoutant l’utilisateur. Si on liste simplement les attributs d’un utilisateur, on ne voit en revanche pas d’attribut memberOf
.
En fait, il existe beaucoup d’autres attributs que ceux qu’on voit par défaut, mais ils sont gérés automatiquement par Active Directory. On ne peut pas les modifier manuellement. Ce sont des attributs construits à partir d’autres attributs, les fameux constructed attributes. Et parmi eux, une classe d’attributs s’appelle les backlinks. Ce sont des attributs qui vont de pair avec un vrai attribut, sur le même objet ou sur d’autres objets.
Par exemple, l’attribut memberOf
est un backlink qui va de pair avec l’attribut member
. Ainsi, dès que l’attribut member
d’un objet est modifié (ajout ou suppression d’un utilisateur ou d’un groupe), ce changement est automatiquement reflété dans sa paire, memberOf
, de l’objet concerné. Donc si on affiche ces backlinks, on peut voir la liste des groupes auxquels appartient un utilisateur.
Et bien devinez quoi, il existe la même chose pour les PSO. On n’a pas le droit de lister les PSO avec un utilisateur standard, donc on ne peut pas lire l’attribut msDS-PSOAppliesTo
présent sur chaque PSO.
Mais on a de la chance, il existe un constructed link pour cet attribut, et il s’appelle msDS-ResultantPSO. Alors lui, c’est pas un simple backlink, parce qu’il est un peu plus intelligent. Tous les utilisateurs du domaine ont cet attribut qui est potentiellement mis à jour à chaque fois qu’une PSO est appliquée à des utilisateurs, mais aussi à des groupes. Si un groupe est ajouté dans une PSO, tous les membres de ce groupe auront leur attribut msDS-ResultantPSO
qui sera mis à jour, sous réserve que la PSO soit prioritaire. Donc en plus de dynamiquement résoudre les membres des groupes, cet attribut contiendra toujours le nom de la PSO effective qui s’applique à chaque utilisateur.
Et la cerise sur le gâteau dans tout ça, c’est que cet attribut, on peut le lire sur tous les utilisateurs du domaine, même avec un compte sans privilège.
Vous vous souvenez, on a appliqué une PSO au groupe Domain Admins. Allons regarder les attributs de type constructed du compte adm_pixis, qui fait partie de ce groupe.
On voit bien notre back-link memberOf
qui contient Domain Admins, ainsi que notre attribut construit msDS-ResultantPSO
dans lequel on retrouve la PSO que nous avons créée, et appliquée au groupe Domain Admins.
C’est parfait, maintenant on est capable de savoir si la politique de mots de passe d’un utilisateur est affectée ou non par une PSO.
Alors attention, on n’a toujours pas le droit de lire le contenu de la PSO, du moins pas en tant qu’utilisateur standard. Mais d’un point de vue password spraying, rien que savoir qu’une PSO est appliquée sur un utilisateur est extrêmement précieux. On peut tout simplement ignorer tous les comptes pour lesquels une PSO est appliquée, et restreindre nos tests aux utilisateurs pour lesquels la politique de mot de passe effective est celle du domaine.
Outillage
C’est en écrivant un outil de password spraying que j’ai suivi ce lapin blanc des politiques de mot de passe pour tenter de réduire au maximum le risque de verrouiller des comptes lors de mes tests d’intrusion. L’outil que j’ai développé suit toute cette démarche pour déterminer la liste des utilisateurs et la politique de mot de passe effective pour chacun d’entre eux. Si l’outil n’est pas capable de lire le contenu des PSO, il se contentera d’ignorer les comptes affectés lors des tests.
Mais j’ai voulu aller un peu plus loin. On a vu qu’au bout d’une certaine durée, l’attribut badPwdCount
des utilisateurs était réinitialisé. Cette certaine durée, qu’on retrouve dans l’attribut lockoutObservationWindow
sur le domaine, ou dans l’attribut msDS-LockoutObservationWindow
des PSO, peut ainsi varier d’un utilisateur à l’autre.
L’outil que j’ai développé prend en entrée une liste de mots de passe qu’on souhaite tester sur les utilisateurs, et il va tenter tous les mots de passe sur tous les utilisateurs, en prenant soin de respecter les seuils de verrouillages, les temps d’attente pour que le compteur soit remis à zéro pour pouvoir continuer les tests.
Pour que tout ça fonctionne sans accroc, l’outil commence par récupérer l’heure du contrôleur de domaine pour être parfaitement synchronisé, et se synchronise régulièrement avec le LDAP (on n’est pas à l’abri d’un vrai utilisateur qui se trompe de mot de passe pendant notre password spraying).
Bref, je suis super heureux de partager avec vous l’outil conpass, qui m’est extrêmement utile en tests d’intrusion, j’espère qu’il le sera autant pour vous.
Alors attention, il a fonctionné durant mes derniers pentests, mais ça reste un outil qui va tester des mots de passe, écrit par un humain qui fait des erreurs, donc il est possible qu’il y ait des bugs et que ça plante, ou que ça verrouille des comptes. Je suis donc très preneur de retours, de tests dans des environnements maitrisés, pour qu’il soit le plus robuste possible.
Ceci est un cross-post de la version anglaise : https://en.hackndo.com/password-spraying-lockout/