Skip to content

Instantly share code, notes, and snippets.

@xybytes
Created December 24, 2023 02:48
Show Gist options
  • Save xybytes/1911be32161fc912cb81f3fc7e7e6b17 to your computer and use it in GitHub Desktop.
Save xybytes/1911be32161fc912cb81f3fc7e7e6b17 to your computer and use it in GitHub Desktop.

BloodHound Cypher Cheatsheet

  1. Find edges

  2. Users

  3. Groups

  4. Kerberos

  5. Computers

  6. GPO

  1. Session
  1. Remove dataset from neoj4

Find edges

Find all edges for specific user

MATCH p = allShortestPaths((u:User)-[*1..3]->(a))
WHERE u.name =~ '[email protected]' AND u <> a
RETURN p
MATCH p = allShortestPaths((u:User {name: 'USER01@CORPORATE.LOCAL'})-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..2]->(a))
WHERE u <> a
RETURN p

Find all edges for specific Group

MATCH p = allShortestPaths((u:Group)-[*1..3]->(a))
WHERE u.name =~ 'DOMAIN [email protected]' AND u <> a
RETURN p
MATCH p = allShortestPaths((u:User {name: 'DOMAIN [email protected]'})-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..2]->(a))
WHERE u <> a
RETURN p

Find all user edges for specific Group

MATCH (n:User),(m:Group {name:'DOMAIN [email protected]'}), p=(m)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..2]->(n)
RETURN p

Find all user edges for specific User

MATCH (n:User),(m:User {name:'[email protected]'}), p=(m)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..2]->(n)
RETURN p

Find all computer edges for specific Group

MATCH (n:Computer),(m:Group {name:'[email protected]'}), p=(m)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..2]->(n)
RETURN p

Shortest paths to Domain

MATCH p = allShortestPaths((uc)-[*1..2]->(d:Domain {name: "CORPORATE.COM"}))
WHERE uc:User OR uc:Computer
RETURN p

Shortest paths to Domain Admins group from all domain groups

MATCH (n:Group), (m:Group {name:'DOMAIN [email protected]'})
WHERE n <> m
MATCH p=shortestPath((n)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..]->(m))
RETURN p

Shortest paths to Domain Admins group from computers

MATCH (n:Computer),(m:Group {name:'DOMAIN [email protected]'}),p=shortestPath((n)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..]->(m)) RETURN p

List all High Valued Targets

MATCH (m) WHERE m.highvalue=TRUE RETURN m

Shortest Paths from Kerberoastable Users to High Value Targets

MATCH p = allShortestPaths((u:User)-[*1..]->(h))
WHERE u.hasspn = true AND h.highvalue = true
RETURN p

Users

Find users created in the last 30 days

MATCH (u:User) where u.enabled=TRUE and u.whencreated  > (datetime().epochseconds - (30 * 86400)) RETURN u

Find users credentials in description fields

MATCH (m:User) WHERE m.description CONTAINS 'password' RETURN m.name, m.description

Users never logged on and account still active

MATCH (n:User) WHERE n.lastlogontimestamp=-1.0 AND n.enabled=TRUE RETURN n

Users logged in the last 90 days

MATCH (u:User) WHERE u.lastlogon < (datetime().epochseconds - (90 * 86400)) and NOT u.lastlogon IN [-1.0, 0.0] RETURN u

Users with passwords last set in the last 90 days

MATCH (u:User) WHERE u.pwdlastset < (datetime().epochseconds - (90 * 86400)) and NOT u.pwdlastset IN [-1.0, 0.0] RETURN u

Find users that belong to high value groups

match (u1:User) WHERE u1.plaintext=True MATCH p=(u1:User)-[r:MemberOf*1..]->(m:Group {highvalue:true}) RETURN u1

Find users that can RDP into something

match (u1:User) WHERE u1.plaintext=True MATCH p1=(u1)-[:CanRDP*1..]->(c:Computer) RETURN u1

Users with most local admin rights

MATCH (U:User)-[r:MemberOf|AdminTo*1..]->(C:Computer) WITH U.name as n, COUNT(DISTINCT(C)) AS c RETURN n,c ORDER BY c DESC LIMIT 5

Find if unprivileged users have rights to add members into groups

MATCH (n:User {admincount:False}) MATCH p=allShortestPaths((n)-[r:AddMember*1..]->(m:Group)) RETURN p

Search for key words in users title

MATCH p = (d:Domain)-[r:Contains*1..]->(u:User) WHERE u.title =~ '(?i).*scientist*' AND u.enabled = true RETURN p

Find users that have never logged on and account is still active

MATCH (n:User) WHERE n.lastlogontimestamp=-1.0 AND n.enabled=TRUE RETURN n

Find users with blank passwords that are enabled

MATCH (u:User) WHERE NOT u.userpassword IS null AND u.enabled = TRUE RETURN u.name,u.userpassword

Find if unprivileged users have rights to add members into groups

MATCH (n:User {admincount:False}) MATCH p=allShortestPaths((n)-[r:AddMember*1..]->(m:Group)) RETURN p

All Users with a homedirectory

MATCH p = (d:Domain)-[r:Contains*1..]->(u:User) WHERE u.homedirectory =~ '(?i).*.*' RETURN p

Find constrained delegation

MATCH p=(u:User)-[:AllowedToDelegate]->(c:Computer) RETURN p

Groups

Find all other Rights Domain Users shouldn't have

MATCH p=(m:Group)-[r:Owns|WriteDacl|GenericAll|WriteOwner|ExecuteDCOM|GenericWrite|AllowedToDelegate|ForceChangePassword]->(n:Computer) WHERE m.objectid ENDS WITH '-513' OR m.objectsid ENDS WITH '-515' OR m.objectsid ENDS WITH 'S-1-5-11' OR m.objectsid ENDS WITH 'S-1-1-0' RETURN p

Find what groups can RDP

MATCH p=(m:Group)-[r:CanRDP]->(n:Computer) RETURN p

Groups that contain the word 'admin'

Match (n:Group) WHERE n.name CONTAINS 'ADMIN' RETURN n

Groups of High Value Targets

MATCH p=(n:User)-[r:MemberOf*1..]->(m:Group {highvalue:true}) RETURN p

Non Admin Groups with High Value Privileges

MATCH p=(g:Group)-[r:Owns|:WriteDacl|:GenericAll|:WriteOwner|:ExecuteDCOM|:GenericWrite|:AllowedToDelegate|:ForceChangePassword]->(n:Computer) WHERE NOT g.name CONTAINS 'ADMIN' RETURN p

Groups that can reset passwords (Warning: Heavy)

MATCH p=(m:Group)-[r:ForceChangePassword]->(n:User) RETURN p

Groups that have local admin rights (Warning: Heavy)

MATCH p=(m:Group)-[r:AdminTo]->(n:Computer) RETURN p

Find groups that can reset passwords (Warning: Heavy)

MATCH p=(m:Group)-[r:ForceChangePassword]->(n:User) RETURN p

Find groups that have local admin rights (Warning: Heavy)

MATCH p=(m:Group)-[r:AdminTo]->(n:Computer) RETURN p

Show all high value target groups

MATCH p=(n:User)-[r:MemberOf*1..]->(m:Group {highvalue:true}) RETURN p

Kerberos

Find All Users with an SPN:

MATCH (n:User)WHERE n.hasspn=true
RETURN n

Find All Users with an SPN with passwords last set more then 5 years ago:

MATCH (u:User) WHERE u.hasspn=true AND u.pwdlastset < (datetime().epochseconds - (1825 * 86400)) AND NOT u.pwdlastset IN [-1.0, 0.0]
RETURN u.name, u.pwdlastset order by u.pwdlastset

Kerberoastable Users with a path to DA:

MATCH (u:User {hasspn:true}) MATCH (g:Group) WHERE g.name CONTAINS 'DOMAIN ADMINS' MATCH p = shortestPath( (u)-[*1..]->(g) ) RETURN p

Kerberoastable Admins

MATCH (n:Group) WHERE n.objectsid =~ $sid WITH n MATCH p=(n)<-[MemberOf*1..]-(m {hasspn: true}) RETURN p

Find users that can be AS REP roasted

MATCH (u:User {dontreqpreauth: true}) RETURN u

Find Kerberoastable users who are members of high value groups

MATCH (u:User)-[r:MemberOf*1..]->(g:Group) WHERE g.highvalue=true AND u.hasspn=true RETURN u

Computers

Find Server 2000 and Enabled

MATCH (H:Computer) WHERE H.operatingsystem =~ '(?i).*(2000).*' AND H.enabled = TRUE RETURN H

Find Server 2000 with session

MATCH (H:Computer)-[:HasSession]->(y) WHERE H.operatingsystem =~ '(?i).*(2000).*' RETURN H

Find Server 2003 and Enabled

MATCH (H:Computer) WHERE H.operatingsystem =~ '(?i).*(2003).*' AND H.enabled = TRUE RETURN H

All computers without LAPS and the computer is enabled

MATCH p = (d:Domain)-[r:Contains*1..]->(c:Computer) WHERE c.haslaps = false AND c.enabled = true RETURN p

Find computers that allow unconstrained delegation that are not domain controllers:

 MATCH (c1:Computer)-[:MemberOf*1..]->(g:Group) WHERE g.objectid ENDS WITH '-516' WITH COLLECT(c1.name) AS domainControllers MATCH (c2:Computer {unconstraineddelegation:true}) WHERE NOT c2.name IN domainControllers RETURN c2

All enabled computers with a description

MATCH p = (d:Domain)-[r:Contains*1..]->(c:Computer) WHERE c.description =~ '(?i).*.*' RETURN p

All computers without LAPS and the computer is enabled

MATCH p = (d:Domain)-[r:Contains*1..]->(c:Computer) WHERE c.haslaps = false AND c.enabled = true RETURN p

Computers with administrative Domain Users

MATCH p=(m:Group)-[r:AddMember|AdminTo|AllExtendedRights|AllowedToDelegate|CanRDP|Contains|ExecuteDCOM|ForceChangePassword|GenericAll|GenericWrite|GetChanges|GetChangesAll|HasSession|Owns|ReadLAPSPassword|SQLAdmin|TrustedBy|WriteDACL|WriteOwner|AddAllowedToAct|AllowedToAct]->(t) WHERE m.objectsid ENDS WITH '-513' OR m.objectsid ENDS WITH '-515' OR m.objectsid ENDS WITH 'S-1-5-11' OR m.objectsid ENDS WITH 'S-1-1-0' RETURN p

Find computers with constrained delegation permissions and the corresponding targets where they allowed to delegate

MATCH (c:Computer) WHERE c.allowedtodelegate IS NOT NULL RETURN c

GPO

View all GPOs

Match (n:GPO) RETURN n

Shortes path from Group to GPO

MATCH (n:Group {name:'DOMAIN [email protected]'}), (m:GPO)
WHERE n <> m
MATCH p=shortestPath((n)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..]->(m))
RETURN p

Shortes path from Computer to GPO

MATCH (n:Computer {name:'DOMAIN [email protected]'}), (m:GPO)
WHERE n <> m
MATCH p=shortestPath((n)-[r:MemberOf|HasSession|AdminTo|AllExtendedRights|AddMember|ForceChangePassword|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|CanRDP|ExecuteDCOM|AllowedToDelegate|ReadLAPSPassword|Contains|GpLink|AddAllowedToAct|AllowedToAct*1..]->(m))
RETURN p

Find Users/Groups with direct access to GPOs

MATCH p = (n)-[r:AddMember|AddSelf|WriteSPN|AddKeyCredentialLink|AllExtendedRights|ForceChangePassword|GenericAll|GenericWrite|WriteDacl|WriteOwner|Owns]->(g:GPO) RETURN p

Find if any domain user has interesting permissions against a GPO (Warning: Heavy)

MATCH p=(u:User)-[r:AllExtendedRights|GenericAll|GenericWrite|Owns|WriteDacl|WriteOwner|GpLink*1..]->(g:GPO) RETURN p

Session

Find the active user sessions on all domain computers

MATCH (n:User),(m:Computer), (n)<-[r:HasSession]-(m)
WHERE NOT n.name STARTS WITH 'ANONYMOUS LOGON' AND NOT n.name=''
WITH n, count(r) as rel_count
ORDER BY rel_count DESC
MATCH p=(m)-[r:HasSession]->(n)
RETURN p

Top Ten Users with Most Sessions

MATCH (n:User),(m:Computer), (n)<-[r:HasSession]-(m) WHERE NOT n.name STARTS WITH 'ANONYMOUS LOGON' AND NOT n.name='' WITH n, count(r) as rel_count order by rel_count desc LIMIT 10 MATCH p=(m)-[r:HasSession]->(n) RETURN p

Find all active Domain Admin sessions

MATCH (m:User)-[r:MemberOf*1..]->(n:Group) WHERE n.objectid =~ '(?i)S-1-5-.*-512' WITH m MATCH q=((m)<-[:HasSession]-(o:Computer)) RETURN q

Remove dataset from neo4j

match (a) -[r] -> () delete a, r
match (a) delete a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment