Golden Ticket refusé trois fois : ce que Kerberos vérifie vraiment
Dans mon homelab, un contrôleur de domaine a rejeté trois fois un Golden Ticket forgé avec la bonne clé de krbtgt : l'horloge, l'ordre des opérations puis l'existence du compte m'ont montré ce que Kerberos vérifie au-delà de la signature.
Le symptôme
Pour voir ce que mes corrections de production empêchent vraiment, j'ai attaqué un Active Directory volontairement vulnérable dans mon homelab, un cluster Proxmox de trois nœuds qui m'appartient. Rien ne touche une entreprise. Le domaine LAB.AD.local tourne sur un contrôleur Windows Server 2022, DC-LAB ; l'attaque part d'une station Kali.
La chaîne d'attaque avait abouti au DCSync, qui réplique les secrets du domaine, dont les clés de krbtgt : le compte qui signe les tickets Kerberos. Dernière étape, le Golden Ticket : un ticket écrit soi-même, pour le compte de son choix. J'ai utilisé la clé AES256 plutôt que l'empreinte NTLM, car un contrôleur Windows Server 2022 chiffre ses tickets en AES et un ticket en RC4 détonnerait.
Le contrôleur a refusé le ticket. La clé de krbtgt était pourtant la bonne.
Ce que le symptôme écarte déjà
Avant de reforger quoi que ce soit, le refus permettait déjà de raisonner :
- La clé est correcte : elle vient de la réplication du domaine. La cryptographie n'est pas en cause.
- Le contrôleur est joignable et lit le ticket : c'est lui qui le rejette.
- La question devient : si la signature est bonne, que vérifie d'autre le contrôleur avant d'accepter un ticket ?
Trois refus, trois causes
Les causes sont tombées une à une.
1. L'horloge. Kali et le contrôleur avaient plusieurs heures d'écart, à cause du fuseau horaire. Kerberos tolère cinq minutes. J'ai aligné le fuseau de Kali sur celui du contrôleur et réglé l'heure à la main, faute d'outil de synchronisation disponible.
2. L'ordre des opérations. L'heure corrigée, le refus persistait. Le ticket avait été forgé avant la correction : il portait des horodatages calculés avec l'heure fausse. Corriger l'horloge ne corrige pas un ticket déjà écrit ; il fallait le reforger.
3. Le compte. Mon premier ticket usurpait un compte inventé. Un Windows Server 2022 à jour des correctifs Kerberos vérifie que le compte décrit dans le ticket existe, et rejette les autres.
Ce que Kerberos vérifie, au-delà de la signature
Un rappel général aide à relier ces trois refus. Un ticket d'authentification Kerberos (TGT) est chiffré et signé avec la clé de krbtgt. Qui détient cette clé peut donc écrire un ticket que le contrôleur ne distingue pas d'un vrai par la cryptographie. Le contrôleur vérifie pourtant d'autres choses.
Le temps. Chaque échange Kerberos porte un horodatage. Au-delà d'un écart toléré, cinq minutes par défaut, le contrôleur refuse : c'est ce qui empêche de rejouer plus tard un échange intercepté. Le ticket contient aussi ses propres dates de validité, fixées au moment de la forge avec l'horloge de la machine qui le forge. D'où les deux premiers refus.
Le PAC. Le ticket transporte un bloc, le PAC, qui décrit le compte : son identifiant (SID) et ses groupes. Dans un Golden Ticket, c'est l'attaquant qui rédige ce bloc, et il le signe avec la même clé. Autrefois, un ticket bien signé au nom d'un compte inventé passait. Les correctifs récents font vérifier au contrôleur que le compte décrit existe bien dans l'annuaire. D'où le troisième refus.
Cette validation ne bloque pas le Golden Ticket. Elle réduit la marge de l'attaquant : il lui faut désormais un compte existant.
La correction
Une fois l'horloge alignée, j'ai reforgé le ticket pour le compte réel « Administrateur ». Les commandes viennent d'Impacket.
Kali · forge et utilisation du ticket (homelab, valeurs génériques)
# 1. SID du domaine, avec un compte du domaine
impacket-lookupsid 'LAB.AD.local/<compte>:<mot de passe>@<IP du contrôleur>' | grep 'Domain SID'
# 2. Forge, après correction de l'heure, pour un compte qui existe
impacket-ticketer -aesKey <clé_aes256_krbtgt> -domain-sid <SID_du_domaine> \
-domain LAB.AD.local Administrateur
# 3. Utilisation : Kerberos exige le nom complet (ajouté dans /etc/hosts)
export KRB5CCNAME=Administrateur.ccache
impacket-smbclient -k -no-pass DC-LAB.LAB.AD.local
Le ticket a été accepté. Il a ouvert tous les partages du contrôleur, partages administratifs et disque système compris, sans aucun mot de passe. Il reste valable plusieurs années.
Changer tous les mots de passe ne l'invalide pas ; seule une double rotation de krbtgt le fait. L'explication est générale : le compte krbtgt garde sa clé actuelle et la précédente, pour que les tickets en circulation restent valides pendant un changement. Une seule rotation laisse donc la clé volée utilisable.
Ce que j'en retiens
- Devant un refus Kerberos, regarder l'horloge en premier, puis recréer tout ce qui a été produit avant la correction : un ticket forgé avec l'heure fausse garde son erreur.
- La validation du PAC réduit la marge de l'attaquant, elle ne bloque pas le Golden Ticket : un compte inventé ne passe plus, un compte réel passe toujours. L'enjeu reste la clé. Ici, elle venait du DCSync : il faut limiter et protéger les comptes qui ont les droits de réplication.
- La double rotation de
krbtgtinvalide les tickets déjà forgés, mais elle n'empêche pas d'en forger un nouveau si la clé fuit à nouveau. C'est une mesure que j'avais appliquée sur l'annuaire de production ; ce labo m'en a montré la portée et la limite.