
Tout les amoureux d’Active Directory ont surement entendu parler de l’attaque sur les comptes Delegated Managed Service Account (dMSA) nommée BadSuccessor. Alors, vous vous dites surement : « oh, encore un article qui va plus ou moins bien nous expliquer l’astuce »… Eh bien, non. Plutôt que de vous redire ce que vous savez déjà (et si ce n’est pas encore le cas, vous aurez matière à creuser), cet article vous présente rapidement le fonctionnement de l’attaque afin de comprendre l’enjeu global puis une solution pour circonscrire les risques. Si vous êtes pressés, allez directement à la fin de cet article !
Harden AD et l’attaque BadSuccessor
En tant qu’auteur de la solution, il a bien fallut que je regarde si cette attaque la concerne… Et la réponse est oui : Harden AD est concernée par cette attaque. Par défaut, nous avons attribué un droit très large sur les OU utilisateurs des Tier 2 (comptes utilisateurs) et Tier 1 (comptes de service), en limitant la permission aux profils Administrator et Manager, comme le montre la capture d’écran ci-dessous :

Lorsque nous avions estimé le risque, nous avions validé que ce dernier restait acceptable du point de vue de l’obtention de privilège au niveau Active Directory, puisque l’attaquant restait dans son tier d’accès (même s’il faut avouer que ce n’est pas très fin comme permission). Avec cette nouvelle technique d’attaque, le risque d’évasion du tier et, pire, de prise de contrôle de l’AD, est indéniable.
La suite de cet article propose un retour sur l’analyse d’Akamaï (https://www.akamai.com/blog/security-research/abusing-dmsa-for-privilege-escalation-in-active-directory) et sur le moyen d’adresser ce risque sur notre modèle de délégation.
Rappel technique : qu’est-ce que le PAC ?
Le PAC (pour Privilege Attribute Certificate) est une structure qui permet le transfert des informations liées à l’autorisation fournies par les contrôleurs de domaine (DC). Il est utilisé par les protocoles d’authentification (comme Kerberos ou NTLM) qui vérifient les identités dans le but de transporter les informations d’autorisation qui contrôlent l’accès aux ressources.
Une fois l’authentification effectuée, la tâche suivante consiste à déterminer si une demande particulière est autorisée. La gestion des systèmes informatique modélise souvent les décisions d’autorisation à travers des groupes ; par exemple, tous les ingénieurs pouvant accéder à une imprimante spécifique ou tout le personnel commercial pouvant accéder à un certain serveur web. Rendre les informations de groupe disponibles de manière cohérente pour plusieurs services permet une gestion plus simple. Pour simplifier, on peut représenter le PAC sous cette forme visuelle :

Si le schéma met en évidence ici le stockage du SID (Secure IDentity) du compte, c’est précisément parce-que l’attaque va reposer sur une modification du contenu du PAC lors de l’utilisation d’un dMSA. Mais avant d’en dire davantage, revoyons tout d’abord comment la mise en œuvre d’un dMSA s’opère.
Migration d’un compte vers un dMSA
Je ne vais pas reprendre le contenu de l’article d’Akamaï, qui est particulièrement bien détaillé, mais vous présenter ici une synthèse des opérations effectuées lors du processus de migration (mes excuses, je l’ai rédigé en anglais) :

Ce qui est important à noter, c’est que l’action se pose en deux étapes : préparer l’objet pour la migration, en lui donnant des droits spécifiques, puis finaliser la migration en désactivant le compte que l’on remplace. Sur le papier, tout est parfaitement logique : on s’assure même que l’opération soit réalisée avec un compte membre du groupe administrateurs du domaine. Saut phare, saut gourde (oui, je suis en Bretagne, cela influe sur mon humour). Coté authentification, deux scénarios vont se présenter : une authentification particulière durant la phase de migration, puis une définitive une fois la migration terminée. Ce premier schéma décrit le processus d’authentification durant la phase de migration (encore merci à Akamaï !) – toujours en anglais, sorry :

Durant cette phase, le compte de service va, de lui-même, initier les modifications sur le compte dMSA afin de lui permettre de lire le mot de passe de l’objet (les SPN, quant à eux, ont été copiés de l’objet historique vers le dMSA lors de l’initialisation de la migration). Une fois la migration terminée, le compte source de l’application est désactivé et seul l’objet dMSA permet l’authentification, comme l’illustre le schéma ci-dessous :

Le client étant désactivé, le KDC retourne une erreur en indiquant le compte dMSA qui doit être utilisé pour la prochaine authentification. Avec ce mécanisme, n’importe-quel compte de service historique peut être remplacé par un dMSA (pour ce qui concerne les performances, en revanche, il y a matière à discuter – il va falloir aussi passer en faux positif les tentatives de connexions sur un compte migré… Mais c’est une autre histoire).
PAC en avril, la chasse aux oeufs de l’AD
Découvert officiellement en avril (merci, cela m’a permis un méga jeu de mot bien comme je les aime), l’attaque repose sur l’absence totale de contrôle lorsque l’on écrit dans les attributs du compte dMSA. Ce qui est important à comprendre, c’est que le contenu du PAC est différent dans le cas d’un compte dMSA (toujours en anglais) :

Dans notre cas, le PAC contient non seulement les informations propres à notre dMSA, mais également le SID du compte que l’on a remplacé ainsi que tous les groupes qui lui sont associés ! Peut-on mettre n’importe-quel compte ? Oui. Même le SID d’un contrôleur de domaine. A ce jour, si cette faille est exploitée, votre domaine est perdu…
Fonctionnement de l’attaque
Pour que cette attaque soit opérationnelle, il faudra être en mesure de créer un objet dMSA et d’en modifier les attributs. Notez que, dans le cas de l’attaque, il n’est pas nécessaire de réaliser réellement l’opération, uniquement de créer le compte. La commande new-adServiceAccount rend possible la création de l’objet à n’importe quel endroit de l’annuaire (ils ne sont donc pas restreints au conteneur « Managed Service Accounts », l’emplacement par défaut). D’autre part, le droit Create Child Objects est nécessaire sur les objets de type utilisateur, afin de pouvoir manipuler les attributs msDS-ManagedAccountPrecededByLink, qui permettra de « voler » le compte ciblé et msDS-DelegatedMSAState pour faire croire à une migration terminée.
Il n’existe à ce jour aucun moyen de ‘protéger’ un objet contre l’usurpation par un dMSA, même avec l’attribut « le compte est sensible et ne peut être délégué ». De plus, non seulement il est possible de « voler » les permissions de n’importe-quel objet, mais encore vous pouvez retrouver les mots de passe des comptes « volés » dans le champ « Previous-Keys » du Ticket Granting Ticket (TGT). Je vous invite à lire l’article d’Akamaï cité en référence au début de cet article pour comprendre l’astuce.
Conditions et conséquences
Pour que vous soyez exposé à cette attaque il faudra que votre schéma soit en version 10 (Windows Server 2025), c’est-à-dire que vous ayez intégré un contrôleur de domaine (DC) Windows Server 2025 – même si vous l’avez retiré depuis. En cas de succès, l’attaquant peut exfiltrer des comptes valides (nom d’utilisateur et mot de passe) qu’il pourra par la suite revendre ou compromettre intégralement votre domaine. A noter que, du fait qu’il peut se substituer à n’importe-quel compte, les données critiques de l’entreprise sont alors à porter de mains également !
Contre-mesure
Très bien, maintenant que nous avons compris le risque et la méthode, voyons comment s’en prémunir. Tout d’abord, rappelons qu’il n’existe pas de solution miracle : seul Microsoft sera en mesure de nous apporter une contre-mesure permanente en revoyant le processus de provisioning des comptes dMSA. Nous avons donc plusieurs choix : interdire la création des objets dMSA (en déclarant l’attribut expiré par exemple), ou encore limiter le périmètre d’action des délégations pour interdire la création des objets dMSA – mais là encore, il y a un risque d’erreur humaine, d’oubli et de potentiels soucis sur les prochaines évolutions (quoique, personnellement, je pense que cela reste maitrisable par une équipe compétente). Aucune de ces approches ne me semblaient optimales pour ne pas à la fois se passer de cette nouvelle fonctionnalité, particulièrement utile à la sécurité de nos infrastructures, et ne pas créer un terreau favorable à de futurs problèmes lors des évolutions du service.
C’est là que vient notre proposition de contre-mesure. Pour qu’elle soit efficace, nous prenons en compte deux règles fondamentales comme prérequis incontournable que vous devrez intégrer à vos processus :
- Les objets dMSA ne peuvent être créés que dans le conteneur Managed Service Accounts ; tout compte créé en dehors de ce conteneur sera supprimé.
- La modification de l’attribut msDS-ManagedAccountPrecededByLink ne permet pas d’insérer le distinguishedName d’un objet protégé, que ce soit parce-que l’attribut AdminCount est positionné à 1 ou que l’attribut UserAccountControl a le bit Not_Delegated positionné à 1.
Avec ces deux règles, vous interdirez à un compte non administrateur du domaine de créer un nouvel objet dMSA (le conteneur autorisé requiert ce niveau de privilège) et vous éviterez que sa modification ne puisse attribuer un droit protégé (ce dernier peut être étendu mais il faudra modifier le script).
Pour le déploiement, que vous ayez ou non déployé Harden AD, commencez par récupérer les sources à cet emplacement :
- Lien Github : https://github.com/LoicVeirman/AD-Tool—dMSA-Monitoring
Connectez-vous sur votre PDCemulator et décompressez ensuite le fichier Zip dans un dossier à la racine de votre disque (par exemple C:\Scripts), puis débloquez les fichiers et exécutez le script de déploiement :
cd c:\Scripts
Get-ChildItem -Path . -Recurse | Unblock-File
.\Fix-DetectBadSuccessor.ps1

Le script va procéder aux actions suivantes :
- Le script de contre-mesure est copié dans le dossier \\mon.domaine\netlogon\HAD\Check-dMSAobjectHandling, ce qui permet à la GPO de déployer le script sur les contrôleurs de domaine et de permettre aux tâches planifiées d’être opérationnelles.
- Les fichiers de la GPO sont adaptés pour votre domaine (ils contiennent par défaut des références au domaine d’origine qui a permis sont élaboration).
- Une nouvelle GPO est créée (HAD-TS-dMSA-BadSuccessor) ; les paramètres sont ensuite importés depuis la sauvegarde contenu dans le zip. Cette GPO permettra de copier le script des tâches planifiées dans l’emplacement %programData%\HardenAD\Check-dMSAobjectHandling, puis de créer deux tâches planifiées (HardenAD\dMSA – Creation et HardenAD\dMSA – Modification) – ces tâches se déclenchent sur la détection des évènements 5137 (création) et 5136 (modification) dans le journal de sécurité.
- Pour terminer, le script ajoute des règles d’audit à la racine du domaine : ces règles vont permettre de repérer la création et la modification des objets de classe msDS-DelegatedManagedServiceAccount.
Finalement, patientez jusqu’au prochain cycle de mise à jour des stratégies de sécurité (toutes les 5 minutes sur un contrôleur de domaine) et vous devriez voir les tâches planifiées créées sur les DCs. A chaque run, le script inscrit des évènements dans le journal du système :
- Application, source HAD-dMSAobjectHandling, event ID 5137 :
- Warning : objet détecté et supprimé avec succès – vous avez été protégé contre l’attaque (à auditer !)
- Error : objet détecté et non supprimé (erreur rencontré) – vous êtes en risque !
- Application, source HAD-dMSAobjectHandling, event ID 5136 :
- Warning : modification détectée et annulée avec succès – vous avez été protégé contre l’attaque (à auditer !)
- Error : modification détectée et non annulée (erreur rencontré) – vous êtes en risque, sauf si cette modification fait suite à la création de l’objet.
Par défaut, le script collecte un log de debug et l’enregistre dans l’emplacement Applications and Services Logs\HAD-Check-dMSAobjectHandling. Si vous voulez vérifiez le bon fonctionnement des tâches, exécutez le script suivant :
$dmsaName = read-host -Prompt "dMSA account name"
if ($null -ne $dmsaName -and $dmsaName.Length -le 20) {
Try {
New-ADServiceAccount -Name $dmsaName -DNSHostName "DontCare" `
-PrincipalsAllowedToRetrieveManagedPassword "$($env:computername)" -CreateDelegatedServiceAccount `
-OtherAttributes @{"msDS-ManagedAccountPrecededByLink"="CN=Administrator,CN=Users,$((Get-AdDomain).DistinguishedName)" ; "msDS-DelegatedMSAState"=2} `
-Path $(Get-AdDomain).UsersContainer
} Catch {
Write-host "Failed to create dMSA: $($_)" -ForegroundColor Magenta
}
} else {
Write-Host "Invalid username." -ForegroundColor Red
}
Notes
Le script part du principe que l’audit avancé sur Active Directory est en place. Si vous avez un doute ou si cela n’est le cas pour vous, vous pouvez importez la GPO de configuration de l’audit en utilisant le paramètre -AddAudit au lancement du script.
Si vous souhaitez rejouer le script suite à une erreur ou une modification, utilisez le paramètre -Force, qui forcera ce dernier à supprimer la GPO HAD-TS-dMSA-BadSuccessor avant de la réimporter.
Conclusion
Et voilà ! Normalement, le risque est bien adressé. Les tâches déclenchent la remédiation en moins d’une seconde dans mes labs ! J’espère que cette approche technique et les explications autours de cette dernière vous auront appris de nouvelles choses. N’hésitez pas à décortiquer le contenu du backup pour voir comment le schedule récupère les évènements de l’event et les passent en arguments au script 😉
(c’est bon, Gérard, tu peux lire maintenant !)