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
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 ».
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.
- https://learn.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server?view=sql-server-ver16
- https://learn.microsoft.com/fr-fr/windows-server/identity/ad-ds/deploy/schema-updates
- https://learn.microsoft.com/en-us/windows/win32/extensible-storage-engine/jet-coltyp-enumeration
- https://www.ssi.gouv.fr/uploads/IMG/pdf/Audit_des_permissions_en_environnement_Active_Directory_article.pdf
- Module développé par la société Fox-IT : https://github.com/fox-it/dissect.esedb
XMCO
Découvrir d'autres articles
Inscrivez-vous à notre newsletter !
Tous les mois, nous vous envoyons un condensé de l'actualité d'XMCO, les webinars thématiques, les événements...