Cypher Queries that Support Target Selection and Attacks


Count how many computers each user has admin access to

Example: If a user is not a DA but has admin access to 1,000 computers, you might want to mark that user as a High Value Target.

Count the number of the computers where each domain user has direct Admin privileges:

MATCH (u:User)-[:AdminTo]->(c:Computer) RETURN count(DISTINCT(c.name)) AS COMPUTER, u.name AS USER ORDER BY count(DISTINCT(c.name)) DESC

Count the number of the computers where each domain user has derivative Admin privileges:

MATCH (u:User)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c:Computer) RETURN count(DISTINCT(c.name)) AS COMPUTER, u.name AS USER ORDER BY count(DISTINCT(c.name)) DESC

Cyper Queries that Support Kerberoasting

Cracking SPN/Kerberoasted hashes is slow AF. Consider using these to help prioritize which SPNs to target for cracking.

List all Kerberoastable users that are members of High Value Target groups:

MATCH p=shortestPath((n:User)-[:MemberOf]->(g:Group)) WHERE g.highvalue=true AND n.hasspn=true RETURN n.name AS Kerberoastable_User,g.name AS Privileged_Group

List all Kerberoastable users whose password was last changed BEFORE 2010-01-01:

  • Reasoning: Service accounts probably don’t have their passwords changed very frequently (expected), but passwords from 11+ years ago are likely to be way weaker than today’s passwords.
  • If you don’t get any hits, adjust the epoch time. LINK
MATCH (u:User {hasspn: true}) WHERE u.pwdlastset < 1262304000 RETURN u.name,u.pwdlastset

Find Linux hosts

MATCH (c:Computer {enabled: True}) WHERE ( c.name =~ '(?i).*(lin|nix|redhat|centos|ubuntu|deb).*' OR c.operatingsystem =~ '(?i).*(lin|nix|redhat|centos|ubuntu|deb).*' OR c.description =~ '(?i).*(linux|redhat|centos|ubuntu|debian).*' ) RETURN c.name as Computer, c.operatingsystem AS OS, c.description AS Description

Find interesting hosts where you can RDP

Hosts with details where all users can RDP:

  • Very fast query
MATCH p=(g:Group)-[:CanRDP]->(c:Computer) WHERE g.name =~ '(?i)DOMAIN USERS.*' RETURN g.name AS Group_Name,c.name AS Computer_Name,c.description AS Description,c.enabled AS Enabled, c.operatingsystem AS Operating_System

Count of computers where each owned user has RDP access:

MATCH p = allShortestPaths((o {owned:true})-[r:CanRDP|MemberOf*1..]->(c:Computer)) RETURN o.name AS Owned_Object, count(DISTINCT(c.name)) AS Computers_with_RDP_Access

Full list and details of computers where owned users can RDP:

MATCH p = allShortestPaths((o {owned:true})-[r:CanRDP|MemberOf*1..]->(c:Computer)) RETURN o.name AS Owned_Object, c.name AS Computer_Name, c.description AS Description, c.enabled AS Enabled, c.operatingsystem AS Operating_System

See Also