Pentest d’un lab Active Directory : de test:test à Domain Admin
J’ai passé plusieurs de jours à monter un lab Active Directory vulnérable sur mon Proxmox, puis à le pentester de A à Z. Les techniques utilisées ici sont toutes classiques et très bien documentées. Ce qui m’intéressait, c’était d’enchaîner la chaîne d’attaque complète du début à la fin, du scan initial jusqu’au shell SYSTEM sur le DC, en me forçant à comprendre chaque étape plutôt que de courir après une flag.
Ce post raconte le déroulé complet. Les commandes sont dans l’article quand elles ont compté ; le script de déploiement du lab et les notes brutes sont sur GitHub.
Pourquoi ce projet
Dans le cadre de ma reconversion vers la cyber, j’alterne entre des modules théoriques (AD, Kerberos, NTLM) et de la pratique sur des plateformes type HTB ou TryHackMe. Le problème des plateformes, c’est qu’on finit vite par reconnaître les patterns et à chercher la flag plutôt qu’à comprendre le pourquoi. Je voulais un environnement que je contrôle du début à la fin, où je sais exactement quelles vulnérabilités sont en place parce que c’est moi qui les ai mises.
L’objectif : trois machines Windows, un domaine AD, un scénario gray-box (je dispose d’un accès réseau, je simule un attaquant interne après phishing ou compromission d’un poste). Je me donne un livrable à rendre comme si c’était une vraie mission : rapport de pentest détaillé, plan d’action priorisé, restitution.
Le lab
Trois VMs Windows Server 2022, déployées sur un des trois Proxmox du homelab, dans un VLAN isolé pour éviter toute fuite sur le reste du réseau.
| Machine | IP | Rôle | OS |
|---|---|---|---|
| DC01 | 10.10.11.10 | Contrôleur de domaine | Windows Server 2022 |
| FS01 | 10.10.11.20 | Serveur de fichiers | Windows Server 2022 |
| WS01 | 10.10.11.30 | Poste de travail | Windows Server 2022 |
Domaine : corp.lab. La machine d’attaque est une Kali dans le même sous-réseau.
Les vulnérabilités sont volontairement représentatives de ce qu’on trouve en entreprise après dix ans de dérive : mots de passe faibles, credentials traînant dans des scripts ou des attributs LDAP, pas de LAPS, pas de tiering, LSASS non protégé. Rien d’exotique. Ce sont des défaillances qu’on retrouve partout, même dans des infras récentes.
Phase 1 — Reconnaissance
Un scan de découverte pour vérifier la topologie :
| |
Quatre hôtes remontent la gateway et les trois cibles. Scan complet ensuite :
| |
Les scripts NSE font déjà un gros travail. Le certificat SSL RDP du DC trahit le FQDN (DC01.corp.lab), le script rdp-ntlm-info confirme le domaine, et smb2-security-mode sort une info qui va devenir importante plus tard : le SMB signing est bien forcé sur le DC, mais il est seulement activé (et pas exigé) sur FS01 et WS01. À retenir, ça rouvre une porte SMB Relay pour plus tard si le reste cale.
Énumération Kerberos sans authentification sur le port 88 :
| |
Trois comptes valides remontent : test, administrator, backup. Le DC accepte l’énumération Kerberos anonyme. Pas idéal pour un DC en production.
Dernière tentative à l’aveugle, le dump LDAP anonyme :
| |
Le bind s’ouvre, mais les fichiers générés sont vides. L’AD refuse l’énumération anonyme. Tant pis.
Phase 2 — Premier accès : user-as-pass
Classique mais ça marche toujours. Le compte test identifié via Kerberos, on tente test:test :
| |
Succès. Pas d’admin local, mais un compte de domaine standard suffit pour la phase suivante. C’est cette vulnérabilité, un mot de passe identique au login, qui ouvre toute la chaîne. Sans elle, il aurait fallu passer par du SMB Relay (possible vu V01), du password spraying, ou autre chose.
Phase 3 — Reconnaissance authentifiée
Avec un compte valide, tout change. Dump LDAP complet :
| |
39 utilisateurs, les groupes, la politique de mot de passe. Deux observations immédiates :
- Le champ
descriptiondu comptehelpdesk01contient en clair :Compte temporaire - Mot de passe 'Helpdesk2026!'. Je teste, ça répond partout. - Tous les comptes du domaine ont le flag
DONT_EXPIRE_PASSWD. Combiné à l’absence de politique de verrouillage, c’est un terrain parfait pour du brute-force ou du spraying tranquille.
Les comptes à privilèges identifiés :
| Compte | Groupes | Observation |
|---|---|---|
| dadmin1 | Domain Admins, Special Projects | Cible finale |
| dadmin2 | Domain Admins, Special Projects | Cible finale |
| Administrator | Domain Admins, Enterprise Admins | Compte builtin |
| helpdesk01 | IT Support | MDP en clair dans description LDAP |
| svc_sql | Research Team, IT Support | SPN configuré (Kerberoastable) |
| svc_app | Research Team | SPN configuré (Kerberoastable) |
| deploy_svc | Ops Team, IT Support | Credentials trouvées ensuite |
Kerberoasting
Les comptes avec SPN se demandent un TGS sans privilège particulier. On les récupère pour cracker offline :
| |
Trois comptes remontent : svc_sql, svc_iis, svc_app. Cracking avec hashcat en mode 13100 (Kerberos 5 TGS-REP) sur rockyou :
| |
Deux cassent en quelques secondes :
svc_sql:azertyuiopsvc_iis:P4ssw0rd
Le troisième (svc_app) résiste. Mot de passe long, 25+ caractères sans doute. Quand la policy est appliquée, Kerberoasting ne donne rien.
Exploration des partages
Même compte test, on liste les partages accessibles en lecture :
| |
Un partage Configuration sur FS01 en lecture pour tous. Je le télécharge :
| |
Dans Windows/Safety/Shell/Remote/Scripts/admin.ps1, un gros classique :
| |
Credentials hardcodés du compte deploy_svc. Quatre comptes en poche maintenant : test, helpdesk01, svc_sql, svc_iis, plus deploy_svc. Aucun n’est Domain Admin, mais l’un d’eux va servir de pivot.
Phase 4 — Mouvement latéral
On teste deploy_svc sur les trois machines :
| |
Mention (Pwn3d!) uniquement sur WS01 deploy_svc est administrateur local sur le poste de travail. Pas sur FS01, pas sur DC01. Il faut pivoter.
Secretsdump sur WS01
Étant admin local, on dump SAM, LSA Secrets et sessions cachées :
| |
Trois éléments intéressants ressortent :
- Le hash NTLM du compte
Administratorlocal de WS01. - Une session mise en cache d’un compte
helpdesk01(DCC2, pas directement réutilisable). - Un
DefaultPassworddans LSA Secrets :vagrant:vagrantvestige du déploiement de la VM via Vagrant, qui aurait dû être nettoyé avant mise en production dans un vrai contexte.
Pass-the-Hash vers FS01
Le pari classique : est-ce que l’admin local a le même mot de passe partout ? Si LAPS n’est pas déployé, souvent oui. On teste :
| |
(Pwn3d!) sur FS01. L’hash de l’admin local est bien identique sur WS01 et FS01. Je suis maintenant admin local sur le serveur de fichiers, qui est un serveur membre du domaine.
Dump LSASS sur FS01 credentials DA
La cerise : lsassy permet de dumper LSASS à distance quand on est admin local.
| |
Et là, jackpot. Les deux comptes dadmin1 et dadmin2 (Domain Admins) ont des sessions actives sur FS01. Leurs credentials sont en mémoire dans LSASS ,j’en sors le hash NTLM de dadmin1 et plusieurs tickets TGT Kerberos de dadmin2.
Ce point-là, c’est la faute de config qui tue : un Domain Admin qui se connecte sur un serveur membre pour y dépanner un truc laisse ses secrets en mémoire pour quiconque devient admin local sur cette machine. C’est pour ça que le modèle de tiering Microsoft (Tier 0 / 1 / 2) existe. Et c’est rare de le voir correctement appliqué hors des grosses boîtes avec une équipe IAM dédiée.
Phase 5 — Compromission du DC
Avec le hash NTLM de dadmin1, Pass-the-Hash direct sur le DC via psexec :
| |
Shell système sur le contrôleur de domaine :
| |
Pour le rapport, création et suppression d’un compte d’audit ajouté aux Domain Admins :
| |
Domaine entièrement compromis. La chaîne complète :
test:test → accès domaine authentifié
→ ldapdump → helpdesk01 / Kerberoasting → svc_sql cracké
→ partage Configuration → deploy_svc → admin local WS01
→ secretsdump → hash admin local
→ Pass-the-Hash → admin local FS01
→ lsassy FS01 → hash dadmin1 (DA)
→ psexec DC01 → NT AUTHORITY\SYSTEM
Cinq phases. Zéro exploit 0-day, que des erreurs de configuration très courantes.
Ce qui m’a bloqué
Quelques points où j’ai perdu du temps inutilement :
Le hashcat qui ne sortait rien la première fois, parce que j’avais oublié que rockyou.txt était gzip sur cette install de Kali et qu’il fallait le gunzip avant. Trente minutes à regarder passer des hashes sans comprendre pourquoi ça ne tombait pas. Classique.
lsassy qui retournait une erreur d’authentification Kerberos alors que les credentials étaient bonnes. Il fallait ajouter le FQDN et pas l’IP pour que la négociation Kerberos passe proprement. Utiliser l’IP fonctionne sur certains outils impacket mais pas sur lsassy selon les modes.
Le psexec sur le DC qui bloquait sans erreur claire. En fait j’avais oublié le -hashes à la première tentative, il demandait un mot de passe que je n’avais pas. J’aurais pu m’en rendre compte plus vite mais sans message d’erreur explicite, j’ai cherché ailleurs pendant un moment.
Ce que j’en retiens
Monter le lab soi-même, c’est différent d’une box toute faite. J’ai compris à quel point des petites défaillances de config s’enchaînent pour donner un domaine entier. Aucune des onze vulnérabilités identifiées n’est critique prise isolément (à part peut-être le test:test), mais mises bout à bout elles forment une kill chain propre.
L’autre chose, c’est la partie livrables. J’ai rédigé le rapport, un plan d’action et une présentation de soutenance. C’est là que j’ai le plus buté : comment on explique à quelqu’un de non-technique que neuf commandes et deux erreurs de config donnent accès à l’intégralité d’un domaine ? C’est un exercice que je n’avais pas anticipé, et honnêtement plus difficile que la partie technique.
Corriger n’importe laquelle des vulnérabilités critiques de la chaîne aurait stoppé ou sérieusement ralenti l’attaque. Déployer LAPS, appliquer une vraie policy de mot de passe, nettoyer les partages, activer Credential Guard, faire du tiering. Rien de sorcier. Juste du travail d’hygiène qu’on repousse à plus tard parce qu’il n’y a jamais d’incident pour forcer la main.
Prochaine étape : refaire le même lab en appliquant les remédiations une par une, pour voir exactement à quelle étape la chaîne se coupe.
Le lien vers le repo Github GitHub.