BloodHound Advanced Queries
Custom Cypher queries, shortest path analysis to Domain Admins, Kerberoastable accounts, DCSync rights, LAPS targets, and ACL abuse paths for comprehensive AD enumeration.
Collection & Setup
BloodHound requires SharpHound (Windows) or BloodHound.py (Linux/remote) for collection. For CPTS, you'll typically use BloodHound.py from Kali since you start with domain credentials.
# BloodHound.py β collect all methods remotely
pip3 install bloodhound
bloodhound-python -u svc_user -p 'Password1!' -d corp.local -dc DC01.corp.local -c All --zip
# SharpHound β from a compromised Windows host
.SharpHound.exe -c All --zipfilename bh-data.zip
# Neo4j setup (required before BloodHound GUI)
sudo neo4j start
# Default creds: neo4j / neo4j β change on first login
bloodhound &
-c All for comprehensive collection. If stealth matters, -c DCOnly queries only the DC (no computer sessions β faster but misses local admin paths).
Core Cypher Queries
BloodHound's built-in queries cover most attack paths. Use the Raw Query box (top of GUI) for custom Cypher. Neo4j query language β all nodes are labeled User, Computer, Group, Domain, GPO, OU, Container.
Find Shortest Path to Domain Admins
MATCH p=shortestPath((n)-[*1..]->(m:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
WHERE NOT n=m
RETURN p
All Kerberoastable Users
MATCH (u:User {hasspn:true}) WHERE u.enabled=true
RETURN u.name, u.serviceprincipalnames, u.admincount
ORDER BY u.admincount DESC
DCSync Rights (DS-Replication-Get-Changes-All)
MATCH p=(n)-[:DCSync|AllExtendedRights|GenericAll]->(m:Domain)
RETURN p
Accounts with AdminCount=1 (Protected Users)
MATCH (u:User {admincount:1}) WHERE u.enabled=true
RETURN u.name ORDER BY u.name
Computers with LAPS Disabled
MATCH (c:Computer {haslaps:false}) RETURN c.name, c.operatingsystem
Attack Path Analysis
Path from Owned User to DA
# Mark your compromised user as Owned first (right-click β Mark as Owned)
MATCH p=shortestPath((u:User {owned:true})-[*1..]->(g:Group {name:"DOMAIN ADMINS@CORP.LOCAL"}))
RETURN p
Find All GenericWrite/GenericAll Paths
MATCH p=(u:User)-[:GenericWrite|GenericAll|WriteDacl|WriteOwner|Owns]->(n)
WHERE u.enabled=true
RETURN p LIMIT 50
ForceChangePassword Paths
MATCH p=(u:User)-[:ForceChangePassword]->(v:User)
RETURN u.name AS attacker, v.name AS target
Local Admin Rights (CanRDP / AdminTo)
MATCH p=(u:User)-[:AdminTo]->(c:Computer)
WHERE u.name = "SVC_SQL@CORP.LOCAL"
RETURN p
Custom Query Library
AS-REP Roastable Accounts
MATCH (u:User {dontreqpreauth:true}) WHERE u.enabled=true RETURN u.name
Users with Unconstrained Delegation
MATCH (c:Computer {unconstraineddelegation:true}) WHERE c.name <> "DC01.CORP.LOCAL"
RETURN c.name, c.operatingsystem
Constrained Delegation Targets
MATCH (u)-[:AllowedToDelegate]->(c:Computer) RETURN u.name, c.name
Groups with Dangerous Rights to Computers
MATCH p=(g:Group)-[:AdminTo|CanRDP|ExecuteDCOM|AllowedToDelegate]->(c:Computer)
WHERE g.name <> "DOMAIN ADMINS@CORP.LOCAL"
RETURN p LIMIT 100
Cross-Domain Trust Paths
MATCH p=(n)-[:HasForeignGroupMembership|HasForeignSecurityPrincipal]->(m)
RETURN p
Exam Tips
- If no path exists from your user, look for paths via groups your user is a member of
- ReadGMSAPassword edges often lead to service account takeover β privilege escalation
- WriteSPN on a user = you can Kerberoast them (targeted Kerberoasting)
- Always check Inbound Object Control panel on each node β lists who can attack this object
- AddSelf right on a group = add yourself to that group, potentially gaining its privileges