Cet article présente l'intérêt  d'utiliser les Metadata de réplication pour avoir rapidement un aperçu des modifications qui ont pu être effectuées dans un environnement Active Directory lors d'audit Forensic.

Sujet malheureusement d'actualité auquel il faut se préparer car aujourd'*** nul n'est à l'abri d'une compromission de son environnement Active Directory

Introduction

Vous allez me dire : Pas besoin de ça, je fais déjà de l'audit sur mon environnement AD, je vais voir toutes les modifications qui sont effectuées.

Oui mais ... Faisons un petit test.
J'ai un environnement AD avec l'audit des modifications AD activé sur mon DC.

Dans mon environnement j'ai une OU nommée TEST-METADATA

Sur cette OU j'ai configuré un audit pour toutes les modifications effectuées par tous le monde.

L'audit est donc bien configuré sur le DC et sur l'objet au travers des SACL.
Faisons un test en modifiant la description de l'OU.

Effectivement l'audit fonctionne bien. J'ai bien un event qui est généré pour la modification.
Maintenant, modifions les permissions sur cette OU. Pour simplifier les choses je vais juste modifier la protection contre la suppression accidentelle qui modifie les ACL sur l'objet.

Mon attribut a bien été modifié (les ACL de l'OU en fait) mais pourtant je n'ai pas d'event généré ...
Si je modifie à nouveau la description, les events sont bien générés (2 events, un pour la suppression de l'ancienne valeur, un pour l'ajout de la nouvelle)

Les modifications sur les objets audités ne génèrent donc pas toutes des events ...

Je ne vais pas rentrer dans le détails mais je vais juste vous dire ce que j'ai fait pour empêcher l'audit des modifications des ACL.
Vous le savez sûrement, les permissions sont "stockés" dans l'attribut ntSecurityDescriptor
J'ai modifié l'attribut searchFlags de l'objet du schéma nt-security-descriptor.

Et j'ai spécifié de ne pas auditer cet attribut.

Le problème c'est que la modification de cet attribut n'est pas auditée ...
Et donc si une personne malveillante a eu accès a des droits de type "Schema Admins" sur votre environnement, il est possible que qu'elle ait effectuée des modifications de ce type pour masquer ses prochaines actions sans que vous vous en rendiez compte ...

Alors on fait toujours confiance aux audits AD ?
Maintenant que l'on est complètement parano, voyons comment détecter ce type de modification.

Je ne vais pas rentrer dans le détail, mais la solution vous l'aurez devinée, c'est les Metadata de réplication.
Un simple Repadmin nous donne l'information, l'attribut searchFlags a été modifié 2 fois.

Et si on regarde les Metadata de notre OU on voit bien les modifications de la description et des ACL (DACL et SACL) :

Bien évidement l'attribut searchFlags n'est pas le seul attribut qu'il faut vérifier.

Methodes de recuperation des Metadata



Nous allons maintenant aborder les différentes méthodes pour récupérer les Metadata de Réplication.
L'objectif étant bien évidemment d'automatiser au maximum la récupération de ces données.

Repadmin

Nous venons de voir que l'on peut utiliser l'outil Repadmin et plus particulièrement avec le paramètre Repadmin /Showobjmeta

Un exemple avec les Metadata d'une OU :

Repadmin nous permet de récupérer très facilement les Metadata pour un objet donné.
Par contre il est difficile à utiliser pour récupérer les Metadata d'un nombre important d'objets.
De plus le format de sortie  impose un traitement assez conséquent pour avoir des informations exploitables.
On l'utilisera donc plutôt pour avoir les Metadata d'un objet unique. On pourra s'en servir par exemple pour récupérer le timestamp et le DC d'origine d'une modification d'un attribut pour ensuite consulter les logs.

LDP 

Nous allons voir maintenant un autre outil qui va nous permettre de récupérer les Metadata de réplication.
C'est un outil généralement peu utilisé mais qui peut rendre bien des services, LDP.
Pour récupérer les Metadata de réplication il suffit de se positionner sur l'objet et de faire un clic-droit puis Advanced et Replication Metadata


Et on affiche les Metadata :

Le problème c'est que comme pour Repadmin, ce n'est pas facilement exploitable d'autant plus qu'avec ldp nous n'avons pas le nom des attributs...
On peut toutefois récupérer les informations sous une forme plus exploitable.
Pour ceci on peut effectuer une recherche sur l'objet et en spécifiant l'attribut msDS-ReplAttributeMetaData

Le format de sortie est de type DS_REPL_VALUE_META_DATA qui a une structure de type XML.
On peut de plus effectuer la recherche sur plusieurs objet.
Par exemple, en effectuant une recherche sur le conteneur Users pour tous les groupes.
Vous remarquerez que j'utilise ici l'attribut msDS-ReplValueMetaData et non msDS-ReplAttributeMetaData. C'est uniquement pour vous montrer que l'on peut récupérer les Metadata de plusieurs objets. Je reviendrais en détail sur cet attribut dans la suite de l'article puisqu'il est très intéressant pour l'audit des groupes.

On arrive donc a récupérer les informations de plusieurs objets dans un format plus exploitable (XML).
On a toutefois toujours besoin de retraitement pour exploiter les données.

Methode GetReplicationMetadata 

On va désormais passer aux méthodes permettant de récupérer les Metadata dans un format exploitable.
On va commencer par utiliser la méthode GetReplicationMetadata de la classe DomainController

Voici le code utilisé:

$DomainName = "metadata.adds"

$ObjectDistinguishedName = ""

$DirectoryContext = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$DomainName)

$DomainController = [System.DirectoryServices.ActiveDirectory.DomainController]::findOne($DirectoryContext)

$MetaData = $DomainController.GetReplicationMetadata($ObjectDistinguishedName)  


On peut donc récupérer facilement les informations dans un format exploitable.
L'intérêt de cette méthode est qu'elle est simple à utiliser et ne nécessite pas l'utilisation du module Powershell ActiveDirectory.

msDS-ReplAttributeMetaData

On va maintenant voir une solution utilisant l'attribut msDS-ReplAttributeMetaData et le module Powershell ActiveDirectory.
J'ai fait une fonction relativement simple qui permet de récupérer ces informations en fournissant le DistinguishedName d'un objet  :

Voici le code de la fonction :

Function Get-ADObjectMetadata {

Param(

        [Parameter(Mandatory=$true,Position=1)]

        [String] $ObjectDN

        )

    ### Chargement du module ActiveDirectory

    try { Import-Module ActiveDirectory |Out-Null}

    catch { Write-Warning "Cannot load ActiveDirectory module."; Break }

    $ADObject = Get-ADObject $ObjectDN -Properties "msDS-ReplAttributeMetaData"

    $ReplAttributeMetaData = $ADObject."msDS-ReplAttributeMetaData"

    $ReplAttributeMetaData = "<root>" + $ReplAttributeMetaData + "</root>"

    $ReplAttributeMetaData = $ReplAttributeMetaData.Replace([char]0," ")

    $ReplAttributeMetaData = [XML]$ReplAttributeMetaData

    $ReplAttributeMetaData = $ReplAttributeMetaData.root.DS_REPL_ATTR_META_DATA

    $TabObjectMetadata = @()

    $ReplAttributeMetaData | Foreach {

        $obj = New-Object psobject

        $obj |Add-Member -type NoteProperty -name AttributeName -value $_.pszAttributeName

        $obj |Add-Member -type NoteProperty -name Version -value $_.dwVersion

        $obj |Add-Member -type NoteProperty -name TimeLastOriginatingChange -value $_.ftimeLastOriginatingChange

        $obj |Add-Member -type NoteProperty -name usnOriginatingChange -value $_.usnOriginatingChange

        $obj |Add-Member -type NoteProperty -name usnLocalChange -value $_.usnLocalChange

        $obj |Add-Member -type NoteProperty -name LastOriginatingDsaDN -value $_.pszLastOriginatingDsaDN

        $TabObjectMetadata += $obj

        }

    return $TabObjectMetadata

    }


Encore une fois les données sont facilement exploitables.

Get-ADReplicationAttributeMetadata


Pour finir, Windows Server 2012 R2 (et Powershell 4.0) apporte de nombreuses Cmdlets.
Get-ADReplicationAttributeMetadata répond parfaitement à notre besoin en toute simplicité.



Metadata et Attributs lies


Nous venons de voir rapidement l'attribut msDS-ReplValueMetaData.
Pour bien comprendre on va repartir des bases.

Les tables de la base Active Directory


On va commencer par revoir rapidement comment sont stockées les données dans la base Active Directory.
Comme vous le savez sûrement la base Active Directory est stockée physiquement dans le fichier ntds.dit (avec les fichiers de logs qui lui sont associés).
Ce que peu de personnes savent c'est comment sont organisées les données dans ce fichier.
Si l'on se réfère au technet (Data Store Physical Structure), le fichier ntds.dit contient 3 tables : Data Table, Link Table et SD Table

En réalité la base de données Active Directory contient 12 tables.
Christoffer Andersson a publié une série d'articles sur le sujet et il liste toutes les tables dans son premier article sur le sujet : How the Active Directory – Data Store Really Works (Inside NTDS.dit) – Part 1
Si vous avez déjà joué avec Esentutl (à faire en lab), il est déjà possible d'avoir des informations sur le contenu du fichier ntds.dit en utilisant les paramètres de dump (Esentutl /file dump)

On récupère donc déjà pas mal d'informations (tables et index) sur le contenu de la base.

Il est aussi possible de faire un dump de la base avec ldp, How to Use the Online Dbdump Feature in Ldp.exe

Faire ce type de dump est très intéressant pour comprendre la structure et le fonctionnement de la base Active Directory.

Pour aller encore plus loin, il est possible d'utiliser libesedb pour dumper le contenu de toutes les tables.

Une fois le dump effectué, on dispose de toutes les tables de la base.

Si on ouvre par exemple le fichier de la table sd_table.

Pas très lisible au premier abord mais facilement interprétable lorsque l'on s'est penché sur le sujet.

Mais revenons à nos 3 tables, la table qui nous intéresse est la table Link Table.
Cette table contient les attributs liés (Linked Attributes). L'attribut lié qui nous intéresse ici est l'attribut Member.

Linked Value Replication

Avant Windows Server 2003, lorsqu'un changement était effectué par exemple dans les membres d'un groupe, c'était tout le contenu de l'attribut member qui était répliqué. Si j'avais un groupe avec 1000 membres et que j'en ajoutais 1, tout le contenu de l'attribut Member (1001 groupes) était répliqué.
Windows Server 2003 a introduit un nouveau mécanisme de réplication appelé Linked Value Replication (LVR) qui permet de répliquer les valeurs individuels et non la totalité.

Vous vous demandez peut-être c'est quoi le rapport avec l'audit Forensic Active Directory ?
Qui dit réplication, dit Metadata de réplication.

Avant 2003 je n'aurais eu que la date de dernier changement de l'attribut Member ce qui n'est pas très intéressant.
Avec le mécanisme LVR, j'ai les metadata au niveau de chaque valeur contenue dans l'attribut Member et je peux donc savoir quand un objet a été ajouté ou supprimé de l'attribut Member.

Un example concret

Imaginons que je veux auditer un AD, je vais bien évidemment auditer les groupes à privilèges.
On va donc commencer par lister les membres de ces groupes, par exemple le groupe Domain Admins.

Ok il n'y a que Administrator dedans c'est un bon début.
Mais s'arrêter à ce niveau serait une grave erreur.
Maintenant si je veux savoir qui a été membre de ce groupe ?
Il va falloir rechercher les logs (si l'audit est en place) et tout consolider, pas simple et dépendant de beaucoup de facteurs.

Pour gagner du temps on va à nouveau se servir des Metadata de réplication.
On va commencer par réutiliser Repadmin avec le paramètre /ShowObjMeta

On voit dans la seconde partie les membres du groupe et on peut noter qu'un utilisateur nommé Intruder a été membre de ce groupe ce qui est très suspicieux ...

Vous noterez que par défaut l'attribut Member n'est pas renvoyé par la commande Repadmin. Pour cela il faut ajouter le paramètre /Linked.

Le format de sortie de repadmin n'étant pas facilement exploitable, nous allons voir d'autres méthodes.

Methodes de recuperation des Metadata

Tout d'abord avec Windows Server 2012. Comme nous l'avons vu dans le chapitre précédent, il existe une Cmdlet dédiée.

C'est très simple de retrouver l'information.

 

Pour 2008 R2, c'est un peu plus compliqué, c'est ici que nous allons utiliser l'attribut msDS-ReplValueMetaData.

Pour récupérer les informations j'ai fait la fonction suivante :

Function Get-ADGroupMembershipMetadata {

    Param(

    [Parameter(Mandatory=$true,Position=1)]

    [String] $GroupDN

    )

    ### Chargement du module ActiveDirectory

    try { Import-Module ActiveDirectory |Out-Null}

    catch { Write-Warning "Cannot load ActiveDirectory module."; Break }

    $Group = Get-ADObject $GroupDN -Properties "msDS-ReplValueMetaData"

    $ReplValueMetaData = $Group."msDS-ReplValueMetaData"

    $ReplValueMetaData = "<root>" + $ReplValueMetaData + "</root>"

    $ReplValueMetaData = $ReplValueMetaData.Replace([char]0," ")

    $ReplValueMetaData = [XML]$ReplValueMetaData

    $ReplValueMetaData = $ReplValueMetaData.root.DS_REPL_VALUE_META_DATA

    $TabMembersMetadata = @()

    $ReplValueMetaData | Foreach {

        $obj = New-Object psobject

        $obj |Add-Member -type NoteProperty -name ObjectDN -value $_.pszObjectDn

        $obj |Add-Member -type NoteProperty -name TimeCreated -value $_.ftimeCreated

        $obj |Add-Member -type NoteProperty -name TimeDeleted -value $_.ftimeDeleted

        $obj |Add-Member -type NoteProperty -name Version -value $_.dwVersion

        $obj |Add-Member -type NoteProperty -name TimeLastOriginatingChange-value $_.ftimeLastOriginatingChange

        $obj |Add-Member -type NoteProperty -name LastOriginatingDsaDN -value $_.pszLastOriginatingDsaDN

        $TabMembersMetadata += $obj

        }

    $TabADGroupMembershipMetadata = New-Object psobject

    $TabADGroupMembershipMetadata |Add-Member -type NoteProperty -name ObjectDN -value $GroupDN

    $TabADGroupMembershipMetadata |Add-Member -type NoteProperty -name Members -value $TabMembersMetadata

    return $TabADGroupMembershipMetadata

    }  


Si on reprend notre exemple :

On arrive bien à récupérer les informations.

Quelques limitations

Maintenant quelques remarques concernant cette méthode. Tout d'abord, les informations restent disponibles le temps du Tombstone.
En effet, lorsqu'un membre est enlevé d'un groupe, il est marqué comme étant supprimé. L'objet sera supprimé à l'issue du Tombstone.
Ensuite, le lien est supprimée lorsque le membre est supprimé.
Christoffer Andersson a fait un très bon article sur le sujet (How deletion/removal of data really works in Active Directory)

Reprenons notre exemple :

Sauf si vous avez activé la Corbeille Active Directory :

On voit une fois de plus que les Metadata de réplication peuvent être "détournée" de leurs objectifs premiers et se révéler  très utile lors d'audit de type Forensic.

Quels attributs faut-il verifier ?



En cours de rédaction …