Skip to main content

ProfileHound - BloodHound OpenGraph collector for user profiles stored on domain machines. Make informed decisions about looting secrets by identifying active user profiles on domain machines.

Project description

    ____             _____ __     __  __                      __
   / __ \_________  / __(_) /__  / / / /___  __  ______  ____/ /
  / /_/ / ___/ __ \/ /_/ / / _ \/ /_/ / __ \/ / / / __ \/ __  /
 / ____/ /  / /_/ / __/ / /  __/ __  / /_/ / /_/ / / / / /_/ /
/_/   /_/   \____/_/ /_/_/\___/_/ /_/\____/\__,_/_/ /_/\__,_/

ProfileHound

ProfileHound is a post-escalation tool to help find and achieve red-teaming objectives by locating domain user profiles on machines. It uses the BloodHound OpenGraph format to build a new edge called HasUserProfile which determines if a user profile exists on a computer. This edge allows operators to make informed decisions about which computers to target for looting secrets.

This tool requires administrative access to the C$ share on target machines to enumerate user profiles.

Huge thank you to Remi Gascou (@podalirius) for the ShareHound and bhopengraph tools. I've wanted to build a tool to collect this data for a while and using these libraries allowed me to focus on building instead of plumbing.

[!WARNING] ProfileHound is in early stages of development and does not have all collection modes implemented yet. Use with caution in production environments, you assume the risk of using this tool.

Why?

Post-exploitation objectives in Active Directory have shifted from data stored on-site into SaaS applications and the cloud. To prove value in offsec, we need to demonstrate how access to these services can be compromised. In many cases, these services are used only by certain groups or users, such as HR, Finance, etc. In some scenarios, certain SaaS applications can only be accessed from specific machines.

BloodHound's HasSession edge is great, but it's only useful when a user is logged into a machine. If a user is not logged into a machine when the data is collected, it's much more difficult to find which computer may contain secrets to facilitate further exploitation. User profiles may contain a significant amount of valuable intel within DPAPI, cached credentials, SSH keys, cloud keys, and more - these don't require an active user session to access.

HasUserProfile Edge Example

ProfileHound uses BloodHound's OpenGraph format to build a new graph edge called HasUserProfile which determines if a user profile exists on a domain machine. This can help operators focus on machines where a high-value user or group has a profile.

This edge also has properties for the profile creation and modification timestamps, allowing specific Cypher queries to find active or long-term user profiles on specific machines.

Installation

Install ProfileHound using pipx (unless you enjoy dependency hell):

pipx install profilehound

To use the bleeding edge version, you can install from source:

pipx install git+https://github.com/m4lwhere/profilehound.git

Docker

To use a containerized approach, build the image and run the tool with the following:

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

Usage

For example, to run using a Domain Admin account sccm.lab\alice with password whiteRabbit:

profilehound --auth-user alice --auth-password whiteRabbit --auth-domain sccm.lab --dns 192.168.57.10 --auth-dc-ip 192.168.57.10
    ____             _____ __     __  __                      __
   / __ \_________  / __(_) /__  / / / /___  __  ______  ____/ /
  / /_/ / ___/ __ \/ /_/ / / _ \/ /_/ / __ \/ / / / __ \/ __  /
 / ____/ /  / /_/ / __/ / /  __/ __  / /_/ / /_/ / / / / /_/ /
/_/   /_/   \____/_/ /_/_/\___/_/ /_/\____/\__,_/_/ /_/\__,_/    v0.1.0
@m4lwhere

BloodHound CE OpenGraph collector for user profiles stored on domain machines.

[2025-12-29 16:59:58] [INFO] Loaded 4 targets
[2025-12-29 16:59:58] [INFO] Successful authentication on CLIENT.sccm.lab (192.168.57.13) as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Successfully connected to share \\CLIENT.sccm.lab\C$ as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Enumerating profiles in \\CLIENT.sccm.lab\C$\Users\...
[2025-12-29 16:59:59] [INFO]     alice: S-1-5-21-3016982856-3796307652-1246469985-1112  created:2025-12-26      modified:2025-12-28
[2025-12-29 16:59:59] [INFO]     sccm-account-da:       S-1-5-21-3016982856-3796307652-1246469985-1119  created:2025-12-26      modified:2025-11-07
[2025-12-29 16:59:59] [INFO] Found 2 domain profile(s) for CLIENT.sccm.lab
[2025-12-29 16:59:59] [INFO] Successful authentication on DC.sccm.lab (192.168.57.10) as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Successfully connected to share \\DC.sccm.lab\C$ as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Enumerating profiles in \\DC.sccm.lab\C$\Users\...
[2025-12-29 16:59:59] [INFO] No domain profiles found for DC.sccm.lab
[2025-12-29 16:59:59] [INFO] Successful authentication on MECM.sccm.lab (192.168.57.11) as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Successfully connected to share \\MECM.sccm.lab\C$ as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Enumerating profiles in \\MECM.sccm.lab\C$\Users\...
[2025-12-29 16:59:59] [INFO]     alice: S-1-5-21-3016982856-3796307652-1246469985-1112  created:2025-12-28      modified:2025-11-07
[2025-12-29 16:59:59] [INFO]     eve:   S-1-5-21-3016982856-3796307652-1246469985-1116  created:2025-12-27      modified:2025-11-07
[2025-12-29 16:59:59] [INFO] Found 2 domain profile(s) for MECM.sccm.lab
[2025-12-29 16:59:59] [INFO] Successful authentication on MSSQL.sccm.lab (192.168.57.12) as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Successfully connected to share \\MSSQL.sccm.lab\C$ as sccm.lab\alice
[2025-12-29 16:59:59] [INFO] Enumerating profiles in \\MSSQL.sccm.lab\C$\Users\...
[2025-12-29 16:59:59] [INFO]     alice: S-1-5-21-3016982856-3796307652-1246469985-1112  created:2025-12-28      modified:2025-12-28
[2025-12-29 16:59:59] [INFO]     franck:        S-1-5-21-3016982856-3796307652-1246469985-1117  created:2025-12-27      modified:2025-11-07
[2025-12-29 16:59:59] [INFO] Found 2 domain profile(s) for MSSQL.sccm.lab
[2025-12-29 16:59:59] [INFO] Found 3 targets with profiles
[2025-12-29 16:59:59] [INFO] Exported OpenGraph intel to profilehound_20251229-165958.json

This created a file called profilehound_20251229-165958.json in the current directory. This file can be imported directly into BHCE by dragging and dropping the file into the BloodHound UI. It will automatically be parsed and correlate nodes via SID. The new edge HasUserProfile will be created to show the relationship between the user and the profile.

How it Works

ProfileHound uses the C$ share to enumerate user profiles on a domain machine at \\<target>\C$\Users\. It will read the user's NTUSER.DAT file to determine if the user is a domain account or local account by retrieving the SID from the file metadata. For example, it will gather all user directories at \\<target>\C$\Users\ and then loop over each directory to find the NTUSER.DAT file at \\<target>\C$\Users\<username>\NTUSER.DAT. If the NTUSER.DAT file is owned by a well-known SID, it will try to find the user's SID by reading their DPAPI directory (e.g. \\<target>\C$\Users\<username>\AppData\Roaming\Microsoft\Protect\<SID>).

Because we are reaching the C$ share, we need an administrative account to authenticate to the target machine. ProfileHound will use the credentials provided to authenticate to the target machine. If you are using a domain account, you can use the --auth-domain option to specify the domain. If you are using a local account, you can use the --auth-local option.

The creation and last modified times of the NTUSER.DAT file are gathered and can be used to determine if the profile is active. This correlation is handled within cypher queries on the edge properties, examples are below.

It's interesting to note that if the NTUSER.DAT file is last modified before the creation date, it is likely that the profile was created but not used in a tangible way. This condition exists because the NTUSER.DAT file is copied from the C:\Users\Default profile when a new user profile is created, maintaining the same modified date even though the creation date is later. Because of this, we can be reasonably confident that specific profile will not contain any secrets.

Selecting Targets

ProfileHound uses @podalirius_ 's ShareHound as a library to enumerate targets. If no --target or --target-file options are provided, ProfileHound will enumerate targets by connecting to LDAP to gather all machine FQDNs in the domain automatically.

Fun Queries

There's a lot of powerful conclusions we can gather from this data, telling us where we should focus our attention. All of these queries can be imported into BloodHound by dragging and dropping the ProfileHound_Cypher_Queries.zip file into the BloodHound UI using the Import button on the Saved Queries page. Here are a few examples:

Find all User Profile Edges

This is a simple query that will find all user profiles in the graph.

MATCH p=(u:User)-[:HasUserProfile]->(c:Computer)
RETURN p

Find User Profiles by Group Name

This will find all user profiles that are members of the domain "Administrators" group.

MATCH p=(g:Group)<-[:MemberOf*1..]-(u:User)-[:HasUserProfile]->(c:Computer)
WHERE toLower(g.samaccountname) = "administrators"
RETURN p

Find User Profiles Active within last 3 Days

This will find all user profiles that have been modified within the last 3 days. This helps determine where a user profile might be a user's primary machine and have good loot.

WITH 3 as active_days
MATCH p = (u:User)-[e:HasUserProfile]-(c:Computer)
WHERE e.profileModified > (datetime().epochseconds - (active_days * 86400))
RETURN p

Active User Profiles within a Specific Group (Powerful)

This is an extremely powerful query to locate specific user profiles used within the last 3 days for members of a specific group.

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

Remove Unused User Profiles

This will remove any user profiles where the NTUSER.DAT file is modified before the creation date. This indicates that the profile was created, but not used in a tangible way. This condition exists because the NTUSER.DAT file is copied from the C:\Users\Default profile when a new user profile is created, maintaining the same modified date even though the creation date is later.

match p = (u:User)-[e:HasUserProfile]-(c:Computer)
where e.profileCreated < e.profileModified
return p

Credits

This simply wouldn't be possible without Remi Gascou's (@podalirius) ShareHound and bhopengraph libraries.

Future Improvements

The focus on this tool is determining which machines are most likely to contain secrets for specific users. Future improvements will include:

  • Implement @garrettfoster13's SCCMHunter as a library to improve data collection.
    • Use get_lastlogon function to create HasUserProfile edges on machines.
    • Use get_puser function to associate domain users as primary device owners for specific machines.
  • Implement Azure AD device ownership correlation from AzureHound.
    • This seems to be already collected as an AZDeviceOwner object at .data.owners[owner.DeviceOwner.onPremisesSecurityIdentifier]
  • Use ShareHound to spider for sensitive files in matching profiles and ingest into the graph.
  • Mine the NTUSER.DAT file for recent programs, documents, and browser activity.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

profilehound-0.1.1.tar.gz (15.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

profilehound-0.1.1-py3-none-any.whl (17.7 kB view details)

Uploaded Python 3

File details

Details for the file profilehound-0.1.1.tar.gz.

File metadata

  • Download URL: profilehound-0.1.1.tar.gz
  • Upload date:
  • Size: 15.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for profilehound-0.1.1.tar.gz
Algorithm Hash digest
SHA256 6ab6ccbfab780af7fee0be20b93a7c56d6d6f9ae94b7793961f124ad14c788a4
MD5 366b65b9d61c5b19352e17e05125ef7c
BLAKE2b-256 4e1cd89a98e06dc927ab365837f898fc57ef83ffcdbbc83feb6969c1c08ebad3

See more details on using hashes here.

File details

Details for the file profilehound-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: profilehound-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 17.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for profilehound-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9f0d910e5828b412eb3fecf12fccfd33549cbbccfe8edafdcec9e6d2e4fb2392
MD5 b54a076f3297d584f2c77f3fcf314bfe
BLAKE2b-256 c6f2b3759f549c929453fee293add6fbbf16b26fb630cbc40687d0ef7d61f1b5

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page