jeudi 31 juillet 2014

mercredi 23 juillet 2014

Mise à disposition par l'ANSSI de l'outil de modélisation des Chemins de contrôle en environnement Active Directory

Bonjour à tous.

L'ANSSI a mis à disposition son outil de modélisation des chemins de contrôle Active Directory qui avait été présenté au SSTIC2014.

Pour rappel, la présentation est directement disponible dans le lien suivant : Chemins de contrôle en environnement Active Directory - Chacun son root, chacun son chemin



L'outil quant à lui est disponible ici : AD-control-paths

A très bientôt.


dimanche 20 juillet 2014

De l'intérêt des Metadata de Réplication lors d'audit Forensic Active Directory, Partie 3

Bonjour à tous.

On continue notre série sur les Metadata de réplication.
Je vous ai parlé rapidement dans la Partie 2  de l'attribut msDS-ReplValueMetaData.

Pour bien comprendre on va repartir des bases.
On va commencer par voir 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 aujourd'hui 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.

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.

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.

Tout d'abord avec Windows Server 2012.
Comme nous l'avons vu dans l'article 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.

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 va s'arrêter ici pour aujourd'hui.

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.

Les Metadata de réplication ont encore beaucoup de chose à nous apprendre, nous verrons cela dans la suite de l'article.

J'espère en tout cas que cet article vous aura intéressé.
A très bientôt.


samedi 19 juillet 2014

Comment déléguer : la gestion d'autorisation de serveurs DHCP

Bonjour à tous.

On continue dans notre série sur la délégation d'administration avec toujours pour objectif de tendre vers le "Zéro Admins".

On va voir ici une tâche qui par défaut nécessite beaucoup trop de droits sur l'Active Directory, l'autorisation de serveur DHCP. En effet, pour gérer l'autorisation de serveur DHCP dans Active Directory, il faut être membre soit du groupe "Domain Admins", soit "Enterprise Admins".

Bien évidemment il est inconcevable dans notre optique du "Zéro Admins" qu'une équipe d'administration du service DHCP ait autant de droits.


Prenons un scénario assez classique :
Vous venez d'installer un nouveau serveur DHCP et vous voulez déléguer son administration à un administrateur qui aura pour unique tâche la gestion du DHCP.
Vous créez un groupe de sécurité dédié, vous l'imbriquez dans le groupe local d'administration DHCP du serveur DHCP et vous mettez votre administrateur dans le groupe que vous avez créé.

Votre administrateur se connecte au serveur DHCP par la Console DHCP mais il n'a pas l'option d'autorisation du serveur DHCP.



Vu que l'on ne souhaite pas donner des droits "Domain Admins" ou "Enterprise Admins" pour cette tâche il va falloir la déléguer.
La délégation s'effectue depuis la console Sites et Services Active Directory.
Par défaut, seule la partie Sites est visible.



Pour voir la partie Services, il faut se placer à la racine de la console puis aller dans "Affichage" puis sélectionner "".



La partie Services est désormais visible. C'est le conteneur "NetServices" qui nous intéresse.



Voici les droits par défaut sur ce conteneur.



Pour déléguer l'autorisation de serveur DHCP, faire un clic-droit sur le conteneur NetServices puis cliquer sur "Delegate Control ..."



L'assistant de délégation apparait. Cliquer sur "Next"



Ajouter le groupe que vous avez créé au préalable.



Sélectionner "Create a custom task to delegate"



Sélectionner "This folder, existing objects in this folder ..."



Sélectionner ensuite "Full Control"



Finaliser la délégation.



Il est aussi possible de faire cette action en Powershell afin d'industrialiser la délégation et éviter les erreurs.



Les commandes Powershell suivantes permettent d'effectuer la tâche de délégation :


Import-Module ActiveDirectory

$AdminDHCP = Get-ADGroup "Manage DHCP Authorization"

### Container NetServices
$ObjectDN = "CN=NetServices,CN=Services,CN=Configuration," + (Get-ADDomain).DistinguishedName
### Contrôle total sur tous les objets
[System.Security.Principal.SecurityIdentifier] $AdminDHCPSecId = $AdminDHCP.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "GenericAll"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.DirectoryServices.ActiveDirectorySecurityInheritance] $SecInherit = "All"
$ACE01 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $AdminDHCPSecId,$ADRights,$AccCtrlType,$SecInherit
### Setting ACE
$ACL = Get-Acl AD:\$ObjectDN
$ACL.AddAccessRule($ACE01)
$ACL|Set-ACL




L'autorisation de serveur DHCP est maintenant délégué au groupe "Manage DHCP Authorization".
Votre administrateur DHCP peut désormais autoriser des serveurs DHCP.



Et nous avons réussi à limiter les droits de notre administrateur.



J'espère que cet article vous aura intéressé.

A très bientôt.

jeudi 17 juillet 2014

Comment déléguer : la gestion des rôles FSMO


Bonjour à tous.

J'avais commencé à évoquer le sujet dans mon article précédent sur la Délégation d'administration Active Directory et Powershell .

Je commence donc une nouvelle série d'articles sur le sujet de la délégation d'administration qui est un sujet essentiel lorsque l'on parle de sécurité et d'Active Directory. Je me suis rendu compte au travers de mes différentes missions que ce sujet n'est pas toujours bien maîtrisé et qu'il peut en résulter de gros risques si son implémentation n'a pas été correctement effectuée.

L'objectif de cette série est d'être en mesure d'effectuer une délégation d'administration très granulaire pour limiter les droits au strict nécessaire (principe du moindre privilège) et essayer de tendre vers le "Zéro Admin" membre des groupes à privilèges pré-définis.


Aujourd'hui nous allons voir comment déléguer la gestion des rôles FSMO.

Il y a 2 parties dans cette délégation, le transfert et le transfert forcé (seize).
Le transfert utilise des droits étendus (Extended Rights).



Le second nécessite d'avoir les droits d'écriture sur l'attribut FSMORoleOwner.



Bien sûr, on peut faire cette délégation via l'interface, mais maintenant que l'on sait le faire en Powershell, on ne va pas se priver.

J'utilise ici 2 morceaux de code de Joe Corey qu'il a publié dans l'article suivant Active Directory Delegation via PowerShell.
Ils vont nous permettre de récupérer le GUID des droits étendus et de l'attribut FSMORoleOwner.

Je commence donc par importer le module ActiveDirectory, je récupère l'objet RootDSE et mon groupe de délégation nommé "Manage FSMO" et je construit les 2 hashtables avec le code de Joe.



Le principe est toujours le même :
Je créé les ACE à ajouter, je récupère les ACL de l'objet, j'ajoute les ACE dans les DACL et je réapplique les ACL sur l'objet.

Voici pour le rôle Schema Master :


On peut vérifier que les droits ont bien été positionnés:



Nos droits ont bien été positionnés, il ne reste plus qu'à faire pareil pour les 4 autres rôles FSMO.
Je vais m'arrêter ici, le principe reste le même.

Voici le code complet :

Import-Module ActiveDirectory

$RootDSE = Get-ADRootDSE
$ManageFSMO = Get-ADGroup "Manage FSMO"

### Getting Class And Attribute GUID
$GuidMap = @{}
Get-ADObject -SearchBase ($RootDSE.SchemaNamingContext) -LDAPFilter "(schemaidguid=*)" -Properties lDAPDisplayName,schemaIDGUID |% {
    $GuidMap[$_.lDAPDisplayName]=[System.GUID]$_.schemaIDGUID
    }

### Getting Extended Rights GUID
$ExtendedRightsMap = @{}
Get-ADObject -SearchBase ($RootDSE.ConfigurationNamingContext) -LDAPFilter "(&(objectclass=controlAccessRight)(rightsguid=*))" -Properties displayName,rightsGuid | % {
    $ExtendedRightsMap[$_.displayName]=[System.GUID]$_.rightsGuid
    }


### Schema Master
$ObjectDN = $RootDSE.schemaNamingContext
### Change-Schema-Master
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "ExtendedRight"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID =  $ExtendedRightsMap["Change Schema Master"]
$ACE01 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Write Permission FSMORoleOwner Attribute
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "WriteProperty"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID = $GuidMap["FSMORoleOwner"]
$ACE02 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Setting ACE
$ACL = Get-Acl AD:\$ObjectDN
$ACL.AddAccessRule($ACE01)
$ACL.AddAccessRule($ACE02)
$ACL|Set-ACL


### Naming Master
$ObjectDN = "CN=Partitions," + $RootDSE.configurationNamingContext
### Change-Domain-Master
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "ExtendedRight"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID =  $ExtendedRightsMap["Change Domain Master"]
$ACE01 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Write Permission FSMORoleOwner Attribute
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "WriteProperty"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID = $GuidMap["FSMORoleOwner"]
$ACE02 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Setting ACE
$ACL = Get-Acl AD:\$ObjectDN
$ACL.AddAccessRule($ACE01)
$ACL.AddAccessRule($ACE02)
$ACL|Set-ACL


### Infrastructure Master
$ObjectDN = "CN=Infrastructure," + $RootDSE.defaultNamingContext
### Change-Infrastructure-Master
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "ExtendedRight"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID =  $ExtendedRightsMap["Change Infrastructure Master"]
$ACE01 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Write Permission FSMORoleOwner Attribute
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "WriteProperty"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID = $GuidMap["FSMORoleOwner"]
$ACE02 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Setting ACE
$ACL = Get-Acl AD:\$ObjectDN
$ACL.AddAccessRule($ACE01)
$ACL.AddAccessRule($ACE02)
$ACL|Set-ACL


### PDC Emulator
$ObjectDN = $RootDSE.defaultNamingContext
### Change-PDC
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "ExtendedRight"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID =  $ExtendedRightsMap["Change PDC"]
$ACE01 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Write Permission FSMORoleOwner Attribute
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "WriteProperty"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID = $GuidMap["FSMORoleOwner"]
$ACE02 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Setting ACE
$ACL = Get-Acl AD:\$ObjectDN
$ACL.AddAccessRule($ACE01)
$ACL.AddAccessRule($ACE02)
$ACL|Set-ACL


### RID Master
$ObjectDN = "CN=RID Manager$,CN=System," + $RootDSE.defaultNamingContext
### Change-Rid-Master
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "ExtendedRight"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID =  $ExtendedRightsMap["Change Rid Master"]
$ACE01 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Write Permission FSMORoleOwner Attribute
[System.Security.Principal.SecurityIdentifier] $ManageFSMOSecId = $ManageFSMO.SID
[System.DirectoryServices.ActiveDirectoryRights] $ADRights = "WriteProperty"
[System.Security.AccessControl.AccessControlType] $AccCtrlType = "Allow"
[System.GUID] $GUID = $GuidMap["FSMORoleOwner"]
$ACE02 = New-Object -TypeName System.DirectoryServices.ActiveDirectoryAccessRule -ArgumentList $ManageFSMOSecId,$ADRights,$AccCtrlType,$GUID
### Setting ACE
$ACL = Get-Acl AD:\$ObjectDN
$ACL.AddAccessRule($ACE01)
$ACL.AddAccessRule($ACE02)
$ACL|Set-ACL



Si vous regardez bien, le code est quasiment identique pour chacun des rôles, seul le droit étendu et le Distinguished Name changent.
J'aurai pu aussi simplifier le code au niveau des ACE car il y a beaucoup de redondance mais je trouve plus lisible d'avoir tous les paramètres du constructeur.

J'espère que cet article vous aura intéressé.
A bientôt.