BloodHound maps Active Directory relationships and finds attack paths that are invisible to manual enumeration. On Forest, it revealed a chain through 5 nested groups to WriteDACL on the domain. I would never have found that by hand. Never.
This is how I set it up, collect data, import it, and find the paths that matter.
Setup — BloodHound CE on Kali
BloodHound CE (Community Edition) replaced the old BloodHound. It runs as a Docker container with a web UI.
Install and Start
# Pull and start BloodHound CE
curl -L https://ghst.ly/getbhce | docker compose -f - up
# First run takes a few minutes to pull images
# Web UI: http://localhost:8080
First Login — The neo4j Password Gotcha
On first launch, BloodHound CE generates a random admin password. It’s printed in the Docker logs and is easy to miss.
# Find the initial password
docker compose logs | grep "Initial Password"
# or check the logs scrollback for the generated credentials
The gotcha I hit on Active: I couldn’t find the password in the terminal output because it scrolled past. Had to dig through Docker logs. Save it the first time.
Default credentials are usually admin / <random>. You’ll be forced to change the password on first login.
Verify It’s Running
Navigate to http://localhost:8080. You should see the BloodHound CE login page. Log in with the initial creds and set a new password.
Data Collection — bloodhound-python
bloodhound-python is the Linux collector. It queries the DC remotely — no need to run anything on the target.
The Command I Use Every Time
bloodhound-python -u 'USERNAME' -p 'PASSWORD' -ns $ip -d DOMAIN.local -c All
Flag Breakdown
| Flag | What it does |
|---|---|
-u | Username |
-p | Password |
-ns | Nameserver (DC IP) — critical, tells it where to resolve DNS |
-d | Domain name |
-c All | Collect everything — users, groups, sessions, ACLs, trusts, containers, GPOs |
Output
Creates several JSON files in the current directory:
20260324_computers.json
20260324_domains.json
20260324_groups.json
20260324_users.json
Real Examples from My Boxes
# Active — GPP creds
bloodhound-python -u 'SVC_TGS' -p 'GPPstillStandingStrong2k18' -ns 10.129.3.112 -d active.htb -c All
# Forest — AS-REP creds
bloodhound-python -u 'svc-alfresco' -p 's3rvice' -ns 10.129.95.210 -d htb.local -c All
# Blackfield — AS-REP creds
bloodhound-python -u 'support' -p '#00^BlackKnight' -ns $ip -d BLACKFIELD.local -c All
Gotchas
-nsis not optional in practice. Without it, DNS resolution fails because your Kali box doesn’t know how to resolve the domain. Always set it to the DC IP.-c Allis the right default. Some guides say to use-c DCOnlyfor stealth. For CTF boxes and OSCP, just grab everything.- Domain name matters. Some boxes use
domain.htb, others usedomain.htb.local, others usedomain.local. Get it from nmap LDAP output ornxc smboutput. Wrong domain name = collection fails silently or returns incomplete data. - If passwords have special characters (
$,!,#), use single quotes in bash.
Importing Data into BloodHound CE
- Log into BloodHound CE at
http://localhost:8080 - Click the Upload button (top right, arrow icon)
- Select all the JSON files from bloodhound-python
- Wait for ingestion to complete
That’s it. The graph database is populated. Time to query.
Queries That Matter
These are the queries I actually run. In order.
1. Shortest Path to Domain Admin
This is the first thing I check. Every time.
In BloodHound CE:
- Go to Explore → Pathfinding
- Start node: your owned user
- End node: DOMAIN ADMINS@DOMAIN.LOCAL
- Hit search
On Forest, this showed:
svc-alfresco → Service Accounts → Privileged IT Accounts → Account Operators
→ GenericAll over Exchange Windows Permissions
→ WriteDACL over HTB.LOCAL domain
Five groups deep. Invisible without BloodHound.
2. Kerberoastable Users
MATCH (u:User) WHERE u.hasspn=true RETURN u
Or use the built-in “List all Kerberoastable Users” query in the Analysis tab.
On Active, this showed the Administrator account had SPN active/CIFS:445. That’s unusual — normally you Kerberoast service accounts, not the actual Administrator. But the SPN was there, and the password was weak.
3. AS-REP Roastable Users
MATCH (u:User) WHERE u.dontreqpreauth=true RETURN u
Or the built-in “List all AS-REP Roastable Users” query.
Found svc-alfresco on Forest and support on Blackfield this way.
4. Users with DCSync Rights
MATCH p=(u)-[:MemberOf|GetChanges|GetChangesAll*1..]->(d:Domain) RETURN p
Shows who can already DCSync without any privilege escalation. If you own one of these accounts, go straight to impacket-secretsdump.
5. Find Principals with Dangerous Rights
Look at the Analysis tab for pre-built queries:
- Shortest path from owned principals
- Find all paths to Domain Admins
- Users with local admin rights
- Group memberships for a specific user
Understanding the Graph — Edge Types That Matter
When you see a path in BloodHound, the edges (arrows between nodes) tell you what kind of access you have. These are the ones I’ve actually exploited:
GenericAll
Full control over the target object. You can:
- Reset their password
- Add them to groups
- Modify their attributes
- Set an SPN on them (targeted Kerberoasting)
On Forest, svc-alfresco’s group chain gave GenericAll over Exchange Windows Permissions. That meant I could add myself to that group.
WriteDACL
Can modify the access control list of the target object. This is the big one. WriteDACL on a domain object means you can grant yourself any permission — including DCSync rights.
On Forest, Exchange Windows Permissions had WriteDACL over the HTB.LOCAL domain. After adding myself to that group, I used PowerView to grant DCSync rights:
Add-DomainObjectAcl -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity svc-alfresco -Rights DCSync
Then impacket-secretsdump pulled every hash in the domain.
ForceChangePassword
Can change the target user’s password without knowing the current one. Done via rpcclient:
rpcclient -U 'support%#00^BlackKnight' $ip
rpcclient $> setuserinfo2 audit2020 23 'Password@1234'
On Blackfield, support had ForceChangePassword over audit2020. Changed the password, used audit2020’s access to the forensic share, grabbed the LSASS dump.
Other Edges Worth Knowing
| Edge | What It Means | Exploitation |
|---|---|---|
| GenericWrite | Can modify attributes | Set SPN → Kerberoast, or set logon script |
| WriteOwner | Can take ownership | Take ownership → give yourself GenericAll |
| AddMember | Can add users to the group | Add yourself or a compromised user |
| ReadLAPSPassword | Can read LAPS passwords | Get local admin password for that machine |
| AllowedToDelegate | Kerberos delegation | Constrained/unconstrained delegation attacks |
Attack Paths I’ve Seen
Path 1: Nested Group Abuse → DCSync (Forest)
Owned User → Group → Group → Group → GenericAll → Target Group → WriteDACL → Domain
The play: Add yourself to the group that has WriteDACL. Use WriteDACL to grant yourself DCSync rights. Run secretsdump.
Path 2: ForceChangePassword → Lateral Movement (Blackfield)
Owned User → ForceChangePassword → Target User → Access to new resources
The play: Change the target’s password. Log in as them. See what they have access to that you didn’t.
Path 3: Direct Kerberoasting (Active)
Owned User → GetUserSPNs → Administrator has SPN → Crack TGS → Domain Admin
The play: BloodHound shows which high-value accounts have SPNs. If Administrator or another DA account has one, Kerberoast it.
My BloodHound Workflow
Every AD box, same process:
- Get any valid creds — null session, AS-REP Roast, creds in files, password spray, whatever
- Run bloodhound-python with
-c All - Upload JSON files to BloodHound CE
- Mark your user as owned — right-click → Mark as Owned
- Run pathfinding — owned user → Domain Admins
- Check pre-built queries — Kerberoastable, AS-REP Roastable, DCSync rights
- Walk the path BloodHound shows you
Step 5 is where the magic happens. BloodHound does the graph traversal across every group membership, ACL, and delegation in the domain. It finds paths you would never find manually.
The truth: I have never solved an AD box without BloodHound showing me something I missed. On Forest, the path was through 5 nested groups. On Blackfield, it showed the ForceChangePassword edge. On Active, it confirmed the Administrator SPN. BloodHound is not optional. It’s the map.