samedi 2 août 2014

Comment déléguer : la gestion des Stratégies de Groupes, Partie 1

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".

Nous allons parler aujourd'hui de la gestion des Stratégies de Groupes.
De nombreuses tâches d’administration peuvent être en relation avec la gestion des Stratégies de Groupes.

Nous allons commencer par recenser toutes ces tâches :
  • Création de GPO
  • Modification de GPO
  • Liaison de GPO sur une OU ou à la racine du domaine
  • RSOP (Planning)
  • RSOP (Logging)
  • Liaison de GPO sur les Sites Active Directory
  • Création de Filtres WMI

Il y a donc un certains nombre de tâches d'administration possibles en relation avec la gestion des Stratégies de Groupes.


Création de GPO

Pour déléguer la création des GPO, plusieurs choix s'offrent à nous.
Nous pouvons tout d'abord utiliser le groupe prévu à cet effet, Group Policy Creator Owners.
Notre objectif étant de ne pas utiliser les groupes Built-in nous n'utiliserons pas cette méthode

Nous pouvons ensuite donner explicitement les droits sur les objets. Pour rappel, une GPO est composée de 2 partie,un objet de type Group Policy Container dans l'AD (GPC) et un dossier dans le SYSVOL (GPT).
Il faudrait donc déléguer les droits sur ces 2 parties ce qui est faisable mais on préfèrera éviter de toucher aux droits du SYSVOL directement.

Nous pouvons enfin utiliser la console GPMC.
Soit en via l'interface graphique, soit via l'interface IGPM (IGPM interface).
Généralement, on cherche à automatiser au maximum l'implémentation de notre modèle de délégation. On préfèrera donc utiliser l'interface IGPM qui nous permettra de scripter cette délégation.

 Voici un exemple de script :


Import-Module ActiveDirectory

$Domain = Get-ADDomain

$GroupAdminsGPO = Get-ADGroup -Identity "Admins GPO"

$GPM = New-Object -ComObject gpmgmt.gpm

$Constant=$GPM.GetConstants()
### Initialize the Domain object
$GPMDomain = $GPM.GetDomain($Domain.dnsroot, "", $Constant.UseAnyDC)

### Get a GPMSOM object representing the domain
$GPMSOM = $GPMDomain.GetSOM("")

### Get the current SecurityInfo object for the domain
$GPMSecInfo = $GPMSOM.GetSecurityInfo()

$GPMPermission = $GPM.CreatePermission($GroupAdminsGPO.Name,$Constant.PermSOMGPOCreate,$false)

$GPMSecInfo.Add($GPMPermission)
$GPMSOM.SetSecurityInfo($GPMSecInfo)

 



On peut vérifier via la console GPMC que le droit a bien été délégué.



Modification de GPO

Nous allons voir maintenant la modification des GPO.
Par défaut, lorsqu'une GPO est créée, seuls le créateur-propriétaire, les membres de "Domain Admins" et les membres de "Enterprise Admins" ont les permissions de modification de GPO.

Sur une petite structure, il est possible qu'il n'y ait qu'une seule personne qui administre les GPO.
Le comportement par défaut n'est donc pas problématique. En revanche lorsque plusieurs personnes doivent administrer les GPO, ce comportement devient problématique car seul le créateur de la GPO a les droits de modification.

Voici un exemple :



Il faut donc changer ce comportement. Pour cela nous allons modifier le DefaultSecurityDescriptor de la classe d'objet GroupPolicyContainer afin que notre groupe de délégation ait les droits sur les GPO à leur création. Cette modification est documentée chez Microsoft : How to change the default permissions on GPOs in Windows Server 2008 R2, Windows Server 2008, Windows Server 2003, and Windows 2000 Server

Cette modification peut être effectuée soit via ADSIEDIT comme dans la KB, soit en powershell. Nous allons voir la méthode avec Powershell.

On récupère d'abord le Default Security Descriptor de la classe d'objet Group-Policy-Container.


Puis on ajoute les droits à notre groupe de délégation.


On peut finir par mettre à jour le cache du schéma pour que la modification soit prise en compte immédiatement.


On peut vérifier que notre groupe de délégation à bien les droits lorsque l'on créé une GPO.



Voici le code que j'ai utilisé :

Import-Module ActiveDirectory

$RootDSE = Get-ADRootDSE

$DNGroupPolicyContainer = "CN=Group-Policy-Container," + $RootDSE.schemaNamingContext
$GroupPolicyContainer = Get-ADObject $DNGroupPolicyContainer -Properties defaultSecurityDescriptor

$GroupAdminsGPO = Get-ADGroup -Identity "Admins GPO"
$NewDefaultSecurityDescriptor = $GroupPolicyContainer.defaultSecurityDescriptor + "(A;CI;RPWPCCDCLCLOLORCWOWDSDDTSW;;;" + $GroupAdminsGPO.SID +")"
$GroupPolicyContainer.defaultSecurityDescriptor = $NewDefaultSecurityDescriptor
Set-ADObject -Instance $GroupPolicyContainer

$SchemaOwner = [System.DirectoryServices.ActiveDirectory.ActiveDirectorySchema]::GetCurrentSchema()
$SchemaOwner.RefreshSchema()



Toutefois, cette modification n'est pas suffisante. En effet, la modification ne sera effective que pour les nouvelles GPO, il nous faut donc aussi traiter les GPO existantes.

Pour faire cette modification, nous allons utiliser les Cmdlet du module GroupPolicy.
Le code est assez simple, on prend toutes les GPO (dans mon cas, c'est à adapter), on vérifie si notre groupe de délégation a des droits sur la GPO et on corrige si ce n'est pas le cas.


Voici le code (les Out-Null sont là pour éviter l'affichage en sortie de toutes les GPO) :


Import-Module ActiveDirectory, GroupPolicy

$GroupAdminsGPO = Get-ADGroup -Identity "Admins GPO"

Get-GPO -All | foreach-object {
   
    if(!($_ | Get-GPPermissions -TargetName $GroupAdminsGPO.Name -TargetType Group -ErrorAction SilentlyContinue | Out-Null)){
        $_ | Set-GPPermissions -TargetName $GroupAdminsGPO.Name -TargetType Group -PermissionLevel GpoEditDeleteModifySecurity | Out-Null}
    }

 

Je vais m'arrêter ici pour cette première partie.
Il faudra bien évidemment adapter ces morceaux de code à votre contexte et à votre besoin, l'objectif ici étant juste de vous montrer que l'on peut scripter cette partie de la délégation des GPO.

A très bientôt.

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.