Yuval Gordon Chercheur en sécurité | Microsoft

Les systèmes d'identité - en particulier Active Directory, qui est la principale source d'identité pour la plupart des entreprises - sont constamment attaqués par les cybercriminels parce qu'ils sont la porte d'entrée des systèmes d'information critiques d'une organisation, y compris des données précieuses sur les clients.

Nous allons ici explorer une tactique peu connue de la liste de contrôle d'accès discrétionnaire (DACL) que les attaquants peuvent utiliser pour cacher l'appartenance à un groupe et éventuellement échapper à la détection. En utilisant l'attribut Primary Group ID et une entrée de contrôle d'accès (ACE) spécifique, vous pouvez masquer l'appartenance à un groupe dont vous êtes déjà membre, sans disposer d'aucune autorisation sur ce groupe. Cette astuce ne fonctionne pas avec les membres de groupes protégés tels que les administrateurs de domaine, mais peut fonctionner avec les membres de groupes normaux tels que DnsAdmins, qui peut être utilisé pour escalader vers les administrateurs de domaine.

Lire la suite

Comment Active Directory gère l'appartenance à un groupe normal

Pour bien comprendre ce que cette technique ajoute, il faut d'abord avoir une connaissance de base de la façon dont les membres des groupes sont gérés par Active Directory. Chaque contrôleur de domaine stocke une base de données Active Directory (ntds.dit). Chaque ntds.dit contient une colonne appelée DNT (Distinguished Name Tag), qui est comme l'identifiant de l'objet dans la base de données. Lorsque nous ajoutons un utilisateur à un groupe, le contrôleur de domaine ajoute une ligne à une table appelée "link_table" qui enregistre un lien entre le DNT du membre (backlink_DNT) et le DNT du groupe (link_DNT).

C'est assez simple jusqu'à présent, mais ce n'est pas tout ce qu'il y a à savoir sur l'appartenance à un groupe. Il existe un autre attribut appelé PrimaryGroupID (PGID) qui spécifie l'identifiant relatif (RID) du groupe primaire de l'utilisateur, qui est la dernière partie d'un SID principal (SID principal = SID du domaine + RID). Cet attribut est défini par défaut sur 513 (Utilisateurs du domaine) pour les nouveaux utilisateurs, 515 (Ordinateurs du domaine) pour les nouveaux ordinateurs, 516 (Contrôleurs du domaine) pour les contrôleurs de domaine et 521 pour les contrôleurs de domaine en lecture seule. Cet attribut peut également être défini en cliquant sur le bouton "Définir le groupe primaire" dans l'onglet "Membre de" de l'outil Utilisateurs et ordinateurs d'Active Directory, si l'accès en écriture requis est présent sur l'utilisateur cible.

Définition du groupe primaire dans Active Directory
Définition du groupe primaire

Cet outil permet de définir le groupe primaire uniquement sur un groupe dont l'utilisateur est déjà membre. La particularité de cet attribut - et la raison pour laquelle les administrateurs Active Directory doivent en être conscients afin de se prémunir contre les abus des adversaires - est qu'en définissant l'ID de groupe primaire (PGID), vous désactivez le lien d'appartenance entre le groupe et le membre. En d'autres termes, le lien est supprimé de la table link_table susmentionnée.

"Mais comment est-ce possible, Yuval ? Lorsque je recherche des membres du groupe Admins du domaine, je vois également des utilisateurs dont le groupe primaire est défini sur Admins du domaine !" Excellente question, lecteur !

La plupart des outils qui interrogent les membres demandent en fait deux choses. Imaginons que nous voulions obtenir tous les membres du groupe Domain Admins :

  1. L'outil demandera l'attribut membre, ce qui amènera le DC à vérifier la table link_table et à renvoyer les objets qui ont un lien membre avec le groupe Domain Admins.
  2. L'outil recherchera tout objet dont l'attribut PrimaryGroupID contient la valeur 512 (RID des administrateurs de domaine).

Pourquoi faut-il contrôler l'utilisation de l'identifiant du groupe primaire ?

En utilisant l'ID de groupe primaire, vous faites en sorte que l'appartenance à l'un des groupes soit inscrite dans un attribut du côté du membre. Pour mieux comprendre ce qui peut être réalisé avec cette action, examinons la situation du point de vue d'un attaquant.

Imaginez que vous souhaitiez cacher l'appartenance d'un utilisateur à l'un de ses groupes. Dans le cas d'une appartenance normale, vous pourriez simplement spécifier une entrée de contrôle d'accès Active Directory (ACE) pour refuser l'accès à tout le monde en "lecture de l'appartenance au groupe". Mais cette approche rendra l'appartenance de l'utilisateur presque vide (le groupe principal sera toujours affiché), ce qui peut sembler suspect. De plus, avec cette approche, l'appartenance n'est cachée que du côté du membre et non du côté du groupe. Ainsi, si quelqu'un essaie de lire l'un des membres du groupe, l'utilisateur y figurera toujours.

C'est là que le PGID entre en jeu : En spécifiant le groupe primaire, vous pouvez faire en sorte que l'appartenance ne soit répertoriée que du côté des membres. Maintenant, si vous ajoutez un ACE pour refuser à tout le monde de lire PGID sur l'objet, l'une des appartenances au groupe est maintenant cachée, à la fois du côté des membres et du côté du groupe.

Comment les attaquants peuvent utiliser le Primary Group ID pour cacher des utilisateurs malveillants

En utilisant une simple fonction PowerShell, vous pouvez cacher l'utilisateur "haxer" du groupe "attackers", en changeant le PGID en RID du groupe "attackers", puis en ajoutant un deny-read sur PGID.

Adhésion du côté de l'utilisateur
Adhésion du côté de l'utilisateur

The primary group now shows <None>. Odd, but still might go unnoticed.

Appartenance à Active Directory du côté du groupe
Adhésion du côté du groupe

Le code suivant peut être utilisé pour masquer l'appartenance à un groupe spécifique dont l'utilisateur est déjà membre, si l'utilisateur en cours d'exécution dispose d'une DACL d'écriture (Permissions de modification) sur l'utilisateur cible. Par exemple, pour me cacher (haxer) du groupe des attaquants dont je suis déjà membre (RID 2607), j'ai utilisé la fonction indiquée ci-dessus. J'ai mis l'indicateur "AddWritePGIDToCurrent" à true parce que je n'avais pas les permissions requises - je n'avais que la permission WriteDACL.

function Hide-Membership {
  param (
    [parameter(Mandatory = $true)]
    [string]$TargetDN,
             
    [parameter(Mandatory = $true)]
    [int]$RID,

    [parameter(Mandatory = $false)]
    [bool]$AddWritePGIDToCurrent = $false
  )

  $target = [ADSI]"LDAP://$TargetDN"
  $identityReference = (New-Object System.Security.Principal.NTAccount("everyone")).Translate([System.Security.Principal.SecurityIdentifier])
  $guid = New-Object Guid "bf967a00-0de6-11d0-a285-00aa003049e2" # Guid of primaryGroupID attribute

  $target.PsBase.Options.SecurityMasks = "Dacl"

  if ($AddWritePGIDToCurrent) {
    $identityReferenceCurrentUser = ([System.Security.Principal.WindowsIdentity]::GetCurrent()).User
    $aceAllow = New-Object System.DirectoryServices.ActiveDirectoryAccessRule @($identityReferenceCurrentUser,"WriteProperty","Allow",$Guid)
    $target.PsBase.ObjectSecurity.AddAccessRule($aceAllow)
    $target.CommitChanges()
  }

  $aceDeny = New-Object System.DirectoryServices.ActiveDirectoryAccessRule @($identityReference,"ReadProperty","Deny",$Guid)

  $target.PsBase.ObjectSecurity.AddAccessRule($aceDeny)
  $target.CommitChanges()
  $target.primarygroupid = $RID 
  $target.CommitChanges()
}
Hide-Membership -TargetDN "CN=haxer,CN=Users,DC=f047-d01,DC=lab" -RID 2607 -AddWritePGIDToCurrent $true

Notez que cette technique ne fonctionnera pas sur les membres d'un groupe protégé par le processus SDPROP et AdminSDHolder, car nous nous appuyons sur la DACL, qui dans ce cas sera simplement ramenée à la DACL de AdminSDHolder toutes les heures ou presque.

Détection de l'utilisation malveillante de l'identifiant du groupe primaire pour dissimuler l'appartenance à un groupe

Vous pouvez détecter l'utilisation de PGID pour masquer l'appartenance à un groupe en surveillant les ACE définis comme refusant la lecture de cette propriété. Mais cette tâche peut s'avérer difficile si l'on ne dispose pas des outils ou des systèmes appropriés.

Une option consiste à utiliser périodiquement la ligne de commande ci-dessous pour rechercher tout utilisateur dont le PGID n'est pas lisible. Je ne connais aucune raison légitime pour qu'un utilisateur ait un PGID inexistant ou illisible, mais cela peut arriver, et vous pouvez donc voir quelques faux positifs.

Get-ADUser -Filter {-not(primaryGroupID -like "*")}

Un moyen plus simple de surveiller l'utilisation malveillante de cette technique : Semperis Directory Services Protector comprend un indicateur qui surveille et alerte sur les utilisateurs ayant la configuration "Utilisateurs et ordinateurs sans PGID lisible".

Protéger Active Directory du barrage continu d'attaques peut s'avérer difficile. Mais en surveillant continuellement votre environnement pour détecter les nombreuses façons dont les attaquants peuvent exploiter certaines configurations, vous pouvez identifier les intrusions et y remédier avant qu'elles ne se transforment en véritables brèches.