Auditer les modèles de certificats AD CS (ESC1-ESC4)
Auditer chaque modèle de certificat AD CS pour ESC1-ESC4 : drapeaux de sujet, EKU, droits d'inscription et ACL des modèles, avec PowerShell et un ordre de correction sûr.
La plupart des compromissions AD CS n'ont pas besoin d'un bogue. Elles ont besoin d'un seul modèle de certificat qui permet à un utilisateur à faibles privilèges d'écrire le sujet de son propre certificat, ou d'une seule ACL de modèle qui permet à cet utilisateur de réécrire le modèle jusqu'à obtenir ce résultat. Les classes ESC1 à ESC4 sont toutes des problèmes au niveau des modèles, ce qui les rend auditables depuis LDAP uniquement : chaque paramètre pertinent est un attribut d'un objet pKICertificateTemplate dans la partition de configuration, et chaque droit d'inscription est une ACE sur ce même objet.
Le pilier de durcissement AD CS explique chaque classe ESC de manière conceptuelle. Ce guide en est la procédure d'audit : établir l'inventaire des modèles publiés, évaluer chacun selon les quatre dimensions de risque (contrôle du sujet, EKU d'authentification, qui peut s'inscrire, qui peut écrire), les corriger dans un ordre sûr et vérifier le résultat. Les paramètres propres à l'AC, comme EDITF_ATTRIBUTESUBJECTALTNAME2 et l'inscription web, sont traités séparément dans sécuriser l'inscription web AD CS.
Mesurer : inventorier les modèles et leurs lieux de publication
Un modèle n'a d'importance pour l'inscription qu'une fois publié par une AC : la première étape consiste donc à séparer les modèles publiés de la trentaine de modèles par défaut qui dorment dans l'annuaire. Les noms des modèles publiés sont stockés dans l'attribut certificateTemplates de l'objet pKIEnrollmentService de chaque AC.
$configNC = (Get-ADRootDSE).configurationNamingContext
$pks = "CN=Public Key Services,CN=Services,$configNC"
$tplBase = "CN=Certificate Templates,$pks"
$caBase = "CN=Enrollment Services,$pks"
# Quelle AC publie quel modèle
Get-ADObject -SearchBase $caBase -LDAPFilter '(objectClass=pKIEnrollmentService)' `
-Properties dNSHostName, certificateTemplates |
ForEach-Object {
foreach ($t in $_.certificateTemplates) {
[pscustomobject]@{ CA = $_.Name; Host = $_.dNSHostName; Template = $t }
}
} | Sort-Object Template | Format-Table -AutoSizeConservez cette sortie. C'est aussi la liste de vos AC d'entreprise, qui ont leur place dans votre inventaire Tier 0 aux côtés des contrôleurs de domaine.
Auditer : évaluer chaque modèle sur le sujet, l'EKU et l'approbation
Quatre attributs déterminent si un modèle peut servir à usurper une identité :
| Attribut | Ce qu'il faut rechercher |
|---|---|
msPKI-Certificate-Name-Flag | 0x1 (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT) : le demandeur écrit le sujet et le SAN |
pKIExtendedKeyUsage / msPKI-Certificate-Application-Policy | Client Authentication (1.3.6.1.5.5.7.3.2), Smart Card Logon (1.3.6.1.4.1.311.20.2.2), PKINIT Client Authentication (1.3.6.1.5.2.3.4), Any Purpose (2.5.29.37.0), ou aucun EKU |
msPKI-Enrollment-Flag | 0x2 (CT_FLAG_PEND_ALL_REQUESTS) : approbation du gestionnaire de certificats de l'AC requise |
msPKI-RA-Signature | Nombre de signatures autorisées (cosignature par un agent d'inscription) requises |
Le script ci-dessous les combine avec les données de publication. Un modèle sans EKU est considéré comme utilisable pour l'authentification, car un certificat sans restriction d'EKU est valide pour tout usage (le cas ESC2).
$published = Get-ADObject -SearchBase $caBase -LDAPFilter '(objectClass=pKIEnrollmentService)' `
-Properties certificateTemplates | ForEach-Object { $_.certificateTemplates } | Sort-Object -Unique
$authEku = '1.3.6.1.5.5.7.3.2','1.3.6.1.4.1.311.20.2.2','1.3.6.1.5.2.3.4','2.5.29.37.0'
$agentEku = '1.3.6.1.4.1.311.20.2.1' # Certificate Request Agent (ESC3)
Get-ADObject -SearchBase $tplBase -LDAPFilter '(objectClass=pKICertificateTemplate)' -Properties `
'msPKI-Certificate-Name-Flag','msPKI-Enrollment-Flag','msPKI-RA-Signature',
'pKIExtendedKeyUsage','msPKI-Certificate-Application-Policy','msPKI-Template-Schema-Version' |
ForEach-Object {
$eku = @($_.pKIExtendedKeyUsage) + @($_.'msPKI-Certificate-Application-Policy') |
Where-Object { $_ } | Sort-Object -Unique
[pscustomobject]@{
Template = $_.Name
Published = $published -contains $_.Name
Schema = $_.'msPKI-Template-Schema-Version'
SuppliesSubject = [bool]($_.'msPKI-Certificate-Name-Flag' -band 0x1)
AuthCapable = ($eku.Count -eq 0) -or [bool]($eku | Where-Object { $_ -in $authEku })
RequestAgent = [bool]($eku -contains $agentEku)
ManagerApproval = [bool]($_.'msPKI-Enrollment-Flag' -band 0x2)
RASignatures = [int]$_.'msPKI-RA-Signature'
EKUs = $eku -join ', '
}
} | Where-Object Published | Sort-Object SuppliesSubject, AuthCapable -Descending | Format-Table -AutoSizeLisez la sortie ainsi. SuppliesSubject et AuthCapable tous deux à true, sans approbation ni signature RA : c'est un candidat ESC1 typique, dont l'exploitabilité dépend uniquement de qui peut s'inscrire. RequestAgent à true signale un candidat ESC3. Une colonne EKUs vide sur un modèle publié correspond à ESC2.
Deux cas particuliers méritent une remarque. D'abord, les modèles de schéma version 1 (comme le modèle intégré WebServer) qui autorisent un sujet fourni étaient à la base d'ESC15 (CVE-2024-49019), où des stratégies d'application pouvaient être injectées dans la demande ; la mise à jour de sécurité de novembre 2024 a corrigé ce problème côté AC : vérifiez donc que vos AC sont à jour et dupliquez les modèles v1 en versions v2+ que vous contrôlez. Ensuite, les modèles dont la stratégie d'émission est liée à un groupe AD via msDS-OIDToGroupLink (ESC13) confèrent l'appartenance à ce groupe à quiconque détient le certificat : examinez donc tous les objets OID de stratégie d'émission qui portent cet attribut.
Auditer : droits d'inscription et ACL des modèles
L'inscription est un droit étendu sur l'objet modèle : Certificate-Enrollment (0e10c968-78fb-11d2-90d4-00c04f79dc55) et Certificate-AutoEnrollment (a05b8cc2-17bc-4802-a710-e7c15ab866a2). GenericAll accorde aussi l'inscription. Les droits d'écriture (WriteProperty, WriteDacl, WriteOwner, GenericWrite, GenericAll) sur le modèle relèvent d'ESC4 : leur détenteur peut activer le drapeau de sujet.
$rightNames = @{
'0e10c968-78fb-11d2-90d4-00c04f79dc55' = 'Enroll'
'a05b8cc2-17bc-4802-a710-e7c15ab866a2' = 'AutoEnroll'
'00000000-0000-0000-0000-000000000000' = 'AllExtendedRights'
}
$broad = '(^|\\)(Everyone|Authenticated Users|Domain Users|Domain Computers|Users)$'
$expected = '(^|\\)(Domain Admins|Enterprise Admins|SYSTEM)$'
Get-ADObject -SearchBase $tplBase -LDAPFilter '(objectClass=pKICertificateTemplate)' |
ForEach-Object {
$tpl = $_
(Get-Acl -Path "AD:\$($tpl.DistinguishedName)").Access |
Where-Object { $_.AccessControlType -eq 'Allow' -and $_.IdentityReference.Value -notmatch $expected } |
ForEach-Object {
$r = $_.ActiveDirectoryRights.ToString()
$kind = if ($r -match 'GenericAll|GenericWrite|WriteDacl|WriteOwner|WriteProperty') { 'WRITE (ESC4)' }
elseif ($r -match 'ExtendedRight') { $rightNames[$_.ObjectType.ToString()] }
if ($kind) {
[pscustomobject]@{
Template = $tpl.Name
Published = $published -contains $tpl.Name
Trustee = $_.IdentityReference.Value
Right = $kind
Broad = $_.IdentityReference.Value -match $broad
}
}
}
} | Sort-Object Published, Right -Descending | Format-Table -AutoSizeCroisez les deux sorties. La liste prioritaire comprend tout modèle publié utilisable pour l'authentification, qui fournit le sujet ou émet des certificats d'agent de demande, et dont un droit Enroll a Broad à true. Juste derrière vient toute ligne WRITE (ESC4) pour un mandataire non administrateur, publié ou non, car un accès en écriture à un modèle est un ESC1 latent qui n'attend que d'être exploité. N'oubliez pas les conteneurs eux-mêmes : un accès en écriture sur CN=Certificate Templates, CN=Enrollment Services ou l'objet NTAuthCertificates relève d'ESC5 et appartient à la même revue, comme décrit dans auditer les ACL AD.
Recouper avec Locksmith et PSPKIAudit
Deux outils PowerShell orientés défense valent la peine d'être exécutés en complément de vos propres scripts. Locksmith (Invoke-Locksmith) signale ESC1-ESC8 et plusieurs classes plus récentes dans son mode par défaut, et peut générer des scripts de correction ; examinez ses modes avant d'exécuter ceux qui corrigent. PSPKIAudit s'appuie sur le module PSPKI et ajoute l'analyse des certificats émis. Des outils offensifs comme Certify et Certipy énumèrent les mêmes données ; si votre red team les utilise, comparez leurs résultats à votre inventaire au lieu de considérer l'un ou l'autre comme faisant autorité. Pour une vue en graphe de qui peut atteindre un droit d'inscription via des groupes imbriqués, voir la gestion des chemins d'attaque avec BloodHound.
Imposer : corriger dans l'ordre le moins perturbant
Traitez les constats dans cet ordre, qui supprime le plus de risque par changement tout en cassant le moins de flux.
- Dépublier les modèles que personne n'utilise. Vérifiez d'abord dans la base de données de l'AC les émissions récentes par modèle (voir Vérifier ci-dessous). La dépublication est instantanée et réversible :
# Sur l'AC (module ADCSAdministration)
Get-CATemplate | Sort-Object Name
Remove-CATemplate -Name 'LegacyVPNUser' -Force- Supprimer les droits d'inscription larges. Remplacez Domain Users ou Authenticated Users sur les modèles sensibles par un groupe dédié qui ne contient que les comptes ou ordinateurs qui ont besoin du certificat. Conservez le droit Read pour Authenticated Users afin que l'inscription automatique puisse toujours découvrir les modèles.
- Supprimer le drapeau de sujet fourni. Dans la console Modèles de certificats (
certtmpl.msc), ouvrez le modèle, allez dans l'onglet Subject Name et sélectionnez « Build from this Active Directory information ». La console positionne correctement les drapeaux de sujet et de SAN correspondants, ce qui est plus sûr que de modifier le masque de bits directement. Lorsqu'un sujet fourni est un vrai besoin (certificats de serveur web demandés par un système de provisionnement), retirez les EKU d'authentification client de ce modèle et limitez l'inscription au service de provisionnement. - Ajouter une approbation ou des signatures RA sur les modèles qui doivent conserver un sujet fourni en même temps qu'un EKU d'authentification. Dans l'onglet Issuance Requirements, cochez « CA certificate manager approval ».
- Retirer les droits d'écriture à tout mandataire autre qu'un administrateur PKI et redéfinir le propriétaire du modèle sur Enterprise Admins ou votre groupe d'administrateurs PKI.
- Restreindre les agents d'inscription. Dans l'onglet Enrollment Agents de l'AC, limitez chaque agent à des modèles et groupes cibles nommés, au lieu du réglage par défaut « tout le monde, tous les modèles ».
Les modifications des objets modèles se répliquent via la partition de configuration comme n'importe quelle autre modification AD : effectuez-les sur un DC et laissez la réplication les propager.
Vérifier
Relancez les deux scripts d'audit : aucun modèle publié utilisable pour l'authentification ne doit cumuler SuppliesSubject et un droit Enroll Broad, et aucune ligne WRITE (ESC4) ne doit subsister pour des mandataires non administrateurs.
Confirmez qui utilise réellement un modèle avant et après chaque changement, à partir de la base de données de l'AC :
# Certificats émis à partir d'un modèle au cours des 90 derniers jours (à exécuter sur l'AC)
$since = (Get-Date).AddDays(-90).ToString('MM/dd/yyyy')
certutil -view -restrict "Disposition=20,NotBefore>=$since" `
-out "RequestID,RequesterName,CommonName,CertificateTemplate,NotBefore" csv > issued-90d.csvCertificateTemplate est enregistré sous forme d'OID du modèle pour les modèles v2+ ; faites la correspondance avec la sortie de certutil -template. Activez ensuite l'audit des modifications de modèles pour rendre les dérives visibles. EDITF_AUDITCERTTEMPLATELOAD fait journaliser par l'AC l'événement 4898 lorsqu'elle charge un modèle et 4899 lorsqu'un modèle a changé, et une SACL sur le conteneur Certificate Templates vous fournit des événements 5136 indiquant l'attribut modifié :
certutil -setreg policy\EditFlags +EDITF_AUDITCERTTEMPLATELOAD
Restart-Service certsvcTransférez les événements 4886, 4887, 4899 et 5136 vers votre SIEM et alertez lorsqu'un certificat est émis avec un SAN qui ne correspond pas au demandeur. Le pilier audit et détection couvre le volet collecte.
Ce qui casse
- Dépublier un modèle : les certificats existants restent valides jusqu'à leur expiration, mais le renouvellement échoue. Les machines en inscription automatique journaliseront des erreurs d'inscription dans le journal Application (source CertificateServicesClient-AutoEnrollment) lorsqu'elles tenteront de renouveler : vérifiez ce journal sur un échantillon de clients après chaque changement.
- Retirer l'inscription de Domain Users ou Domain Computers : l'inscription automatique s'arrête silencieusement pour quiconque ne figure pas dans le nouveau groupe. Alimentez le groupe de remplacement avant de supprimer l'ancienne ACE, pas après.
- Supprimer le drapeau de sujet fourni : les systèmes de provisionnement, connecteurs MDM, répartiteurs de charge et scripts qui soumettent un CSR avec leur propre sujet obtiendront à la place des certificats avec le sujet dérivé d'AD, ou échoueront purement et simplement. Donnez-leur un modèle dédié sans EKU d'authentification client.
- Approbation du gestionnaire : les demandes restent en attente jusqu'à l'intervention d'un gestionnaire de certificats, ce qui casse l'inscription sans surveillance. Ne l'utilisez que sur des modèles à faible volume.
- Restreindre les agents d'inscription : le personnel chargé du provisionnement des cartes à puce ne peut inscrire que pour les modèles et groupes listés ; les nouveaux types de cartes nécessitent donc une modification de la configuration de l'AC.
Pour aller plus loin : le thème Services de certificats AD, le mappage fort des certificats pour le volet KDC de l'authentification par certificat, et la gestion des chemins d'attaque pour identifier qui peut atteindre indirectement un droit d'inscription.
Questions fréquentes
Un modèle de certificat non publié pose-t-il encore problème ?
Ses paramètres n'ont pas d'importance tant qu'aucune AC ne le publie, car personne ne peut s'inscrire sur un modèle qu'aucune AC ne propose. Son ACL, en revanche, compte toujours : quiconque dispose d'un accès en écriture peut le modifier, et quiconque détient les droits Manage CA peut le publier. Traitez les modèles non publiés comme peu prioritaires pour la correction des drapeaux, mais nettoyez quand même les droits d'écriture, et supprimez les modèles que vous n'utiliserez jamais.
L'approbation du gestionnaire suffit-elle à neutraliser un modèle ESC1 ?
Elle transforme le modèle en flux contrôlé plutôt qu'ouvert, ce qui constitue un progrès important, mais elle ne vaut que ce que valent les approbateurs. Un gestionnaire de certificats qui approuve les demandes sans lire le SAN demandé émettra quand même un certificat de Domain Admin. Préférez supprimer le drapeau « enrollee supplies subject » et utilisez l'approbation comme seconde couche sur les modèles qui ont réellement besoin d'un sujet fourni.
Faut-il exécuter Certify ou Certipy en production ?
Les deux sont en lecture seule dans leurs modes d'énumération, mais ce sont des outils offensifs susceptibles de déclencher des alertes EDR. Pour un audit défensif, Locksmith et PSPKIAudit sont conçus pour les administrateurs, et le PowerShell natif de ce guide couvre les mêmes contrôles de modèles. Si vous exécutez un outil offensif, faites-le depuis un hôte approuvé, avec la gestion des changements informée, et comparez les résultats avec votre propre inventaire.
Auditer les modèles de certificats AD CS (ESC1-ESC4)