AdminSDHolder et SDProp : nettoyage et surveillance
Établissez une base de l'ACL AdminSDHolder, repérez les comptes adminCount=1 orphelins, réinitialisez leurs ACL, lancez SDProp à la demande et surveillez AdminSDHolder.
AdminSDHolder est l'ACL modèle de chaque compte privilégié d'un domaine. Une fois par heure, le processus SDProp de l'émulateur PDC la copie sur chaque membre des groupes protégés. C'est ce qui en fait l'un des emplacements de persistance les plus efficaces d'Active Directory. Un attaquant qui ajoute une seule ACE à CN=AdminSDHolder,CN=System voit ce droit réappliqué indéfiniment à chaque Domain Admin, même après que les défenseurs ont nettoyé les comptes un par un. Le même mécanisme laisse aussi derrière lui une traînée de comptes adminCount=1 orphelins, avec l'héritage désactivé et des ACL privilégiées périmées.
Le guide de référence sur les ACL explique ce que fait SDProp et fournit une première requête pour les adminCount obsolètes. Ce guide en est le prolongement opérationnel. Il couvre l'ensemble exact des objets protégés, une base de l'ACL AdminSDHolder, une procédure de nettoyage sûre, l'exécution de SDProp à la demande et des alertes qui détectent les manipulations.
Ce que SDProp protège
Dans les domaines Windows Server 2016 et ultérieurs, SDProp protège ces objets ainsi que les membres transitifs de ces groupes :
- Groupes : Account Operators, Administrators, Backup Operators, Domain Admins, Domain Controllers, Enterprise Admins, Enterprise Key Admins, Key Admins, Print Operators, Read-only Domain Controllers, Replicator, Schema Admins, Server Operators.
- Utilisateurs : Administrator (RID 500) et krbtgt.
Chaque exécution de SDProp :
- Lit le descripteur de sécurité de
CN=AdminSDHolder,CN=System,<domain>. - Pour chaque objet protégé et chaque membre transitif, compare l'ACL et l'écrase si elle diffère. L'héritage est désactivé sur l'objet.
- Définit
adminCount=1.
Il n'annule jamais les étapes 2 ou 3 lorsqu'un compte quitte un groupe protégé. L'émulateur PDC l'exécute toutes les 60 minutes par défaut. L'intervalle est défini par AdminSDProtectFrequency (en secondes) sous HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters.
L'imbrication compte. Un groupe de sécurité imbriqué dans Domain Admins est protégé, tout comme ses membres. Un utilisateur membre uniquement par l'affectation de son groupe principal constitue un cas limite bien connu. Vérifiez toujours l'appartenance effective, pas seulement l'attribut member.
Mesurer : établir une base de l'ACL AdminSDHolder
Exportez l'ACL actuelle et conservez-la comme un artefact signé et daté :
$dn = "CN=AdminSDHolder,CN=System," + (Get-ADDomain).DistinguishedName
$acl = Get-Acl -Path "AD:\$dn"
$acl.Sddl | Out-File "C:\Tier0\Baseline\AdminSDHolder-$(Get-Date -f yyyyMMdd).sddl"
$acl.Access | Select-Object IdentityReference, ActiveDirectoryRights, ObjectType,
InheritedObjectType, AccessControlType, IsInherited |
Sort-Object IdentityReference | Format-Table -AutoSize
$acl.OwnerComparez-la avec un domaine de laboratoire fraîchement créé, au même niveau fonctionnel et avec les mêmes produits optionnels (Exchange, par exemple, ajoute ses propres ACE). Attendez-vous à des ACE pour SYSTEM, Administrators, Domain Admins et Enterprise Admins, à un accès en lecture pour Authenticated Users et Pre-Windows 2000 Compatible Access, au droit Change Password pour Everyone et SELF, et à des droits de propriété restreints pour Cert Publishers, Windows Authorization Access Group et Terminal Server License Servers. Le propriétaire doit être Domain Admins.
Vérifiez aussi deux propriétés structurelles. L'objet AdminSDHolder a normalement l'héritage désactivé, afin que les ACE définies sur le conteneur System ou la racine du domaine ne s'y propagent pas. Si l'héritage a été activé, chaque délégation large à la racine du domaine fait partie du modèle appliqué à vos administrateurs. Vérifiez également le propriétaire. Un propriétaire peut toujours réécrire la DACL : un propriétaire non standard est donc aussi grave qu'une ACE WriteDacl. Consignez ces deux éléments dans la base, à côté du SDDL, afin que la comparaison hebdomadaire les couvre.
Tout ce qui sort de cet ensemble, en particulier GenericAll, GenericWrite, WriteDacl, WriteOwner, WriteProperty sur member ou ResetPassword (00299570-246d-11d0-a768-00aa006e0529), doit être expliqué. Un compte utilisateur ou un groupe inconnu disposant de droits d'écriture sur AdminSDHolder doit être traité comme une compromission jusqu'à preuve du contraire.
Auditer : trouver les orphelins
Construisez la liste des objets que SDProp protège actuellement, puis comparez-la à tout ce qui porte adminCount=1. Le guide de référence ne vérifie que les utilisateurs. Ici, les groupes et les ordinateurs sont inclus, et les groupes protégés sont résolus par SID bien connu afin que la requête fonctionne quelle que soit la langue :
$domSid = (Get-ADDomain).DomainSID.Value
$protectedGroupSids = @(
'S-1-5-32-544','S-1-5-32-548','S-1-5-32-549','S-1-5-32-550','S-1-5-32-551','S-1-5-32-552',
"$domSid-512","$domSid-516","$domSid-521","$domSid-526"
)
$forestRootSid = (Get-ADDomain (Get-ADForest).RootDomain).DomainSID.Value
$protectedGroupSids += "$forestRootSid-518","$forestRootSid-519","$forestRootSid-527"
$protected = [System.Collections.Generic.HashSet[string]]::new()
foreach ($sid in $protectedGroupSids) {
$g = Get-ADGroup -Filter "objectSid -eq '$sid'" -ErrorAction SilentlyContinue
if (-not $g) { continue }
[void]$protected.Add($g.DistinguishedName)
Get-ADGroupMember $g -Recursive | ForEach-Object { [void]$protected.Add($_.distinguishedName) }
# les groupes imbriqués sont aussi protégés
Get-ADGroup -LDAPFilter "(memberOf:1.2.840.113556.1.4.1941:=$($g.DistinguishedName))" |
ForEach-Object { [void]$protected.Add($_.DistinguishedName) }
}
Get-ADObject -LDAPFilter '(adminCount=1)' -Properties adminCount, objectClass, whenChanged, nTSecurityDescriptor |
Where-Object { -not $protected.Contains($_.DistinguishedName) -and $_.Name -notin 'Administrator','krbtgt' } |
Select-Object Name, objectClass, whenChanged,
@{ n = 'InheritanceBlocked'; e = { $_.nTSecurityDescriptor.AreAccessRulesProtected } },
DistinguishedNameEnterprise Admins, Schema Admins et Enterprise Key Admins résident dans le domaine racine de la forêt : c'est pourquoi leurs SID utilisent le SID du domaine racine. Dans un domaine enfant, les membres d'Enterprise Admins restent protégés, car Enterprise Admins est membre du groupe Administrators de l'enfant.
Les orphelins typiques sont d'anciens administrateurs ayant changé de fonction, des comptes de service ajoutés « temporairement » à Domain Admins, des groupes imbriqués puis retirés et, dans les domaines anciens, des comptes qui appartenaient autrefois à Account Operators ou Print Operators.
Pourquoi adminCount n'est pas un inventaire fiable des administrateurs
Il est tentant d'utiliser adminCount=1 comme liste des comptes privilégiés. C'est faux dans les deux sens. La liste inclut des orphelins, comme on vient de le voir. Elle manque aussi de vrais privilèges. Un compte disposant de GenericAll sur Domain Admins, un utilisateur détenant des droits DCSync, un membre d'un groupe qui contrôle une GPO liée à l'UO Domain Controllers et le compte de connecteur Entra Connect peuvent tous avoir le contrôle total du domaine sans jamais appartenir à un groupe protégé. SDProp n'y touche jamais : leur adminCount n'est pas défini, leur héritage est actif et ils reçoivent toutes les délégations accordées par leur UO.
Utilisez adminCount pour ce qu'il est : un indice d'appartenance passée à un groupe protégé et une file de nettoyage. Votre véritable inventaire Tier 0 découle des relations de contrôle, ce que mesure précisément l'analyse des chemins d'attaque.
Appliquer : nettoyer correctement les orphelins
Pour chaque orphelin, confirmez avec son propriétaire qu'il n'a plus besoin de privilèges. Faites ensuite trois choses ensemble, car n'en faire qu'une laisse le problème à moitié réglé :
- Réinitialisez l'ACL explicite à la valeur par défaut du schéma pour sa classe d'objet. Cela supprime les ACE copiées depuis AdminSDHolder.
- Réactivez l'héritage, afin que les délégations de niveau UO et vos ACL de hiérarchisation s'appliquent de nouveau.
- Effacez
adminCount.
$dn = (Get-ADUser 'j.smith-old-admin').DistinguishedName
# 1. Sauvegarder, puis réinitialiser au descripteur de sécurité par défaut du schéma
(Get-Acl "AD:\$dn").Sddl | Out-File "C:\Tier0\Backup\$(Get-Date -f yyyyMMdd)-j.smith.sddl"
dsacls $dn /S
# 2. S'assurer que l'héritage est actif (dsacls /S le laisse normalement actif ; on l'impose quand même)
$acl = Get-Acl "AD:\$dn"
$acl.SetAccessRuleProtection($false, $false)
Set-Acl "AD:\$dn" -AclObject $acl
# 3. Effacer le marqueur
Set-ADObject $dn -Clear adminCountChangez aussi le mot de passe du compte. Il était privilégié, et ses identifiants ont pu être mis en cache sur des systèmes hors Tier 0. Demandez-vous si le compte doit seulement continuer d'exister.
Deux mesures de durcissement supplémentaires limitent les futurs orphelins :
- Videz les groupes d'opérateurs. Account Operators, Server Operators, Print Operators et Backup Operators accordent des droits étendus sur les DC et sont protégés. Remplacez-les par une délégation ciblée sur les UO. C'est préférable à leur exclusion de SDProp via le masque
dSHeuristics. - Cessez d'utiliser des groupes protégés pour les comptes de service. Accordez plutôt les droits précis nécessaires, comme décrit dans définir le Tier 0.
Exécuter SDProp à la demande
Après avoir modifié AdminSDHolder ou fait un nettoyage, déclenchez une exécution sur l'émulateur PDC au lieu d'attendre jusqu'à une heure. Sous Windows Server 2008 R2 et versions ultérieures, écrivez l'attribut opérationnel runProtectAdminGroupsTask sur le rootDSE :
$pdc = (Get-ADDomain).PDCEmulator
$root = [ADSI]"LDAP://$pdc/RootDSE"
$root.Put('runProtectAdminGroupsTask', 1)
$root.SetInfo()Cette opération nécessite des droits Domain Admin et s'exécute de manière asynchrone.
Vérifier et surveiller
Relancez la requête sur les orphelins. Elle ne doit plus renvoyer que les comptes que vous avez explicitement acceptés. Mettez ensuite en place une surveillance continue :
- SACL sur AdminSDHolder. Ajoutez une entrée d'audit pour Everyone, en succès, sur Write all properties, Modify permissions et Modify owner pour l'objet AdminSDHolder. Avec Audit Directory Service Changes activé sur les DC, chaque modification produit un événement 5136 portant sur l'attribut
nTSecurityDescriptor. Alertez dessus avec une sévérité élevée. Les modifications légitimes doivent être rares et associées à un ticket. - Comparaison planifiée. Une tâche hebdomadaire compare le SDDL en production au fichier de base et ouvre un ticket à la moindre différence. Cela détecte aussi les modifications faites pendant que l'audit était désactivé.
- Dérive d'adminCount. Alertez sur l'événement 5136 lorsque
adminCountest défini sur un objet hors de votre liste Tier 0 approuvée. Cela signale que quelqu'un a été ajouté à un groupe protégé, même brièvement, et se corrèle avec les événements de modification de groupe 4728, 4732 et 4756.
Microsoft Defender for Identity et PingCastle signalent eux aussi les anomalies d'AdminSDHolder. Utilisez-les comme contrôles croisés, pas comme unique contrôle.
Ce que cela casse
- Les réinitialisations de mot de passe par le support sur les anciens administrateurs. Tant qu'un compte est protégé, SDProp bloque les délégations d'UO héritées, et le support ne peut donc pas réinitialiser son mot de passe. C'est voulu. Le nettoyage inverse cela : une fois l'héritage réactivé, les délégations d'UO s'appliquent de nouveau et le support peut réinitialiser le mot de passe de l'ancien administrateur. Vérifiez que c'est bien ce que vous souhaitez avant de réinitialiser l'ACL d'un compte sensible.
- Les ACE personnalisées placées directement sur les comptes d'administration. SDProp les avait déjà écrasées ; les outils qui en dépendaient étaient donc déjà cassés. La réinitialisation ne fait que le rendre visible.
- Les applications qui se sont accordé des droits via AdminSDHolder, par exemple certains anciens produits de gestion des identités ou de PAM. Retirer d'AdminSDHolder des ACE inexpliquées retire ces droits à tous les administrateurs à la prochaine exécution de SDProp. Confirmez d'abord avec l'éditeur.
- Les modifications de dSHeuristics. Si quelqu'un avait défini le masque d'exclusion, le retirer protège de nouveau les groupes d'opérateurs et leurs membres, et les délégations qui reposaient sur l'exclusion cessent de fonctionner.
Pour aller plus loin : le guide de référence sur les ACL, trouver les droits DCSync pour l'ACL de la racine du domaine, gestion des chemins d'attaque pour voir où mènent encore les droits orphelins, et le guide de référence Tier 0 pour l'usage attendu des comptes protégés.
Questions fréquentes
Peut-on raccourcir l'intervalle de SDProp ?
Oui, avec la valeur DWORD AdminSDProtectFrequency (en secondes, de 60 à 7200) sous HKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters sur l'émulateur PDC. Microsoft déconseille de la modifier en production, car chaque exécution peut générer une charge importante de réplication et de LSASS dans les grands domaines. Pour un test ou après un nettoyage, déclenchez plutôt une exécution unique via l'opération rootDSE runProtectAdminGroupsTask.
Pourquoi effacer adminCount ne rétablit-il pas les autorisations normales ?
Parce qu'adminCount n'est qu'un marqueur. Lorsque SDProp a protégé le compte, il a aussi désactivé l'héritage de l'ACL et y a copié l'ACL d'AdminSDHolder. Effacer adminCount ne change ni l'un ni l'autre. Vous devez aussi réactiver l'héritage et, idéalement, réinitialiser les ACE explicites à la valeur par défaut du schéma, afin que le compte récupère les délégations de l'UO et perde les entrées privilégiées résiduelles.
Faut-il exclure Account Operators ou Backup Operators de SDProp via dSHeuristics ?
Presque jamais. Le masque d'exclusion de dSHeuristics existe pour permettre de déléguer ces groupes d'opérateurs dans des scénarios inhabituels, mais il retire la protection à des groupes qui peuvent déjà atteindre le contrôle du domaine. La meilleure solution est de vider Account Operators, Server Operators, Print Operators et Backup Operators, de les remplacer par des délégations ciblées et de laisser SDProp les protéger.
AdminSDHolder et SDProp : nettoyage et surveillance