
ProfileHound - Collecteur OpenGraph de BloodHound pour les profils utilisateurs stockés sur les machines du domaine. Prenez des décisions éclairées sur la récupération de secrets en identifiant les profils utilisateurs actifs sur les machines du domaine.
____ _____ __ __ __ __
/ __ \_________ / __(_) /__ / / / /___ __ ______ ____/ /
/ /_/ / ___/ __ \/ /_/ / / _ \/ /_/ / __ \/ / / / __ \/ __ /
/ ____/ / / /_/ / __/ / / __/ __ / /_/ / /_/ / / / / /_/ /
/_/ /_/ \____/_/ /_/_/\___/_/ /_/\____/\__,_/_/ /_/\__,_/
ProfileHound est un outil de post-élévation de privilèges qui aide à identifier et à atteindre les objectifs de red team en localisant les profils d'utilisateurs de domaine sur les machines. Il utilise le format OpenGraph de BloodHound pour construire une nouvelle arête appelée HasUserProfile qui détermine si un profil utilisateur existe sur un ordinateur. Cette arête permet aux opérateurs de prendre des décisions éclairées sur les ordinateurs à cibler pour récupérer des secrets.
Cet outil nécessite un accès administratif au partage C$ sur les machines cibles pour énumérer les profils utilisateur.
Un immense merci à Remi Gascou (@podalirius) pour les outils ShareHound et bhopengraph. Je souhaitais depuis un certain temps construire un outil pour collecter ces données, et l'utilisation de ces bibliothèques m'a permis de me concentrer sur le développement plutôt que sur la plomberie.
[!WARNING] ProfileHound est à un stade précoce de développement et n'implémente pas encore tous les modes de collecte. À utiliser avec prudence dans les environnements de production, vous assumez les risques liés à l'utilisation de cet outil.
Les objectifs de post-exploitation dans Active Directory sont passés des données stockées sur site aux applications SaaS et au cloud. Pour prouver notre valeur en sécurité offensive, nous devons démontrer comment l'accès à ces services peut être compromis. Dans de nombreux cas, ces services ne sont utilisés que par certains groupes ou utilisateurs, comme les RH, les finances, etc. Dans certains scénarios, certaines applications SaaS ne sont accessibles que depuis des machines spécifiques.
L'arête HasSession de BloodHound est excellente, mais elle n'est utile que lorsqu'un utilisateur est connecté à une machine. Si un utilisateur n'est pas connecté à une machine au moment de la collecte des données, il peut être difficile de trouver quel ordinateur peut contenir des secrets pour faciliter une exploitation ultérieure. Les profils utilisateur peuvent contenir une quantité importante de renseignements précieux dans DPAPI, des identifiants en cache, des clés SSH, des clés cloud, et plus encore - ces éléments ne nécessitent pas de session utilisateur active pour être accessibles.

ProfileHound utilise le format OpenGraph de BloodHound pour construire une nouvelle arête de graphe appelée HasUserProfile qui détermine si un profil utilisateur existe sur une machine du domaine. Cela peut aider les opérateurs à se concentrer sur les machines où un utilisateur ou un groupe à forte valeur possède un profil.
L'arête HasUserProfile contient des propriétés pour la date de création et la date de dernière modification du profil. Ces informations aident à déterminer :

Cette arête possède également des propriétés pour les horodatages de création et de modification du profil, ce qui permet à des requêtes Cypher spécifiques de trouver des profils utilisateur actifs ou de longue durée sur des machines spécifiques.
Installez ProfileHound avec pipx (sauf si vous aimez l'enfer des dépendances) :
pipx install profilehound
Pour utiliser la version de pointe, vous pouvez installer à partir des sources :
pipx install git+https://github.com/m4lwhere/profilehound.git
Pour une approche conteneurisée, construisez l'image et exécutez l'outil comme suit :
docker build -t profilehound .
docker run --rm profilehound --help
docker run --rm -v ${PWD}:/profilehound profilehound --auth-user alice --auth-password whiteRabbit --auth-domain sccm.lab --dns 192.168.57.10 --auth-dc-ip 192.168.57.10
Par exemple, pour exécuter avec un compte Admin de domaine sccm.lab\alice et le mot de passe whiteRabbit :
$ profilehound --auth-user alice --auth-password whiteRabbit --auth-domain sccm.lab --target 192.168.57.0/27
____ _____ __ __ __ __
/ __ \_________ / __(_) /__ / / / /___ __ ______ ____/ /
/ /_/ / ___/ __ \/ /_/ / / _ \/ /_/ / __ \/ / / / __ \/ __ /
/ ____/ / / /_/ / __/ / / __/ __ / /_/ / /_/ / / / / /_/ /
/_/ /_/ \____/_/ /_/_/\___/_/ /_/\____/\__,_/_/ /_/\__,_/ v0.1.1
@m4lwhere
BloodHound CE OpenGraph collector for user profiles stored on domain machines.
[12/30/25 11:58:05] INFO Loaded 32 targets
[12/30/25 11:58:08] INFO Successful authentication on 192.168.57.10 (192.168.57.10) as sccm.lab\alice
INFO Successfully connected to share \\192.168.57.10\C$ as sccm.lab\alice
INFO Enumerating profiles in \\192.168.57.10\C$\Users\...
INFO vagrant: S-1-5-21-3016982856-3796307652-1246469985-1000 created:2025-11-07 modified:2025-11-07
INFO Found 1 domain profile(s) for 192.168.57.10
INFO Successful authentication on 192.168.57.11 (192.168.57.11) as sccm.lab\alice
[12/30/25 11:58:09] INFO Successfully connected to share \\192.168.57.11\C$ as sccm.lab\alice
INFO Enumerating profiles in \\192.168.57.11\C$\Users\...
INFO administrator: S-1-5-21-3016982856-3796307652-1246469985-500 created:2025-11-07 modified:2025-11-07
INFO alice: S-1-5-21-3016982856-3796307652-1246469985-1112 created:2025-12-28 modified:2025-11-07
INFO eve: S-1-5-21-3016982856-3796307652-1246469985-1116 created:2025-12-27 modified:2025-11-07
INFO Found 3 domain profile(s) for 192.168.57.11
INFO Successful authentication on 192.168.57.12 (192.168.57.12) as sccm.lab\alice
INFO Successfully connected to share \\192.168.57.12\C$ as sccm.lab\alice
INFO Enumerating profiles in \\192.168.57.12\C$\Users\...
INFO alice: S-1-5-21-3016982856-3796307652-1246469985-1112 created:2025-12-28 modified:2025-12-28
INFO franck: S-1-5-21-3016982856-3796307652-1246469985-1117 created:2025-12-27 modified:2025-11-07
INFO sccm-sql: S-1-5-21-3016982856-3796307652-1246469985-1121 created:2025-11-07 modified:2025-11-07
INFO Found 3 domain profile(s) for 192.168.57.12
INFO Successful authentication on 192.168.57.13 (192.168.57.13) as sccm.lab\alice
INFO Successfully connected to share \\192.168.57.13\C$ as sccm.lab\alice
INFO Enumerating profiles in \\192.168.57.13\C$\Users\...
INFO alice: S-1-5-21-3016982856-3796307652-1246469985-1112 created:2025-12-26 modified:2025-12-28
INFO sccm-account-da: S-1-5-21-3016982856-3796307652-1246469985-1119 created:2025-12-26 modified:2025-11-07
INFO Found 2 domain profile(s) for 192.168.57.13
[12/30/25 11:59:27] INFO Found 4 machines with profiles
INFO Exported OpenGraph intel to profilehound_20251230-115805.json
Ceci crée un fichier nommé profilehound_20251230-115805.json dans le répertoire courant. Ce fichier peut être importé directement dans BHCE en le glissant-déposant dans l'interface BloodHound. Il sera automatiquement analysé et établira une corrélation entre les nœuds via le SID. La nouvelle arête HasUserProfile sera créée pour montrer la relation entre l'utilisateur et le profil.
ProfileHound affichera également un petit résumé de statistiques sur la console une fois terminé :
╭───────────────────────── General Summary ──────────────────────────────╮
│ ProfileHound Statistics │
│ Total Targets with Profiles 4 │
│ Total Unique Profiles (Users) 7 │
│ Average Profiles per Target 2.25 │
╰────────────────────────────────────────────────────────────────────────╯
Top Connected Users
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ User ┃ Machine Count ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ alice │ 3 │
│ vagrant │ 1 │
│ administrator │ 1 │
│ eve │ 1 │
│ franck │ 1 │
└───────────────┴───────────────┘
Top Populated Machines
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Machine ┃ Profile Count ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ 192.168.57.11 │ 3 │
│ 192.168.57.12 │ 3 │
│ 192.168.57.13 │ 2 │
│ 192.168.57.10 │ 1 │
└───────────────┴───────────────┘
Oldest User Profiles
┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ User ┃ Machine ┃ Created ┃ Last Modified ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ vagrant │ DC.sccm.lab │ 2025-11-07 │ 2025-11-07 │
│ sccm-sql │ MSSQL.sccm.lab │ 2025-11-07 │ 2025-11-07 │
│ administrator │ MECM.sccm.lab │ 2025-11-07 │ 2025-11-07 │
│ sccm-account-da │ CLIENT.sccm.lab │ 2025-12-26 │ 2025-11-07 │
│ alice │ CLIENT.sccm.lab │ 2025-12-26 │ 2025-12-28 │
└─────────────────┴─────────────────┴────────────┴───────────────┘
Longest Lived Profiles (Created -> Modified)
┏━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ User ┃ Machine ┃ Age (Days) ┃ Created ┃ Last Modified ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ alice │ CLIENT.sccm.lab │ 1.8 │ 2025-12-26 │ 2025-12-28 │
│ alice │ MSSQL.sccm.lab │ 0.0 │ 2025-12-28 │ 2025-12-28 │
│ sccm-sql │ MSSQL.sccm.lab │ 0.0 │ 2025-11-07 │ 2025-11-07 │
│ administrator │ MECM.sccm.lab │ 0.0 │ 2025-11-07 │ 2025-11-07 │
│ vagrant │ DC.sccm.lab │ 0.0 │ 2025-11-07 │ 2025-11-07 │
└───────────────┴─────────────────┴────────────┴────────────┴───────────────┘
Top 5 Machines to Focus On (Hubs)
┏━━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Machine ┃ Score ┃ Reason ┃
┡━━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ MECM.sccm.lab │ 4.5 │ Has 3 profiles, potential lateral movement hub │
│ MSSQL.sccm.lab │ 4.5 │ Has 3 profiles, potential lateral movement hub │
│ CLIENT.sccm.lab │ 3.5 │ Has 2 profiles, potential lateral movement hub │
│ DC.sccm.lab │ 1.0 │ Has 1 profiles, potential lateral movement hub │
└─────────────────┴───────┴────────────────────────────────────────────────┘
ProfileHound utilise le partage C$ pour énumérer les profils utilisateur sur une machine du domaine à l'adresse \\<target>\C$\Users\. Il lit le fichier NTUSER.DAT de l'utilisateur pour déterminer si le compte est un compte de domaine ou un compte local en récupérant le SID à partir des métadonnées du fichier. Par exemple, il rassemble tous les répertoires utilisateur dans \\<target>\C$\Users\, puis parcourt chaque répertoire pour trouver le fichier NTUSER.DAT à l'adresse \\<target>\C$\Users\<username>\NTUSER.DAT. Si le fichier NTUSER.DAT appartient à un SID bien connu, il tentera de trouver le SID de l'utilisateur en lisant son répertoire DPAPI (par exemple \\<target>\C$\Users\<username>\AppData\Roaming\Microsoft\Protect\<SID>).
Comme nous accédons au partage C$, nous avons besoin d'un compte administratif pour nous authentifier sur la machine cible. ProfileHound utilisera les identifiants fournis pour s'authentifier sur la machine cible. Si vous utilisez un compte de domaine, vous pouvez utiliser l'option --auth-domain pour spécifier le domaine. Si vous utilisez un compte local, vous pouvez utiliser l'option --smb-local-auth.
Par défaut, ProfileHound s'arrête après un échec d'authentification de domaine SMB afin de réduire le risque de verrouillage de compte. Si certains points de terminaison sont susceptibles de refuser l'authentification de domaine et que vous souhaitez continuer à analyser les cibles restantes, utilisez --smb-ignore-failed-domain-auth.
Si ProfileHound s'arrête pendant la collecte de données SMB après avoir déjà trouvé des profils, il tentera d'exporter les résultats OpenGraph partiels avant de se terminer.
Les dates de création et de dernière modification du fichier NTUSER.DAT sont collectées et peuvent être utilisées pour déterminer si le profil est actif. Cette corrélation est traitée dans les requêtes Cypher sur les propriétés de l'arête, avec des exemples ci-dessous.
Il est intéressant de noter que si le fichier NTUSER.DAT a été modifié pour la dernière fois avant sa date de création, il est probable que le profil ait été créé mais n'ait pas été utilisé de manière tangible. Cette condition existe car le fichier NTUSER.DAT est copié à partir du profil C:\Users\Default lors de la création d'un nouveau profil utilisateur, en conservant la même date de modification même si la date de création est postérieure. De ce fait, nous pouvons être raisonnablement certains que ce profil ne contiendra aucun secret.
ProfileHound utilise la bibliothèque ShareHound de @podalirius_ pour énumérer les cibles. Si les options --target ou --target-file ne sont pas fournies, ProfileHound énumérera les cibles en se connectant à LDAP pour rassembler automatiquement tous les FQDN de machines du domaine.
On peut tirer beaucoup de conclusions puissantes de ces données, qui nous indiquent où concentrer notre attention. Toutes ces requêtes peuvent être importées dans BloodHound en glissant-déposant le fichier ProfileHound_Cypher_Queries.zip dans l'interface BloodHound à l'aide du bouton Import de la page Saved Queries. Voici quelques exemples :
Ceci est une requête simple qui trouvera tous les profils utilisateur dans le graphe.
MATCH p=(u:User)-[:HasUserProfile]->(c:Computer)
RETURN p
Cette requête trouvera tous les profils utilisateur qui sont membres du groupe "Administrators" du domaine.
MATCH p=(g:Group)<-[:MemberOf*1..]-(u:User)-[:HasUserProfile]->(c:Computer)
WHERE toLower(g.samaccountname) = "administrators"
RETURN p
Cette requête trouvera tous les profils utilisateur qui ont été modifiés au cours des 3 derniers jours. Cela aide à déterminer où un profil utilisateur peut correspondre à la machine principale d'un utilisateur et contenir un bon butin.
WITH 3 as active_days
MATCH p = (u:User)-[e:HasUserProfile]-(c:Computer)
WHERE e.profileModified > (datetime().epochseconds - (active_days * 86400))
RETURN p
C'est une requête extrêmement puissante pour localiser les profils utilisateur spécifiques utilisés au cours des 3 derniers jours par les membres d'un groupe donné.
WITH 3 as active_days, "administrators" as group_name
MATCH p = (g:Group)<-[:MemberOf*1..]-(u:User)-[e:HasUserProfile]-(c:Computer)
WHERE e.profileModified > (datetime().epochseconds - (active_days * 86400)) AND toLower(g.samaccountname) = group_name
RETURN p
Cette requête supprimera tous les profils utilisateur pour lesquels le fichier NTUSER.DAT a été modifié avant la date de création. Cela indique que le profil a été créé, mais n'a pas été utilisé de manière tangible. Cette condition existe car le fichier NTUSER.DAT est copié à partir du profil C:\Users\Default lors de la création d'un nouveau profil utilisateur, en conservant la même date de modification même si la date de création est postérieure.
match p = (u:User)-[e:HasUserProfile]-(c:Computer)
where e.profileCreated < e.profileModified
return p
Tout cela n'aurait tout simplement pas été possible sans les bibliothèques ShareHound et bhopengraph de Remi Gascou (@podalirius).
L'objectif de cet outil est de déterminer quelles machines sont les plus susceptibles de contenir des secrets pour des utilisateurs spécifiques. Les améliorations futures incluront :
get_lastlogon pour créer des arêtes HasUserProfile sur les machines.get_puser pour associer les utilisateurs de domaine comme propriétaires principaux des appareils pour des machines spécifiques.AZDeviceOwner à .data.owners[owner.DeviceOwner.onPremisesSecurityIdentifier]NTUSER.DAT