Yuval Gordon Chercheur en sécurité | Microsoft

Cet article présente une nouvelle attaque ciblant les comptes de services gérés par groupe (gMSA), baptisée "Golden GMSA", qui permet aux attaquants de récupérer les attributs de la clé racine du service de distribution de clés (KDS), puis de générer hors ligne le mot de passe de tous les gMSA associés.

TL;DR

Un attaquant disposant de privilèges élevés peut obtenir tous les ingrédients nécessaires pour générer le mot de passe de n'importe quel gMSA du domaine à tout moment en deux étapes :

  1. Récupérer plusieurs attributs de la clé racine KDS dans le domaine
  2. Utilisez le GoldenGMSA pour générer le mot de passe de tout gMSA associé à la clé, sans compte privilégié.

Lecture associée

gMSA 101

Les mots de passe des comptes de service ne font généralement pas l'objet d'une rotation régulière, ce qui les expose à des risques, notamment parce qu'ils peuvent être ciblés par le biais du Kerberoasting de Kerberoasting. A gMSA (group Managed Service Account ; le g minuscule est un mystère) est un type de compte spécial dans Active Directory (AD) introduit dans Windows Server 2012 pour résoudre ce problème précis. Le seul but de cet objet est d'être utilisé comme compte de service, avec la caractéristique importante de la rotation des mots de passe. Un compte gMSA peut être utilisé par un ou plusieurs serveurs avec des services compatibles.

Le mot de passe de la gMSA est géré par AD. Il est automatiquement remplacé tous les 30 jours par un mot de passe de 256 octets généré de manière aléatoire, ce qui le rend infaisable. En tant que documentation Microsoft décrit :

Description de Microsoft Key Distribution Service par MS Docs

Le mot de passe est calculé sur la base d'un secret qui change périodiquement et d'attributs non nommés de la gMSA. Le secret utilisé est stocké dans l'objet clé racine du KDS.

Rotation automatique du mot de passe - comment est-ce possible ?

L'idée derrière ce type de compte est intéressante. Les DCs inscriptibles gèrent le mot de passe de la gMSA et le font tourner tous les 30 jours (par défaut). Lorsqu'un serveur utilisant ce compte a besoin d'utiliser la gMSA, il demande d'abord le mot de passe le plus récent au DC en récupérant un attribut appelé msDS-ManagedPassword. Cet attribut est un Binary Large Object (BLOB) qui contient le mot de passe.

L'attribut msDS-GroupMSAMembership d'un gMSA spécifie qui est autorisé à obtenir le mot de passe. Le DC inscriptible, à son tour, utilise cet attribut pour valider que l'appelant est autorisé à l'obtenir. Jusqu'à présent, nous pouvons voir un moyen simple d'abuser de ce système : Si un attaquant accède à un compte qui a accès à msDS-ManagedPassword, il peut lire le mot de passe pour le gMSA en question.

Stockage du mot de passe

Les DC ne stockent généralement pas de mots de passe dans leurs bases de données, mais seulement des secrets dérivés de mots de passe. Cela soulève une question : Supposons que le DC inscriptible ne stocke pas le mot de passe en clair ; comment peut-on le retrouver en lisant l'attribut msDS-ManagedPassword ? Il s'avère que msDS-ManagedPassword est un attribut attribut construitce qui signifie que cet attribut n'est pas stocké dans l'AD mais calculé lorsqu'un utilisateur autorisé tente de le lire.

Comment le msDS-ManagedPassword est-il construit ?

Nous savons maintenant que le mot de passe est construit à la demande par les DCs inscriptibles. Nous savons également que chaque DC inscriptible peut construire l'attribut, et que le résultat sera toujours le même. Cette page montre comment le mot de passe est généré, mais elle n'est pas assez détaillée pour nous permettre de le construire nous-mêmes.

La recherche de la fonction qui construit cet attribut nous conduirait à ntdsai.dll!dbGetConstructedAtt, qui est la fonction responsable de la construction des attributs.

dbGetManagedServiceAccountPassword (mot de passe du compte de service géré)

Nous pouvons voir un appel à dbGetManagedServiceAccountPasswordmais nous intéressons seulement que le mot de passe plutôt qu'au l'ensemble du ManagedPasswordBlob. En creusant plus dans la fonction nous conduit finalement nous à a appel à la fonction KdsCli.dll !KdsGetGmsaPasswordBasedOnKeyId.

KdsGetGmsaPasswordBasedOnKeyId (KdsGetGmsaPasswordBasedOnKeyId)

Passons en revue les paramètres de cette fonction :

  • _SecurityDescriptor est un descripteur de sécurité (SD) prédéfini, codé en dur dans ntdsai.dll, qui accorde des autorisations de lecture et d'écriture à S-1-5-9 (contrôleurs de domaine d'entreprise), comme le montre la capture d'écran suivante :
gmsaSecurityDescriptor
  • _SID est l'ObjectSID de la gMSA souhaitée.
  • _MsdsManagedPasswordID est un attribut de l'objet gMSA qui, entre autres choses, référence par GUID l'instance de clé racine KDS utilisée par le gMSA pour la génération de mots de passe.
    Nous n'avons pas trouvé de documentation formelle pour cet attribut, mais un peu plus de recul nous a permis de comprendre comment le construire nous-mêmes avec les paramètres montrés dans la capture d'écran ci-dessous.
Msds_ManagedpasswordID
  • Le mot de passe est un pointeur vers un tampon qui stockera le mot de passe.
  • La taille du mot de passe est le nombre d'octets qui seront écrits dans OutPassword. La valeur codée en dur est 256.

Récupération de la clé et construction du mot de passe

Le flux d'exécution aboutit finalement à la fonction GetKeyFromKdsService, qui invoque la méthode RPC GetKey.

getKeyStatus

Nous pouvons constater que les paramètres correspondent à la documentation de [MS-GKDI]

Méthode GetKey

Remarque intéressante : GetKey effectue des contrôles d'accès par rapport au TargetSD fourni par l'appelant, ce qui signifie que nous pouvons invoquer cette fonction avec un descripteur de sécurité qui nous accorde l'accès, et le DC renverra une clé. Malheureusement, le SD est également utilisé dans le calcul de la clé. Ainsi, même si nous pouvons toujours modifier le SD pour contourner les contrôles d'accès, nous obtiendrons une clé non valide si le SD fourni n'est pas valide. Le seul descripteur de sécurité valide qui donne une clé valide est celui codé en dur que nous avons mentionné précédemment (gmsaSecurityDescriptor), qui n'accorde l'accès qu'aux contrôleurs de domaine d'entreprise (S-1-5-9).

Si l'appelant dispose des autorisations nécessaires, cette méthode génère une clé et la renvoie dans une structure GKE ( Group Key Envelope ). Après avoir obtenu la clé, nous pouvons enfin appeler kdscli.dll!_GenerateGmsaPassword pour générer le mot de passe.

Générer un mot de passeGmsa

Les sixième et septième paramètres sont facultatifs et n'affectent pas le mot de passe. Pour cette raison, nous pouvons leur attribuer la valeur null.

Récapitulation de la génération du mot de passe gMSA

Un mot de passe gMSA est généré en appelant une fonction qui réside dans kdscli.dll (non exportée, malheureusement), que nous avons sur n'importe quel point de terminaison Windows. L'appel de cette fonction nécessite trois choses :

  1. SID 
  2. msds-ManagedPasswordID du gMSA (peut être récupéré à l'aide d'une requête LDAP)
  3. GKE, qui peut être générée en appelant la méthode GetKey sur le DC avec des privilèges élevés via RPC

Mise en œuvre de GetKey et de la génération de mots de passe hors ligne

Nous avons tenté de simplifier au maximum la génération des mots de passe gMSA, dans la mesure où elle pouvait être effectuée hors ligne. Le seul appel RPC dans le processus est pour GetKey. Nous avons donc décidé de l'inverser et de le porter au code C# qui génère une GKE.

Nous avons découvert que la clé change périodiquement, comme l'indique Microsoft. Mais la clé est dérivée des attributs de l'objet clé racine KDS et de trois entiers (L0KeyID, L1KeyID, L2KeyID) dérivés d'un horodatage, comme le montre la capture d'écran suivante.

GetCurrentIntervalID

L'horodatage actuel est stocké dans l'attribut msDS-ManagedPasswordID du gMSA, lisible par tous les utilisateurs du domaine par défaut, de sorte que nous pouvons récupérer l'horodatage et générer ces nombres entiers.

Les seuls ingrédients que le DC utilise pour générer les mots de passe, mais que nous n'avons pas, sont les attributs suivants de la clé racine KDS :

  • cn
  • msKds-SecretAgreementParam
  • msKds-RootKeyData
  • msKds-KDFParam
  • msKds-KDFAlgorithmID
  • msKds-CreateTime
  • msKds-UseStartTime
  • msKds-Version
  • msKds-DomainID
  • msKds-PrivateKeyLength
  • msKds-PublicKeyLength
  • msKds-SecretAgreementAlgorithmID

La récupération de ces attributs nécessite des droits de lecture et des droits étendus sur l'objet clé racine de KDS, que seuls les administrateurs de domaine possèdent par défaut. Toutefois, ces valeurs ne sont PAS modifiées périodiquement.

Cela signifie que si nous compromettons ces valeurs, nous pouvons les utiliser pour calculer une GKE pour tout gMSA associé à la clé racine du KDS et générer son mot de passe hors ligne.

L'attaque du GMSA d'or 

L'attaque Golden GMSA se produit lorsqu'un attaquant récupère les attributs pertinents d'une clé racine KDS et les utilise ensuite pour générer hors ligne le mot de passe des comptes gMSA associés. L'attaque Golden GMSA est quelque peu similaire à l'attaque Golden Ticket, qui permet aux attaquants qui compromettent le compte krbtgt de falsifier des tickets d'octroi de tickets (TGT) tant que le mot de passe krbtgt reste inchangé.

Une différence notable entre l'attaque Golden Ticket et l'attaque Golden GMSA est que nous n'avons pas connaissance d'un moyen de faire tourner le secret de la clé racine du KDS. Par conséquent, si une clé racine KDS est compromise, il n'y a aucun moyen de protéger les gMSA qui lui sont associés.. La seule solution consiste à créer de nouveaux gMSA avec une nouvelle clé racine KDS.

L'armement de l'attaque Golden GMSA

Nous avons adapté l'attaque Golden GMSA dans un outil que vous pouvez télécharger ici. ici.

L'outil GoldenGMSA Attack peut récupérer les attributs nécessaires à partir d'un objet de clé racine KDS spécifié ou utiliser les valeurs fournies par l'utilisateur pour générer une GKE. L'outil peut également récupérer le msDS-ManagedPasswordID sur la base d'un SID gMSA et, bien sûr, générer le mot de passe du gMSA hors ligne.

Un attaquant peut potentiellement utiliser le mot de passe pour compromettre les services qui utilisent la gMSA en falsifiant un ticket Silver ou en obtenant un ticket de service Kerberos pour les comptes privilégiés par l'intermédiaire de S4U2Self. Si le gMSA dispose de privilèges élevés, l'attaquant peut l'utiliser pour compromettre d'autres ressources et, dans certains cas, compromettre l'ensemble de la forêt.

Exemple d'attaque de l'ASGM en or

Un pirate peut utiliser l'outil GoldenGMSA pour énumérer tous les gMSA et leurs clés racine KDS associées. Un attaquant disposant de privilèges élevés peut également utiliser l'outil GoldenGMSA pour extraire les clés racine KDS.

gMSA_Enumerate

L'attaquant peut ensuite utiliser le KDS vidés root key BLOB pour générer le mot de passe du gMSA hors ligne.

gMSA_Compute

Le mot de passe est encodé en Base64 car il peut contenir des caractères non imprimables.

Détection d'une attaque Golden GMSA

Evénement 4662 une opération a été effectuée sur un objet

Le compromis d'un d'un KDS root key ne génère pas d'événements de sécurité par défaut. Les défenseurs doivent configurer un SACL sur le le KDS root key objets pour tous ceux qui lisent les msKds-RootKeyData attribut. Une fois que l'attribut liste de contrôle d'accès au système (SACL) est configurée, toute atation de vider les données clés d'un KDS root key génère un un événement de sécurité 4662 sur le DC l'objet type d'objet est msKds-ProvRootKey et le nom du compte n'est pas un DCcomme le montre la capture d'écran suivante :

Défense contre les attaques de Golden GMSA

Les comptes de service gérés par groupe sont une excellente fonctionnalité d'Active Directory qui atténue certains risques associés aux comptes de service, tels que les attaques de type "Kerberoasting". Toutefois, les mots de passe associés aux gMSA sont générés à l'aide d'entrées qui ne peuvent pas faire l'objet d'une rotation en cas de compromission, ce qui permet aux attaquants disposant de privilèges élevés de déverser les clés racine KDS et de générer les mots de passe des gMSA associés hors ligne aussi longtemps qu'ils existent.

Les défenseurs doivent surveiller les accès anormaux aux clés racine KDS, tels que les non DC qui lisent l'attribut msKds-ProvRootKey et les événements de connexion anormaux liés aux comptes gMSA.