Analyse de msDS-KeyCredentialLink pour l'attaque Shadow Credentials

Table des matières :

Introduction

Les services de certificats Active Directory (AD CS) sont un rôle de serveur qui permet de construire une infrastructure de clé publique (PKI) et de fournir des capacités de cryptographie à clé publique, de certificats numériques et de signatures numériques pour votre organisation. Depuis la publication de “Certified Pre-Owned: Abusing Active Directory Certificate Services” en 2021 par Will Schroeder (@harmj0y) et Lee Christensen (@tifkin_), de nombreuses attaques sont connues sur AD CS. L’une d’entre elles relève davantage d’une technique de persistance et est connue sous le nom d’attaque de shadow credentials.

Une attaque de shadow credentials sur Active Directory implique qu’un attaquant ajoute un certificat à un compte machine qu’il contrôle. Cela permet à l’attaquant de s’authentifier en tant que cette machine et d’effectuer des actions en son nom, potentiellement en obtenant un accès non autorisé aux ressources. Au cœur de cette technique se trouve l’attribut LDAP msDS-KeyCredentialLink qui stocke le certificat utilisé pour s’authentifier auprès du compte machine.

L’attribut LDAP msDS-KeyCredentialLink est utilisé pour stocker les informations d’authentification par clé publique associées à un objet ordinateur ou utilisateur. Lorsqu’un certificat est ajouté à un compte, il est stocké dans cet attribut.

Vous pouvez consulter ces informations en tant qu’administrateur système en ouvrant la console Utilisateurs et ordinateurs Active Directory et en activant les Fonctionnalités avancées.

Activer les fonctionnalités avancées

Ensuite, sur le compte machine ayant des certificats installés, accédez à Propriétés, puis à Éditeur d'attributs, puis faites défiler jusqu’à trouver l’attribut msDS-KeyCredentialLink.

Afficher l’attribut

Dans cet éditeur d’attributs, nous voyons :

B:828:0002000020000108E2E5700BC0E9522D434C139C15B767678284D922DF7E92BA0DD17D62407E9D20000
2A786DBE1C8FD5259753E75E32DE90CA2CBE04D2A2AF4DACC29DB7C6B06FE3E411B0103525341310008000003
000000000100000000000000000000010001CC86F6DEB74305A202C68F94489B82C499C6F21A74D5E290869E8
2FFF5B5774B961251741E42D7FEC1F5EEAE52B5C759DE321491987D6586F9F3672B4E5B88EB32827480D4444D
958275113832EA7B52E91E8ED414796E6AE9061BE323D3BBFACF4448FE2451DF9325393FE1189CE53E7AE6D02
E7710D71EB1F16B8ACCF13EB63F34834021DAF3398962A6C1DF4F359CE9A81BD2E6FA3D9DD095898C9FC2E231
6DD10B59A5C0C09A71EA12CE70E3AC6EA42C74E258A0C13F102577B9AB2B55658A4F72CAFCDF26B0EBB124EEB
3F7D97BD705D04FFA4B0D4C442F68CDC724A5DD4B42B114BB3A667A54F7A733A26F7AFC6FA09CEC688246EC32
494668148C09950100040101000500100006335A9368151ACC785211B3C9DA8EC9720200070100080008A7E1A
5606E06DA0

Ce format est une structure DN with Binary. Elle est divisée en trois parties :

  1. Une lettre indiquant le type de l’objet. Il s’agit du préfixe qui indique que la chaîne est un DN-Binary (Si elle commence par un S, c’est un objet DN-String).

  2. La longueur de la chaîne hexadécimale. Le nombre qui suit les deux-points (828 dans ce cas) est la longueur de la chaîne hexadécimale contenant les données binaires.

  3. La chaîne hexadécimale contenant les données brutes. Il s’agit des données brutes de la structure. Dans le contexte de l’attribut msDS-KeyCredentialLink, ces données représentent le certificat ajouté à un compte.

  4. Le distinguished name de l’objet dans LDAP. Ce distinguished name (DN) identifie de manière unique une entrée dans l’annuaire LDAP. Dans cet exemple, le distinguished name est CN=podalirius,CN=Users,DC=lab,DC=local.

Pour analyser ces données, vous devriez d’abord séparer les trois parties en fonction des deux-points. Ensuite, vous convertissez l’hexadécimal en bytes. Voici un résumé de ce format DN with Binary :

Structure DN with Binary

Maintenant que nous savons comment analyser la structure DN-Binary, nous devons encore analyser les données brutes qui s’y trouvent.

Analyse du certificat

Les données brutes du certificat sont une structure BCRYPT_RSAKEY_BLOB, une structure qui représente une clé RSA. Dans ce cas, il s’agit d’une clé publique, mais la structure peut également être utilisée pour représenter des clés privées. La structure BCRYPT_RSAKEY_BLOB contient des informations sur la clé, telles que le type de clé, la longueur de la clé, et l’exposant public, suivi par le module de la clé RSA. Voici un schéma pour vous aider à visualiser cette structure :

Structure RSA

Écriture d’une bibliothèque

Afin de pouvoir créer une version Python de l’outil Whisker d’Elad Shamir avec mon collègue Shutdown (nous l’avons appelée pyWhisker), et pour simplifier le processus d’analyse et de génération des valeurs msDS-KeyCredentialLink, j’ai créé une bibliothèque Python appelée pydsinternals. Cette bibliothèque s’inspire de la bibliothèque DSInternals de Michael Grafnetter. La bibliothèque pydsinternals offre un ensemble d’outils et de fonctions qui vous permettent d’analyser et de générer des valeurs msDS-KeyCredentialLink à partir de vos scripts Python.

La bibliothèque comprend des classes telles que DNWithBinary et KeyCredential, qui représentent respectivement la structure DN avec les données binaires et les informations d’identité de la clé. Ces classes fournissent des méthodes pour analyser les données brutes dans un format structuré et pour générer un nouveau certificat X509, puis l’exporter dans le format attendu pour la valeur msDS-KeyCredentialLink.

Voici un exemple de la manière dont vous pouvez utiliser la bibliothèque pydsinternals pour analyser une valeur msDS-KeyCredentialLink :

# Import the necessary modules
from dsinternals.common.data.hello.KeyCredential import KeyCredential
from dsinternals.common.data.DNWithBinary import DNWithBinary

# The msDS_KeyCredentialLink attribute is a DN with Binary that contains the certificate added to a machine account
msDS_KeyCredentialLink = b"B:828:0002000020000108E2E5700BC0E9522D434C139C15B767678284D922DF7E92BA0DD17D62407E9D200002A786DBE1C8FD5259753E75E32DE90CA2CBE04D2A2AF4DACC29DB7C6B06FE3E411B0103525341310008000003000000000100000000000000000000010001CC86F6DEB74305A202C68F94489B82C499C6F21A74D5E290869E82FFF5B5774B961251741E42D7FEC1F5EEAE52B5C759DE321491987D6586F9F3672B4E5B88EB32827480D4444D958275113832EA7B52E91E8ED414796E6AE9061BE323D3BBFACF4448FE2451DF9325393FE1189CE53E7AE6D02E7710D71EB1F16B8ACCF13EB63F34834021DAF3398962A6C1DF4F359CE9A81BD2E6FA3D9DD095898C9FC2E2316DD10B59A5C0C09A71EA12CE70E3AC6EA42C74E258A0C13F102577B9AB2B55658A4F72CAFCDF26B0EBB124EEB3F7D97BD705D04FFA4B0D4C442F68CDC724A5DD4B42B114BB3A667A54F7A733A26F7AFC6FA09CEC688246EC32494668148C09950100040101000500100006335A9368151ACC785211B3C9DA8EC9720200070100080008A7E1A5606E06DA01080009A7E1A5606E06DA01:CN=DC01,OU=Domain Controllers,DC=LAB,DC=local"

# Parse the DN with Binary data blob
data = DNWithBinary.fromRawDNWithBinary(msDS_KeyCredentialLink)

# Create a KeyCredential object from the parsed data
kc = KeyCredential.fromDNWithBinary(data)

# Display the parsed contents of the KeyCredential object
kc.show()

Et vous aurez une description complète de la valeur de l’attribut:

Références