Adieu NTLMv1 - Partie 1 - Détection

Nous voici à la première étape à passer pour désactiver NTLMv1. Détecter qui et quoi l'utilisent dans votre environnement. Avant d'aller dans les détails, on va rapidement parler de compatibilité. J'entends souvent les commentaires suivants:

  • "On a toujours un serveur Windows NT4, du coup on ne peut pas désactiver NTLM v1"
  • "On a une relation d'approbation externe avec un vieux domaine, on a besoin de NTLMv1"
  • "On a toujours une vieille appli qui tourne sous Windows 2000 Server"

Si vous êtes dans un de ces cas, vous avez un gros problème. Et ce n'est pas NTLM1 :) Si vous vous souciez de la sécurité dans votre environnement, faites donc une priorité de se débarrasser de ces vieux systèmes d'exploitation ! D'un point de vue NTLM maintenant, pas de soucis. Voici un rapide tableau montrant depuis quand NTLMv2 est supporté:

Version Support de NTLMv2 Date
Windows NT4 Service pack 4 Octobre 1998
Windows 95 Directory Services client Février 2000
Windows 98 Directory Services client Février 2000
Windows Me Directory Services client Février 2000
Windows 2000 RTM Février 2000
Samba Version 3 Septembre 2003
JCIFS Version 1.3 Octobre 2008

 

Bref, vous n'avez pas d'excuses d'un point de vue OS. Cela étant dit, ce n'est pas parce que l'OS supporte NTLMv2 qu'il n'utilise pas NTLMv1. Et ce qui gouverne l'utilisation de la version de NTLM sur le système est la valeur de registre suivante: LMCompatibilityLevel. Avant d'aller dans les détails, un bref détour sur le tableau blanc pour récapituler comment NTLM fonctionne dans un environnement Active Directory.

NTLM 101

Voici les échanges simplifiés lors d'une authentification NTLM d'un utilisateur de domaine qui accède à un partage réseau sur un serveur membre:

NTLM_0

  1. Alice accède au partage.
  2. Le serveur de fichier lui signale qu'il faut s'authentifier avec NTLM, et pour cela, le serveur de fichier génère un Challenge (un nombre aléatoire) et l'envoie à Alice.
  3. Alice utilise ce Challenge, elle prend le condensé de son mot de passe (hash), le passe dans une fonction avec le Challenge et obtient une Réponse (NTLM Response). Elle envoie le tout au serveur de fichier.
  4. Idéalement, le serveur de fichier doit vérifier si la Réponse est la bonne. Et pour ce faire, le serveur a besoin du condensé de mot de passe pour Alice puis, a besoin d'effectuer le même calcul qu'elle pour vérifier s'il obtient la même réponse. Mais Alice étant une utilisatrice du domaine, le serveur de fichier ne connaît pas son condensé de mot de passe... Et du coup le serveur envoie le tout à un serveur qui lui connaît le condensé et pourra faire le calcul : le contrôleur de domaine. C'est un concept clé de l'authentification NTML appelé : NTLM Pass-Through (on passe à travers le serveur pour l'authentification).
  5. Le contrôleur de domaine a reçu du serveur de fichier le nom d'utilisateur, le Challenge et la Réponse. Il calcule sa propre réponse basée sur sa connaissance du condensé de mot de passe pour Alice (c'est dans la base de données Active Directory) et la compare avec la réponse envoyée. Si c'est la même, il répond au serveur de fichier que c'est bon. Si ce n'est pas bon, il en fait de même.
  6. Si le serveur de fichier a reçu l'accord du contrôleur de domaine, Alice peut continuer d'accéder au serveur de fichier, sinon Alice n'a pas accès.

Notez que ceci est juste la partie authentification, il se peut qu'Alice n'ait pas accès au partage, car elle n'a pas les autorisations, mais dans ce cas-ci, l'authentification a bel et bien fonctionné.

Et la version alors?

Si on regarde dans les détails, la machine cliente depuis laquelle Alice se connecte va négocier la version d'NTLM à utiliser. Et cela est gouverné par une valeur de registre, la fameuse LMCompatibilityLevel. Il y a beaucoup de confusion autour de cette valeur, car elle affecte la version de NTLM à utiliser de deux façons. Elle indique qu'elles sont les versions supportées par le système lorsque ce dernier agit en tant que client. Mais elle indique aussi qu'elles sont les versions supportées par le système lorsqu'il agit en tant que serveur. Dans notre exemple précèdent, Alice est en fait connectée depuis sa station de travail, du coup sa machine agit en tant que client dans cette négociation de version. Si Alice crée un partage sur sa machine et que Bob tente d'y accéder, Bob devrait s'authentifier. Et dans ce cas si, la machine d'Alice agira en tant que serveur.

Voici les différentes valeurs possibles... Lorsque la machine agit en tant que client (ce que la machine accepte de négocier, accepte d'envoyer) :

Valeur LM NTLMv1 NTLMv2 Session Security NTLMv2
0 Oui Oui Non Non
1 Oui Oui Oui Non
2 Non Oui Oui Non
3 Non Non Oui Oui
4 Non Non Oui Oui
5 Non Non Oui Oui

 

Plusieurs remarques... Déjà c'est quoi ce NTLMv2 Session Security... Le nom prête à confusion, il s'agit d'une évolution de NTLMv1, en gros plutôt que d'utiliser le condensé du mot de passe pour calculer la réponse du challenge, on utilise une clé de session négociée entre le client et le serveur... Mais bon, considérons ça comme du NTLMv1 ++. Ensuite, d'un point de vue client (lorsque la machine agit en tant que client dans la négociation NTLM), les valeurs 3, 4 ou 5 ont le même effet.

Maintenant, regardons à quoi correspond la valeur de registre lorsque la machine agit en tant que serveur (ce que la machine accepte de négocier, accepte de recevoir) :

Valeur LM NTLMv1 NTLMv2
0 Oui Oui Oui
1 Oui Oui Oui
2 Oui Oui Oui
3 Oui Oui Oui
4 Non Oui Oui
5 Non Non Oui

 

Là encore plusieurs remarques. Les valeurs de 0 à 3 ne changent rien pour la machine lorsqu'elle agit en tant que serveur. Aussi, il semble souvent étrange que la même valeur gouverne à la fois le comportement server et le client. Mais quand on y regarde de près, il y a une logique. Lorsqu'on met la valeur 4 par exemple, côté client, la machine ne fera jamais de LM. Par contre, elle peut faire du NTLMv1 et NTLMv2. Et lorsque la machine agit en tant que serveur, lorsqu'elle reçoit une connexion entrante qu'elle a besoin d'identifier, cette fois-ci elle n'acceptera que du NTLMv2, assurant un bon compromis entre compatibilité et sécurité. Lorsque toutes les machines d'un environnement ont la même valeur pour LMCompatibilityLevel, on garantit qu'elles peuvent toutes utiliser NTLM sans problème de comptabilité.

L'objectif ultime est de mettre la valeur 5 pour toutes les machines dans l'environnement (par default la valeur est a 3 pour Windows Vista et Windows Server 2008 et supérieur). Nous verrons dans la partie 3 de cette série comment procéder pour ne rien casser.

Auditer tout cela...

Le concept d'NTLM Pass-Through est fondamental, car il nous indique où les évènements d'authentification vont être générés. On va voir 2 évènements:

  • Sur le serveur où se trouve la ressource : 4624
  • Sur le contrôleur de domaine : 4776

Notez que si la ressource à laquelle le client essaie d'accéder est sur le contrôleur de domaine, l'évènement 4624 va aussi être sur le contrôleur de domaine (agissant en tant que serveur dans ce cas).

Pour s'assurer que l'évènement 4624 apparaît bien sur tous vos serveurs (et cela inclut les contrôleurs de domaine), la catégorie d'audit suivante doit être activée :

NTLM_1

Regardons de plus près ce que contient l'évènement 4624 :

NTLM_3

On est sur la machine SRV01 qui partage un répertoire. On voit l'utilisateur AD\pierre se connecter depuis la machine SRV02 (on a même son adresse IP: 10.0.1.12). On voit qu'on utilise NTLM comme authentification et on y voit même la version NTLMv1. Juste regarder cet évènement nous permet d'établir 3 faits :

  1. SRV01 accepte NTLMv1.
  2. SRV02 envoie du NTLMv1.
  3. Le contrôleur de domaine à qui l'authentification NTLM Pass-Through a été transférée accepte aussi NTLMv1.

Que voit-on sur le contrôleur de domaine ? D'abord pour y voir quelque chose, il faut s'assurer que la catégorie d'audit suivante est activée :

NTLM_2

Et voici à quoi ressemble l'évènement 4776:

NTLM_4

On n'y voit pas grand-chose. On sait qu'il s'agit du compte de Pierre, que ça vient de SRV02 (bien que techniquement, ce champ est ici à titre indicatif...) et on ne sait pas s'il s'agit de NTLMv1 ou bien de NTLMv2. En bref, activer l'audit pour cet évènement peut être utile pour suivre d'où les utilisateurs se connectent, mais ne nous aide pas pour identifier les machines faisant du NTLMv1. La catégorie d'audit importante dans notre cas sera bel est bien celle qui nous permettra d'afficher la version d'NTLM utilisée, donc celle qui va générer l'évènement 4624.

En général cette catégorie d'audit est déjà activée (configuration par défaut). Donc pas grand-chose à faire de votre côté. Pour s'assurer que c'est le cas, vous pouvez utiliser la commande suivante:

 auditpol /get /category:"Logon/Logoff"

Exemple de sortie :

 System audit policy
Category/Subcategory                      Setting
Logon/Logoff
  Logon                                   Success and Failure
...

Tant qu'on a Success, on est bon. Il est également possible de créer une stratégie de groupe qui va appliquer cette configuration d'audit partout.

Notez que j'utilise ici la stratégies Audit Avancé, par la stratégie d'audit legacy. Pour en savoir davantage sur l'Audit Avancé, référez-vous à l'article suivant: Advanced Security Audit Policy Step-by-Step Guide (en anglais).

Il conviendra d'activer l'audit de success de connexion sur toutes les machines hébergeant des ressources dans votre environnement (serveurs et contrôleurs de domaine). Je vous laisse le choix de votre configuration par stratégie de groupe. Si jamais cette configuration est un défi, n'hésitez à publier des questions et commentaires dans la section en bas de page.

Filtrer les évènements relatifs a l'utilisation de NTLMv1

Maintenant qu'on a les évènements 4624, il faut identifier ceux qui sont relatifs à une authentification NTLMv1. Il faut donc filtrer le reste (Kerberos, NTLMv1 et autres protocoles). Pour cela, nous allons créer un filtre XPath qu'on va pouvoir utiliser à la fois dans l'interface graphique de l'observateur d'évènements, mais aussi en PowerShell.

 <QueryList>
 <Query Id="0" Path="Security">
  <Select Path="Security">
  Event[
   System[
    EventID=4624
   ] and EventData[
      Data[@Name="LmPackageName"]="NTLM V1"
   ]
  ]
  </Select>
 </Query>
</QueryList>

Exemple dans l'observateur d'évènements :

NTLM_6

 
$_filtre_xml = @"
<QueryList>
 <Query Id="0" Path="Security">
  <Select Path="Security">
  Event[
   System[
    EventID=4624
   ] and EventData[
      Data[@Name="LmPackageName"]="NTLM V1"
   ]
  ]
  </Select>
 </Query>
</QueryList>
"@
Get-WinEvent -FilterXml $_filtre_xml

#ou bien directement la requête XPath
$_filtre_xpath = "Event[ System[ EventID=4624 ] and EventData[ Data[@Name=""LmPackageName""]=""NTLM V1"" ] ]"
#notez les doubles guillemets ainsi que le paramètre LogName pour spécifier le journal
Get-WinEvent -LogName Security -FilterXPath $_filtre_xpath

Ici le filtre XPath en capsule dans les balises <select...> </select> va uniquement faire afficher les évènements 4624 qui ont la propriété LmPackageName égale à "NTLM V1".

NTLM_5

Bruit anonyme et filtre final

Il semble que certains services Windows ainsi que certains protocoles vont générer des évènements 4624 avec du NTLMv1 alors qu'il ne s'agit pas vraiment à proprement dit d'authentification (dans la mesure où désactiver NTLMv1 ne va pas empêcher ces services et protocoles de fonctionner). Bref, il va falloir filtrer ces évènements si la propriété TargetUserName est ANONYMOUS LOGON. On va filtrer basé sur le TargetUserSid (S-1-5-7) comme ceci:

 <QueryList>
 <Query Id="0" Path="Security">
  <Select Path="Security">
  Event[
   System[
    EventID=4624
   ] and EventData[
      Data[@Name="LmPackageName"]="NTLM V1" and Data[@Name="TargetUserSid"]!="S-1-5-7"
   ]
  ]
  </Select>
 </Query>
</QueryList>

Ou en PowerShell:

 
$_filtre_xpath = "Event[ System[ EventID=4624 ] and EventData[ Data[@Name=""LmPackageName""]=""NTLM V1"" and Data[@Name=""TargetUserSid""]!=""S-1-5-7""] ]"
Get-WinEvent -LogName Security -FilterXPath $_filtre_xpath

Étape suivante, collecter l'information sur tous les serveurs

Cela parait une étape périlleuse, c'est en fait très simple. On va utiliser le service de transfert d'évènements qui est déjà inclus dans Windows. Rendez-vous au prochain billet.