Map Active Directory attack paths — SharpHound collection & Cypher
BloodHound maps Active Directory attack paths using graph theory. Collectors (SharpHound / AzureHound / the Python ingestor) gather objects, ACLs, sessions, and trusts; the GUI then reveals shortest paths to Domain Admin. For authorized testing only.
Run from a domain-joined or domain-reachable host. Drops .json files zipped together.
# .exe collector — grab everything
SharpHound.exe -c All
# PowerShell module
Import-Module .\SharpHound.ps1
Invoke-BloodHound -CollectionMethod All
# Specify domain + DC, write to a folder
SharpHound.exe -c All -d domain.local --domaincontroller 10.10.10.10 --outputdirectory C:\loot
# Stealthier / targeted runs
SharpHound.exe -c DCOnly # LDAP-only, no host touches (quiet)
SharpHound.exe -c Session --loop --loopduration 02:00:00 # poll sessions over 2h
SharpHound.exe -c All --stealth # only "stealth" enumeration targets
-c / CollectionMethod |
Gathers |
|---|---|
All |
Everything below except GPOLocalGroup |
Group |
Group memberships |
LocalAdmin,RDP,DCOM,PSRemote |
Local group membership on hosts |
Session |
Logged-on user sessions (re-run with --loop) |
ACL |
DACLs on objects (the juicy edges) |
Trusts |
Domain trusts |
DCOnly |
Pull only from the DC over LDAP (no host enumeration) |
ObjectProps |
Attributes: pwdlastset, description, etc. |
Useful flags: --zipfilename out.zip, --randomizefilenames, --collectallproperties, --throttle 1000 / --jitter 30 (ms, evade detection), --excludedcs.
# Python collector (bloodhound-python) — run from Linux
bloodhound-python -u user -p 'Password123' -d domain.local -ns 10.10.10.10 -c All
bloodhound-python -u user --hashes :<NThash> -d domain.local -ns 10.10.10.10 -c All -k
# Via NetExec (LDAP)
nxc ldap dc.domain.local -u user -p pass --bloodhound -c All --dns-server 10.10.10.10
azurehound -u user@tenant.com -p 'Password' list --tenant tenant.com -o output.json
azurehound -j <jwt> list --tenant <tenant-id> -o output.json # with a refresh/JWT token
curl -L https://ghst.ly/getbhce | docker compose -f - up # bring up BHCE
# GUI: http://localhost:8080 → log in, then drag-drop the zip under Administration > File Ingest
neo4j console # start DB (default bolt://localhost:7687, neo4j/neo4j)
bloodhound # launch the app, log in, drag the zip onto the window
In the GUI sidebar (Analysis tab), the high-value queries:
Right-click any node → Mark as Owned / Mark as High Value to seed path queries.
The query box accepts Cypher. Examples:
// Kerberoastable users
MATCH (u:User {hasspn:true}) RETURN u
// AS-REP roastable (no Kerberos pre-auth)
MATCH (u:User {dontreqpreauth:true}) RETURN u
// Users with paths to Domain Admins
MATCH p=shortestPath((u:User)-[*1..]->(g:Group))
WHERE g.objectid ENDS WITH '-512' RETURN p LIMIT 25
// Computers with unconstrained delegation
MATCH (c:Computer {unconstraineddelegation:true}) RETURN c
// What can an owned user reach? (mark owned first)
MATCH p=shortestPath((n {owned:true})-[*1..]->(m)) RETURN p
// Sessions of Domain Admins (find where to hunt for creds)
MATCH (u:User)-[:MemberOf*1..]->(g:Group)
WHERE g.objectid ENDS WITH '-512'
MATCH p=(c:Computer)-[:HasSession]->(u) RETURN p
| Edge | Abuse |
|---|---|
MemberOf |
Inherited group rights |
AdminTo |
Local admin → dump creds / exec |
HasSession |
Creds of that user may be in LSASS on the host |
GenericAll / GenericWrite |
Full/partial control → reset pw, set SPN, RBCD |
WriteDacl / Owns |
Rewrite the object's DACL → grant yourself rights |
ForceChangePassword |
Reset the target's password |
AllowedToDelegate |
Constrained delegation abuse (S4U) |
DCSync (GetChanges+GetChangesAll) |
Replicate hashes from the DC |
-c Session --loop during the engagement — sessions are transient and reveal where admins log in.DCOnly is the quietest collection; --stealth avoids hammering every host.Authorized testing only. Practice on the AYSEC pro-labs. See also Impacket and Mimikatz.