On dépile le NTDS #2 - La Datatable

Part 2 : La datatable

Dans le précédent article, nous parlions des différentes tables que contient la base de données NTDS de l’Active Directory. Parmi celles-ci, la table plus intéressante et la plus importante en termes de contenu se nomme la datatable. Elle contient les données utilisateurs, groupes, machines, relation d’approbation, etc. Ce sont les informations contenues dans cette table qui sont retournées dans les requêtes LDAP.

L’objectif de cet article est donc de présenter cette structure de données, afin de rentrer plus dans le détail dans le contenu, lors de nos prochains articles.

La structure

Chaque objet de l’Active Directory occupe une ligne dans la table datatable et une ligne peut atteindre plusieurs milliers de colonnes (attributs ou propriétés). Ce nombre très important provient du mécanisme d’extension de schéma qui permet d’ajouter des colonnes pour des objets spécifiques faisant suite à l’installation d’un nouveau service compatible Active Directory ou à une montée de version du schéma. À titre d’exemple, lorsqu’un serveur Exchange est installé dans une entreprise, de nouvelles colonnes spécifiques vont être ajoutées dans la datatable et seront utilisées uniquement par les objets Exchange. Les champs de ces colonnes seront vides pour les autres objets.

Le nombre important de colonnes est l’une des raisons qui a contraint Microsoft à ne pas utiliser de base de données relationnelles classiques. En effet, des bases comme PosgresSql (1) se limitent à 1600 colonnes et 1024 pour SQLServer (2).

Le nom des colonnes

Les noms des colonnes de la datatable ne sont pas compréhensibles par un être humain. Elles sont formées de la façon suivante :
Un préfixe « ATT » + une lettre (indiquant le type de donnée) + un identifiant numérique (l’ID de l’attribut)


Ex : ATTm590045


La lettre indique le type de données stockées (4) :

  • j : entier sur 4 octets (JET_coltyp.Long)
  • q / l : entier signé sur 8 octets (généralement des timestamps) (JET_coltyp.Currency)
  • m : chaine de caractères (JET_coltyp.LongText)
  • k / r : Binaire (JET_coltyp.LongBinary) Etc.

Pour pouvoir comprendre à quoi correspondent les données stockées dans chaque colonne, le procédé n’est pas trivial, mais facilement automatisable. Ce procédé avait déjà été documenté il y a une dizaine d’années par des chercheurs de l’ANSSI (5).

  • La colonne ATTm131532 de la datatable contient le nom LDAP de l’objet
  • La colonne ATTc131102 de la datatable contient l’ID de l’attribut

Voici les différentes étapes :

1 – Nous cherchons dans la table MSysObjects les colonnes présentes dans la datatable du NTDS.
Ex :ATTm590045

2- Nous cherchons ensuite dans la datatable l’ID de l’attribut égal à 590045.

3 – Après avoir identifié l’objet (la ligne) qui contient l’ID 590045, nous regardons dans la colonne ATTm131532 le nom LDAP correspondant

sAMAccountName – ATTm590045

Recherche du nom LDAP des colonnes de la datatable
Recherche du nom LDAP des colonnes de la datatable

Voici quelques exemples de nom de colonnes intéressantes :

Nom de la colonne Attribut LDAP Description
ATTm590045 sAMAccountName Nom d’un utilisateur, nom d’une machine, nom d’un domaine (trust), etc.
ATTm13 description Description de l’objet
ATTj589836 badPwdCount Nombre de saisie d’un mot de passe incorrect
ATTm590187 operatingSystem Nom du système d’exploitation (ex : Windows 10 Professionnel) lorsque c’est un compte machine
ATTm590188 operatingSystemVersion Version du système d’exploitation (ex :10.0 (19042)) lorsque c’est un compte machine
ATTr589970 objectSID L’identifiant (SID) de l’objet

Le tableau ci-dessous permet de comprendre pourquoi on parle de table « creuse ».

Extrait de cinq types d’objets présents dans la datatable
Types d’objets

Ainsi, comme illustré, le tableau de données doit être imaginé comme un gros fichier Excel avec de nombreuses cases vides. L’objet Compte utilisateur dispose d’un nom (sAMAccountName), d’un compteur de connexion (logonCount) mais ne dispose pas de système d’exploitation qui est dédié pour les comptes machines. L’objet Domaine ne dispose d’aucun autre attribut ici excepté la taille minimum des mots de passe par défaut, qui est défini seulement à son niveau.

La liste des correspondances entre le nom de colonne de la datatable et le nom LDAP a été publiée sur notre GitHub pour trois niveaux fonctionnels de domaine différent :

Un script permettant de régénérer cette liste pour un NTDS donné a également été fourni. En fonction du niveau fonctionnel du domaine, le nombre de colonnes diffère. Celui-ci est disponible à l’adresse suivante : https://github.com/xmco/ntds_extract/blob/main/Part-2-La-Datatable/extract_ntds_columns_name.py

Lorsque vous avez établi les noms de colonnes que vous souhaitez extraire, il est possible d’accéder directement aux données.

Néanmoins, certains types d’attributs tels que les dates, les SID ou encore les données chiffrées nécessiteront un traitement particulier pour être exploités. Parmi les données chiffrées, nous avons les condensats cryptographiques des mots de passe (hashNT et hashLM), des informations extrêmement précieuses, que nous aborderons en détail dans un prochain article.


Gabriella Ibghi

Découvrir d'autres articles

  • Active Directory

    On dépile le NTDS #6 – LAPS, des attributs particuliers (1/2)

    Lire l'article
  • Active Directory

    On dépile le NTDS #5 – Les comptes machines dans l’Active Directory

    Lire l'article
  • NTDS - Partie 4
    Active Directory

    On dépile le NTDS #4 – Les comptes dans l’Active Directory

    Lire l'article