esc

BloodHound & Active Directory Enumeration : The Complete Reference

๐Ÿ“… Last Updated: May 03, 2026 10:00 | ๐Ÿ“„ Size: 19.6 KB | ๐ŸŽฏ Type: Security Research Report | ๐Ÿ”— Back to Categories

BloodHound : Active Directory Attack Path Reference

What is BloodHound?

BloodHound is an open-source tool used by attackers and defenders alike to analyze Active Directory (and Azure) domain security. It collects a large amount of data about an AD environment and uses graph theory to visually represent relationships between objects : revealing attack paths that traditional enumeration would never surface.

Why it matters: AD access management is extremely complex. A user can reach Domain Admin through a chain of 6 misconfigurations that no individual ACL review would catch. BloodHound surfaces these chains instantly.

Data is gathered by the SharpHound collector (C# or PowerShell from inside the domain) or bloodhound-python (from Linux/remote). The backend is a Neo4j graph database.


Quick Command Reference

Command Description
.\SharpHound.exe -c all --zipfilename domain_bh Run SharpHound C# ingestor (all collection methods)
Invoke-BloodHound -CollectionMethod all -ZipFileName domain_bh Run SharpHound PowerShell ingestor
bloodhound-python -d <DOMAIN> -c All -u <user> -p <pass> -ns <DC_IP> Run bloodhound-python from Linux
sudo neo4j console Start Neo4j
bloodhound --no-sandbox Launch BloodHound GUI (Linux)

Installation

Windows

1. Install Java JDK 11

Download from Oracle JDK 11 and install silently:

.\jdk-11.0.17_windows-x64_bin.exe /s

2. Install Neo4j 4.4.x

Note: Stick with Neo4j 4.4.x : version 5 has severe performance regression issues with BloodHound. See official docs.

Download from Neo4j Download Center, then:

Expand-Archive .\neo4j-community-4.4.16-windows.zip .
.\neo4j-community-4.4.16\bin\neo4j.bat install-service
net start neo4j

3. Download BloodHound GUI

Grab the latest release from github.com/BloodHoundAD/BloodHound/releases.

Note: Your browser or AV may flag the download as malicious : this is expected. Allow it.


Linux

1. Add Neo4j apt source and install

wget -O - https://debian.neo4j.com/neotechnology.gpg.key | sudo apt-key add -
echo 'deb https://debian.neo4j.com stable 4.4' | sudo tee -a /etc/apt/sources.list.d/neo4j.list
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt install neo4j=1:4.4.16 -y

2. Set Java 11 as active version

sudo update-alternatives --config java
# Select the option corresponding to Java 11

3. Start Neo4j

sudo systemctl start neo4j
# or run as console to check for errors:
sudo neo4j console

Remote access: By default Neo4j only accepts local connections. To allow the BloodHound GUI on a different host to connect, edit /etc/neo4j/neo4j.conf and uncomment: #dbms.default_listen_address=0.0.0.0

4. Download and run BloodHound

unzip BloodHound-linux-x64.zip
cd BloodHound-linux-x64/
./BloodHound --no-sandbox

Configure Neo4j

Navigate to http://localhost:7474/ and log in with neo4j:neo4j.

Neo4j web console

You will be prompted to change the default password.

Change Neo4j password

Then launch BloodHound and authenticate with those same credentials:

BloodHound authentication

Recovering Neo4j Access

If you lost access to Neo4j:

sudo systemctl stop neo4j
# Edit /etc/neo4j/neo4j.conf : uncomment: dbms.security.auth_enabled=false
sudo neo4j console
# Navigate to http://localhost:7474 and click Connect (no creds)
# Run: ALTER USER neo4j SET PASSWORD 'NewPassword';
# Stop Neo4j, re-comment the line, restart

Neo4j password recovery


Data Collection

SharpHound (Windows : from inside the domain)

Run without options to use default collection (recommended starting point):

SharpHound.exe

Default collection methods: Group, LocalAdmin, Session, Trusts, ACL, Container, RDP, ObjectProps, DCOM, SPNTargets, PSRemote

This collects: users/computers, group memberships, domain trusts, abusable ACL permissions, OU structure, GPO links, local group memberships, active sessions, and all SPNs.

Note: Collecting local group memberships and sessions from remote machines requires admin rights on those machines. Without it, SharpHound still collects everything from LDAP : which is usually enough.

Common collection flags:

# Collect everything
SharpHound.exe -c all --zipfilename output_name

# Stealth mode : LDAP only, no direct computer contact
SharpHound.exe -c DCOnly

# Collect only ACLs (fast, low noise)
SharpHound.exe -c ACL

# Target specific domain
SharpHound.exe -c all -d corp.local

# Use alternate credentials
SharpHound.exe -c all -d corp.local --ldapusername user --ldappassword pass

Output: a timestamped .zip file containing JSON files ready for import.

SharpHound output zip


bloodhound-python (Linux : remote collection)

Install: pip install bloodhound

Why use this: You're on Linux and can't run SharpHound. It uses LDAP/RPC remotely with valid credentials. No foothold on a Windows host needed.

# Basic NTLM auth
bloodhound-python -d corp.local -c All -u username -p 'password' -ns <DC_IP>

# Collect only DC data (faster, less noise)
bloodhound-python -d corp.local -c DCOnly -u username -p 'password' -ns <DC_IP>

# Kerberos auth (requires DNS resolution of the DC)
echo "<DC_IP> dc01.corp.local dc01 corp corp.local" | sudo tee -a /etc/hosts
sudo ntpdate <DC_IP>   # sync time : required for Kerberos
bloodhound-python -d corp.local -c All -u username -p 'password' -ns <DC_IP> --kerberos

# Pass-the-hash
bloodhound-python -d corp.local -c All -u username --hashes 'LM:NT' -ns <DC_IP>

# Output as zip
bloodhound-python -d corp.local -c All -u username -p 'password' -ns <DC_IP> --zip

Kerberos tip: Using Kerberos makes your traffic look more like legitimate domain activity than NTLM.

Output files (unzipped by default):

ls
20230112_computers.json  20230112_domains.json  20230112_groups.json
20230112_containers.json 20230112_gpos.json     20230112_ous.json  20230112_users.json

Importing Data into BloodHound

  1. Start the neo4j service
  2. Launch BloodHound and log in
  3. Click the Upload button (top right), select your .zip or drag-and-drop it directly into the window

Upload data

You can upload multiple zip files : BloodHound deduplicates automatically.

Note: Zip files cannot be password-protected.


Navigating the GUI

On first login, BloodHound runs the Find all Domain Admins query automatically.

BloodHound interface

Graph Drawing Area

Right-clicking a node gives you:

Option Description
Set as Starting Node Use as the source in pathfinding
Set as Ending Node Use as the target in pathfinding
Shortest Paths to Here Find all paths from any node to this one
Shortest Paths to Here from Owned Find paths from nodes you've marked as owned
Mark as Owned Tag this node as compromised (used in "from owned" queries)
Mark as High Value Tag for use in "paths to high value" queries
Edit Node Add custom properties

Edges (relationship lines) all have a built-in help menu : right-click any edge to see how to abuse it, with examples and references:

Edge help menu

Search Bar Tips

Search by type using prefix syntax:

  • user:john : find user named john
  • group:domain : find groups containing "domain"
  • computer:ws01 : find computer WS01

Full list of searchable types:

Active Directory: Group, Domain, Computer, User, OU, GPO, Container

Azure: AZApp, AZRole, AZDevice, AZGroup, AZKeyVault, AZManagementGroup, AZResourceGroup, AZServicePrincipal, AZSubscription, AZTenant, AZUser, AZVM

Pathfinding

Click the pathfinding button, set a source and target node, and BloodHound finds the shortest attack path. You can also filter out specific edges if you want to avoid noisy operations like ForceChangePassword:

Pathfinding demo

Keyboard Shortcuts

Shortcut Action
CTRL Cycle node label display (default / always show / always hide)
Spacebar Open spotlight : list all drawn nodes
Backspace Go back to previous graph
S Toggle the info panel

Node Types Reference

Node What it represents
Users Accounts that can log in and access resources
Groups Collections of users/computers for permission assignment
Computers Domain-joined machines
Domains The top-level logical grouping of all resources
GPOs Group Policy Objects that enforce settings on users/computers
OUs Containers for organizing and delegating administration
Containers Organizational containers without admin control (unlike OUs)

Each node's Node Info tab shows:

Section Description
Overview General object info
Node Properties Default AD properties
Extra Properties Non-default string properties (if --CollectAllProperties was used)
Group Membership What groups this object belongs to
Local Admin Rights Where this object has local admin
Execution Rights RDP, DCOM, SQL admin, PSRemote rights
Outbound Object Control What AD objects this node has control over
Inbound Control Rights What has control over this node

User node info


Edges (Attack Relationships)

Edges are the relationships BloodHound draws between nodes. Each one represents an exploitable privilege.

Edge example

Full list of AD edges:

AdminTo MemberOf HasSession
ForceChangePassword AddMembers AddSelf
CanRDP CanPSRemote ExecuteDCOM
SQLAdmin AllowedToDelegate DCSync
GetChanges/GetChangesAll GenericAll WriteDacl
GenericWrite WriteOwner WriteSPN
Owns AddKeyCredentialLink ReadLAPSPassword
ReadGMSAPassword Contains GpLink

Always right-click an edge to open the help menu : it shows exactly how to abuse that relationship, with tools and commands.


Cypher Queries

BloodHound uses Cypher, Neo4j's query language. You can run custom queries in the Raw Query bar at the bottom of the interface.

Enable Query Debug Mode in Settings to see the raw Cypher behind every built-in query.

Cypher Syntax Basics

Element Syntax Example
Node (variable:Label) (u:User)
Property filter {key: "value"} {name: "john@corp.local"}
Relationship -[r:TYPE]-> -[r:MemberOf]->
Variable depth [r:TYPE*1..] *1.. = any depth
Path p = (n)-[...]->(m) Assign path to variable p
Keywords MATCH, WHERE, RETURN

Essential Built-in Queries

Shortest paths to Domain Admins:

MATCH p=shortestPath((n)-[*1..]->(m:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
WHERE NOT n=m
RETURN p

Shortest path to DA


Power Queries (Save These)

Find all paths from a compromised user to anything : the most useful query during an engagement:

MATCH p = shortestPath((n)-[*1..]->(c))
WHERE n.name =~ '(?i)john.*' AND NOT c=n
RETURN p

Replace john with the username you've compromised. If standard DA queries return nothing, this shows you every other path available from that user : to machines, groups, GPOs, anything.

Use allShortestPaths instead of shortestPath to get every possible route, not just the shortest.


Find specific rights that Domain Users should not have over computers:

MATCH p=(g:Group)-[r:Owns|WriteDacl|GenericAll|WriteOwner|ExecuteDCOM|GenericWrite|AllowedToDelegate|ForceChangePassword]->(c:Computer)
WHERE g.name STARTS WITH "DOMAIN USERS"
RETURN p

Find users with non-blank description fields (passwords stored here is common):

MATCH (u:User)
WHERE u.description IS NOT NULL
RETURN u.name, u.description

Users with descriptions

Run this from the Neo4j browser at http://localhost:7474 if BloodHound doesn't display tabular results.


Find all local admins per machine (great for client reporting):

MATCH (c:Computer)
OPTIONAL MATCH (u1:User)-[:AdminTo]->(c)
OPTIONAL MATCH (u2:User)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c)
WITH COLLECT(u1) + COLLECT(u2) AS TempVar,c
UNWIND TempVar AS Admins
RETURN c.name AS COMPUTER, COUNT(DISTINCT(Admins)) AS ADMIN_COUNT, COLLECT(DISTINCT(Admins.name)) AS USERS
ORDER BY ADMIN_COUNT DESC

Local admins query


Find any node with a specific edge (replace WriteSPN with any edge you're hunting):

MATCH p=((n)-[r:WriteSPN]->(m)) RETURN p

WriteSPN edge query


Find group membership path with regex (case-insensitive):

MATCH p=(n:User)-[r1:MemberOf*1..]->(g:Group)
WHERE nodes(p)[1].name =~ '(?i)itadmin.*'
RETURN p

External Cypher cheatsheets:


Saving Custom Queries

Config files live at:

  • Windows: %APPDATA%\Roaming\bloodhound\
  • Linux: ~/.config/bloodhound/ or /root/.config/bloodhound/

The file that matters is customqueries.json. By default it's empty:

{"queries": []}

You can add custom queries by clicking the pencil icon next to Custom Queries in the Queries tab, or editing the file directly.

Example : Search from any owned node to anything (interactive prompt):

{
    "queries": [
        {
            "name": "Search From Owned to Anything",
            "category": "Shortest Paths",
            "queryList": [
                {
                    "final": false,
                    "title": "Select the owned node to search from...",
                    "query": "MATCH (n {owned:true}) RETURN n.name",
                    "props": { "name": ".*" }
                },
                {
                    "final": true,
                    "query": "MATCH p = allshortestPaths((n)-[*1..]->(c)) WHERE n.name = $result AND NOT c=n RETURN p",
                    "allowCollapse": true,
                    "endNode": "{}"
                }
            ]
        }
    ]
}

This query first lists all nodes you've marked as Owned, lets you pick one, then finds all shortest paths from that node to anything in the domain.

Custom query in action

If BloodHound is open when you update customqueries.json, click the refresh icon to reload.


BloodHound for Blue Teams

BloodHound is not just an attacker tool. Blue teams use it to proactively find and remediate misconfigurations before attackers do.

Key insight: If you can identify the attack path, you can break it. BloodHound lets defenders prioritize exactly which ACL misconfiguration or group membership change will remove the most attack paths.

Common defensive use cases:

  • Find all paths to Domain Admins and reduce them
  • Identify users/groups with dangerous ACL permissions (WriteDacl, GenericAll, Owns)
  • Audit which users have local admin rights across the environment
  • Detect accounts with passwords stored in description fields
  • Map trust relationships that create unexpected attack paths
  • Find Kerberoastable accounts (users with SPNs)
  • Identify machines where domain users have local admin

Azure Enumeration with AzureHound

As of BloodHound 4.0+, Azure is supported. Data is collected with AzureHound : a Go binary that queries MS Graph and Azure REST APIs.

Running AzureHound

# Username/password (simplest)
.\azurehound.exe -u "user@tenant.onmicrosoft.com" -p "password" list --tenant "tenant.onmicrosoft.com" -o all.json

# Service principal
.\azurehound.exe --app-id "<APP_ID>" --app-secret "<SECRET>" --tenant "<TENANT>" list -o all.json

Import all.json into BloodHound the same way you import SharpHound data.

AzureHound import

Note: Azure users can't read all objects by default. If a user doesn't have read rights on a subscription, AzureHound won't enumerate VMs, resource groups, etc. under that scope.

Azure Node Types in BloodHound

Once imported, you can search for Azure-specific nodes: AZUser:, AZVM:, AZKeyVault:, AZSubscription: etc.

Use the Transitive Object Control option on a node to see what privileges your compromised user has across Azure resources.

AzureHound attack paths

Azure Attack Path Example

BloodHound can surface paths like: User A has Password Administrator โ†’ can reset User B's password โ†’ User B has contributor access to a Key Vault โ†’ secrets can be extracted.

Azure Key Vault path

Useful tools for Azure post-exploitation after BloodHound analysis:

  • PowerZure : PowerShell framework for Azure exploitation (similar to PowerView but for Azure)
  • Az PowerShell module : Microsoft's official Azure management module
  • AzureAD PowerShell module : Azure AD management

PowerView : Fallback When BloodHound Misses ACLs

When a compromised user shows no paths in BloodHound (especially with older versions missing Self privileges), use PowerView to manually check what ACLs that user has:

Import-Module .\PowerView.ps1
Get-DomainObjectAcl -Identity username -Domain corp.local -ResolveGUIDs

Then take the GUIDs and cross-reference them manually, or add them to BloodHound data.


Further Reading