Vulnérabilité

Etat de l’art de la compromission d’un environnement AD CS - Partie 1

-
Cet article a 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.OWN Security

Partie 1 – Introduction & ESC1

Introduction

La cybersécurité c’est un peu comme un jeu du chat et de la souris sauf que ça coûte cher et ça fait peur.

Pourquoi ? Parce que d’un côté on découvre régulièrement de nouvelles attaques qui font l’objet de publications et qui introduisent de nouvelles méthodes de compromission et de l’autre on se sensibilise à ces nouvelles attaques en espérant que la prochaine ne sera pas découverte à 17h le vendredi.

Or, en juin 2021 (un jeudi, c’est pas trop mal), 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 plusieurs années soient passées, 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.

L’intérêt de cibler AD CS

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 AD Windows dans des entreprises à 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 patch à déployer et les failles peuvent être longtemps exploitables pourvu que les équipes techniques n’y soient pas sensibilisées.

De plus, certaines des vulnérabilités mentionnées plus loin permettent dans le pire des cas de compromettre l’intégralité d’un domaine depuis un simple accès au réseau !

Il m’est même arrivé lors d’un audit de pouvoir compromettre le domaine depuis une prise Ethernet sans avoir à contourner leNAC 802.1X, c’est pour dire.

Rappel, connaissances requises & prérequis

Rappel : AD CS dans un environnement Windows

On va commencer par un petit rappel sur AD CS. La plupart des infos ici viennent directement du papier de SpecterOps qui a fait un travail de recherche phénoménal. 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 WindowsServer 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 trop rentrer dans les détails.

Figure 1. Structure d'un certificat X.509. Source : Framework for a ubiquitous PKI

Un certificat au format X.509 est donc 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 qui vont élargir les fonctionnalités du certificat, par exemple un champ Extended Key Usage qui décrit les utilisations possibles du certificat en question.

Les certificats ayant un grand nombre d’applications, par exemple permettre à tout utilisateur de se connecter via une « smart card » ou à un utilisateur privilégié de signer du code, 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 donc une structure de certificat proposée par une autorité de certification hébergée sur un AD CS. Il définit untype de certificat, les actions qu’il est possible d’effectuer avec ainsi quel es utilisateurs autorisés à en demander un. Cela permet donc à un utilisateur de demander un certificat en envoyant une requête sur un modèle particulier et facilite donc grandement l’enrôlement.

Rappel : 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 KeyUsage correspondant à Client Authentication).

Il existe deux protocoles supportant l’authentification par certificat et il est intéressant de les connaître a finde pouvoir s’adapter lors d’un test d’intrusion.

Kerberos

Pour rappel, l’authentification Kerberos classique fonctionne en suivant les étapes suivantes :

  • Le client demande un ticket d’authentification(TGT) au Key Distribution Center (KDC) qui est généralement un contrôleur de domaine.
  • Le KDC vérifie les identifiants du client et renvoie un TGT chiffré avec la clef privée du Ticket Granting Service (TGS), le service utilisé pour délivrer les TGT.
  • Le client envoie ensuite le TGT chiffré ainsi qu’un nom de ressource au TGS lorsqu’il veut accéder à ladite ressource
  • Le KDC vérifie la validité du TGT et vérifie que l’utilisateur possède bien les droits d’accès à la ressource.
  • Si tout est bon, le KDC délivre une clef de session que le client peut utiliser pour s’authentifier auprès de la ressource.

De façon simplifiée, la première phase d’obtention du TGT s’appelle la pré-authentification et peut se faire soit via une clef symétrique (p.e. les identifiants du client), soit via un certificat X.509 à travers un mécanisme qui s’appelle PKINIT. C’est donc cette fonctionnalité qui peut être abusée dans le cadre d’attaques sur AD CS car si j’obtiens un certificat valide pour un autre utilisateur, je peux m’authentifier auprès duKDC et obtenir des accès à des ressources sensibles.

SChannel

Schannel est un protocole bien plus simple basé surSSL/TLS qui nécessite l’envoi d’un certificat au serveur. Pour faire simple, Schannel vérifie différents magasins de certificats présents sur la machine du client pour tenter de le transmettre au service concerné. La vérification du certificat n’est ensuite pas effectuée par le protocole et doit donc être implémentée par le serveur ciblé. 

LDAP over SSL peut par exemple supporter l’authentification via le protocole SChannel et peut être utilisé pour compromettre un domaine lorsque l’authentification Kerberos ne marche pas comme nous verrons dans la partie Compromission via SChannel.

Mapping des certificats

Sous ce nom un peu barbare se cache le procédé selon lequel le service d’authentification associe un certificat à un utilisateur du domaine après avoir vérifié sa validité. Kerberos et SChannel s’y prennent de plusieurs façons différentes et il convient de faire un rappel ici car certaines vulnérabilités exploitent ces procédés. 

Il existe deux types de mapping différents :les mappings explicites et les mappings implicites.

Pour les mappings explicites, une vérification est faite sur la propriété altSecurityIdentities du compte essayant de s’authentifier. Cette propriété peut contenir des informations permettant d’identifier les certificats rattachés au compte.

Ainsi, lorsqu’une tentative d’authentification par certificat est faite via un mapping explicite, la validité de ce dernier est vérifiée et son identifiant est comparé à la valeur de la propriété altSecurityIdentities de l’utilisateur essayant de se connecter. Si l’identifiant du certificat y est, l’authentification est réussie.

Pour les mappings implicites, c’est le champ Subject Alternative Name du certificat qui est vérifié. L’identité liée au certificat est donc extraite et comparée aux champs UPN (pour les utilisateurs)ou DNS (pour les machines) des objets présents sur le domaine.

Pour plus de détails > [MS-PKCA]:Certificate Mapping | Microsoft Learn

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 ! Ce module Python reprend l’outil Certify.exe initialement développé par SpecterOps 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.

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…Elles permettent généralement d’obtenir un certificat valide au nom d’un utilisateur autre que le sien.

 Nous allons donc à terme passer sur chacune de ces vulnérabilités une à une. Cette première partie va cependant se concentrer surESC1 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 identifier un éventuel serveur AD CS, lister les modèles de certificat et identifier ceux qui sont vulnérables ? Accrochez-vous, on y vient.

Identifier un éventuel serveur AD CS

Imaginons un instant. Je démarre un audit interne, j’ai effectué ma reconnaissance initiale, mon client n’a pas de contrôle d’accès au réseau (puisque c’est mon imagination et je fais ce que je veux) et je cherche désormais le moyen le plus rapide de compromettre le domaine histoire d’impressionner les collègues.

Bon, ils sont à jour donc il va falloir réfléchir un peu plus et ranger les scripts ZeroLogon/EternalBlue… Par contre j’ai lu un article super intéressant sur AD CS, je vais essayer ça !

Continuons d’imaginer deux cas de figure différents :

  • Je ne possède pas de compte sur le domaine :

o  Sans compte sur le domaine, une première solution est de chercher manuellement via une reconnaissance initiale sur le réseau. Par exemple, je lance nmap avec l’option -sL pour effectuer un scan reverse-DNS pour potentiellement récupérer des noms d’hôtes de serveur et si je trouve un serveur qui s’appelle adcs.domaine ou pki.domain, j’ai de grandes chances de l’avoir trouvé !

o  Une deuxième solution, et quelque peu plus élégante, est de passer par un relai NTLM (note de bas de page, lien vers Hackndo). En effet, l’outil Impacket ntlmrelayx.py propose une option –dump-adcslors d’un relai vers LDAP qui permet de récupérer toutes les informations intéressantes.

  • Je possède un compte sur le domaine :

o  Dans ce cas-là, rien de plus simple ! Certipy me permet de contacter automatiquement l’AD CS lorsque je vais lister les modèles de certificat. Nous allons voir ça juste après.

OK, j’ai identifié si oui ou non AD CS est déployé sur le réseau et si j’y ai accès depuis mon sous-réseau. Il s’agit maintenant de lister les modèles de certificats pour savoir si oui ou non je vais pouvoir battre mon record de 15 minutes pour devenir admin du domaine.

Récupération et analyse des modèles de certificat

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. Si on n’a pas de compte, on peut donc passer par le relaiNTLM que j’ai mentionné précédemment qui permet de récupérer les modèles très facilement. On peut également passer par l’option -sspi de Certipy si on l’exécute 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 que l’on a compromis.

Sinon, 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 se faire, la commande classique est la suivante :

Certipy find -u <utilisateur>@<domaine> -p <mot de passe> -target <DNS/IP de l’AD>

Les options supplémentaires qui peuvent être intéressantes sont :

  •  -scheme ldap : si LDAPS n’est pas supporté, passe par LDAP
  •  -stdout/bloodhound/old-bloodhound : Par défaut, Certipy créé des fichiers avec les infos. Ces options permettent respectivement de sortir les informations dans le terminal, dans un format compatible avec ce fork de bloodhound (lien) qui permet de visualiser des défauts de configuration liés à la PKI ou dans un format compatible avec Bloodhound classique.
  • -vulnerable : Cette option permet de filtrer les modèles de certificats qui ne sont pas vulnérables selon Certipy. Attention aux faux négatifs ! Si votre utilisateur fait partie d’un groupe non-privilégié mais non-standard qui peut demander des certificats sensibles, Certipy pourrait ne pas relever la faille.
  •  -enabled : Cette option filtre les modèles de certificats désactivés, ça permet d’éviter les faux espoirs !
  •  -debug : Si quelque chose cloche, on saura pourquoi !

Maintenant qu’on a 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.

 

Paramètres d’un modèle de certificat

Encore 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.
  • A 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 KeyUsages 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). Pour en savoir plus sur ces protections, voir à la fin de l’article dans la section « Détection et défense »
  • Enfin, certains autres paramètres que nous verrons plus tard définissent des autorisations et restrictions additionnelles sur la demande de certificat.

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. Par exemple, l’ACL WriteDACL (ou un truc du genre) permet à l’utilisateur de modifier les paramètres du modèle de certificat.

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 webenrollment (plus d’informations là-dessus dans la partie 2 quand on mentionnera ESC8 😉).

ESC1

Directement, on attaque avec une des vulnérabilités les plus brutales. Si l’on se rappelle les différents paramètres d’un modèle de certificat mentionnés avant, 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é decertification 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 ExtendedKey Usages). 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 flagCT_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 un champ qui s’appelle le subjectAltName (ou SAN).

A nouveau, rien de très grave et.. ah bah si en fait.

 Pas besoin de vous faire un dessin pour comprendre le problème mais j’ai quand même décidé d’en faire un pour bien que vous preniez conscience du souci.

Et là je sais ce que vous pensez :« D’accord mais ça n’arrive jamais, personne n’activerait cette option-là ».Eh bien 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 !

Voici un exemple de modèle de certificat vulnérable tel que découvert via Certipy :

Template Name ESC1
Display Name ESC1
Certificate Authorities ESSOS-CA
Enabled True
Client Authentication True
Enrollment Agent False
Any Purpose False
Enrollee Supplies Subject True
Certificate Name Flag EnrolleeSuppliesSubject
Enrollment Flag None
Private Key Flag 16777216
Extended Key Usage Client Authentication
Requires Manager Approval False
Requires Key Archival False
Authorized Signatures Required 0
Validity Period 1 year
Renewal Period 6 weeks
Enrollment Rights ESSOS.LOCAL\Domain Users
Owner ESSOS.LOCAL\Enterprise Admins
Full Control Principals ESSOS.LOCAL\Domain Admins
ESSOS.LOCAL\Local System
Write Owner Principals ESSOS.LOCAL\Domain Admins
ESSOS.LOCAL\Local System
Write Dacl Principals ESSOS.LOCAL\Domain Admins
ESSOS.LOCAL\Local System
Write Property Principals ESSOS.LOCAL\Domain Admins
ESSOS.LOCAL\Local System
[!] Vulnerabilities 'ESSOS.LOCAL\Domain Users' can enroll, enrollee supplies subject and template allows client authentication en

Comme on peut le voir, l’outil est 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é.

Figure 2- La meilleure surprise qu'on puisse avoir en pentest

Maintenant qu’on a déterminé que le modèle est activé et vulnérable comment l’exploiter ? Avec Certipy toujours ! Et ce en une seule ligne :

PS : Les différentes exploitations partent du principe que vous possédez déjà un compte valide sur le domaine mais je vous invite à creuser ntlmrelayx.py qui propose l’exploitation de ces vulnérabilités via un simple relai rpc.

Certipy req -u <utilisateur>@<domaine> -p <mot de passe> -target <DNS/IP de l’AD CS> -ca <Autorité de certification proposant le modèle vulnérable> -template <nom du modèle vulnérable> -upn <L’utilisateur pour lequel on veut le certificat>@<domaine>

Note : attention, il peut être nécessaire d’affiner votre commande, par exemple en spécifiant l’IP du DC si la commande n’y arrive pas d’elle-même

Et voilà, vous avez le certificat du compte de votre choix au format pfx! Nous allons donc voir ce qu’il est maintenant possible de faire avec.

Utilisation d’un certificat

Bon, trêve de plaisanteries maintenant. On a travaillé dur et on a obtenu un certificat d’administrateur ou de 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.

Compromission via Kerberos

Dans ce cas de figure, imaginons que nous avons obtenu un certificat administrateur.pfx permettant de s’authentifier entant qu’administrateur@domaine.local. Je n’ai plus qu’à sortir Certipy et utiliser la commande suivante :

certipy auth -pfx <chemin vers le certificat> -username administrateur -domain domaine.local -dc-ip <devine>

Et là, Certipy fait un tour de magie et transforme votre certificat un peu ennuyeux en hash NT beaucoup plus fun[1]en plus de récupérer le TGT, plus qu’à faire votre plus beau Pass-the-Hash avec CrackMapExec de la façon suivante :

cme smb <IP du DC> -u administrateur -H <hash> -d domaine.local –ntds

On aurait 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 pour faire un DCSync et dump NTDS si le dump classique via crackmapexec est bloqué.

Bon, je ne veux pas ruiner l’ambiance mais il s’avère que parfois l’authentification par certificat ne marche pas avecKerberos…

Mais pas de panique, rappelez-vous qu’il y a également SChannel !

Compromission via SChannel

Pour exploiter SChannel, le plus simple est de compromettre le certificat d’un compte ayant des droits de réplication sur le contrôleur de domaine, comme par exemple le compte machine du DC. Imaginons donc cette fois-ci que je possède le certificat DC.pfx.

Comme d’habitude, je fais chauffer Certipy mais cette fois-ci, j’ajoute l’option --ldap-shell :

certipy auth -pfx <chemin vers le certificat> -username DC$ -domain domaine.local -dc-ip <devine encore> --ldap-shell

L’option --ldap-shell étant bien nommée, nous obtenons ainsi un shell LDAP sur le DC. Ce n’est par contre pas n’importe quel shell, des commandes sont disponibles pour faciliter la compromission du domaine ! Un petit help nous révèle ces fameuses commandes :

Celle qui nous intéresse ici est la commande set_rbcd qui permet de configurer un compte machine que nous possédons (ou que vous venez de créer sur votre shell ldap via la commande add_computer <nom><mot de passe>) afin de l’autoriser à faire une Resource BasedConstrained Delegation (RBCD).

Pour ceux qui ne savent pas, une RBCD permet à un compte non-privilégié d’obtenir un ST en tant qu’un autre utilisateur pour s’identifier sur un serveur, Pixis l’explique très bien sur son blog : https://beta.hackndo.com/resource-based-constrained-delegation-attack.

getST.py -spn cifs/DC.domaine.local -impersonate DC -dc-ip <IP du… DC> domaine.local/<votre compte machine>:<mot de passe du compte>

Ce ticket de service peut ensuite être utilisé pour effectuer des actions en tant que DC$. On exploite donc son droit de réplication pour faire une attaque de DCSync[2]avec le script secretsdump.py d’Impacket. Attention, il faut au préalable pouvoir lui transmettre le ST précédemment obtenu en définissant la variable d’environnement KRB5CCNAME :

export KRB5CCNAME=DC$.ccache

Maintenant, plus qu’à récupérer le butin :

secretsdump.py -k -no-pass DC.domaine.local

Dans la prochaine partie, nous étudierons plus en détails les vulnérabilités d’ESC2 jusqu’à ESC8 qui apportent leur lot de belles découvertes et de belles pistes à étudier lors de vos audits

Note de bas de page

[1] Vous trouvez ça étrange ? C’est normal. La méthode utilisée sous le capot est UnPAC-the-Hash qui est très bien expliquée ici : https://thehacker.recipes/ad/movement/kerberos/unpac-the-hash

[2] DCSync- The Hacker Recipes

Partager l'article :

Your OWN cyber expert.