Skip to content

Instantly share code, notes, and snippets.

@jeffmcjunkin
Last active November 12, 2023 16:35
Show Gist options
  • Star 65 You must be signed in to star a gist
  • Fork 18 You must be signed in to fork a gist
  • Save jeffmcjunkin/7b4a67bb7dd0cfbfbd83768f3aa6eb12 to your computer and use it in GitHub Desktop.
Save jeffmcjunkin/7b4a67bb7dd0cfbfbd83768f3aa6eb12 to your computer and use it in GitHub Desktop.
Useful Cypher queries for BloodHound
MATCH (u:User)-[r:AdminTo|MemberOf*1..]->(c:Computer
RETURN u.name
That’ll return a list of users who have admin rights on at least one system either explicitly or through group membership
---------------
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
Return username and number of computers that username is admin for, for top N users
---------------
MATCH
(G:Group)-[r:MemberOf|:AdminTo*1..]->(C:Computer)
WITH
G.name as n,
COUNT(DISTINCT(C)) as c
RETURN n,c
ORDER BY c DESC
LIMIT 5
Return group and number of computers that group is admin for, for top N groups
---------------
MATCH
(U:User)-[r:MemberOf|:AdminTo*1..]->(C:Computer)
WITH
U.name as n,
COUNT(DISTINCT(C)) as c
WHERE c>1
RETURN n
ORDER BY c DESC
Show all users that are administrator on more than one machine
---------------
MATCH (u:User)
WITH u
OPTIONAL MATCH (u)-[r:AdminTo]->(c:Computer)
WITH u,COUNT(c) as expAdmin
OPTIONAL MATCH (u)-[r:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c:Computer)
WHERE NOT (u)-[:AdminTo]->(c)
WITH u,expAdmin,COUNT(DISTINCT(c)) as unrolledAdmin
RETURN u.name,expAdmin,unrolledAdmin,expAdmin + unrolledAdmin as totalAdmin
ORDER BY totalAdmin ASC
Show all users that are administrative on at least one machine, ranked by the number of machines they are admin on.
---------------
MATCH p=((S:Computer)-[r:HasSession*1]->(T:User))
WHERE NOT S.domain = T.domain
RETURN p
This will return cross domain 'HasSession' relationships
---------------
MATCH p=(m:Group)-[r:Owns|:WriteDacl|:GenericAll|:WriteOwner|:ExecuteDCOM|:GenericWrite|:AllowedToDelegate|:ForceChangePassword]->(n:Computer) WHERE m.name STARTS WITH ‘DOMAIN USERS’ RETURN p
Find all other Rights Domain Users shouldn't have
---------------
MATCH (n:User)-[r:MemberOf]->(g:Group) WHERE g.highvalue=true AND n.hasspn=true RETURN n, g, r
Show Kerberoastable high value targets
---------------
MATCH (c:Computer) WITH c
OPTIONAL MATCH (n)-[r:AdminTo]->(c) WITH c,COUNT(n) as expAdmins
OPTIONAL MATCH (n)-[r:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c) WITH c,expAdmins,COUNT(DISTINCT(n)) as unrolledAdmins
RETURN SPLIT(c.name,'.')[0],expAdmins,unrolledAdmins,expAdmins + unrolledAdmins as totalAdmins ORDER BY totalAdmins DESC
Return each computername with the number of admins on that machine
---------------
MATCH (c:Computer {domain:'$DOMAINNAME$'}) WITH c
OPTIONAL MATCH (n)-[r:AdminTo]->(c) WITH c,COUNT(n) as expAdmins
OPTIONAL MATCH (n)-[r:MemberOf*1..]->(g:Group)-[r2:AdminTo]->(c)
WITH c,expAdmins,COUNT(DISTINCT(n)) as unrolledAdmins
RETURN SPLIT(c.name,'.')[0],expAdmins,unrolledAdmins,expAdmins + unrolledAdmins as totalAdmins
ORDER BY totalAdmins DESC
Return each computername with the number of admins on that machine for a specific domain
---------------
MATCH (n)
MATCH (t {name: "<some_node>"})
MATCH p = allshortestPaths((n)-[*1..10]->(t))
WHERE NONE(node IN nodes(p) WHERE node.highvalue = true) AND NOT n = t
RETURN p
this will search for the paths to a target node and exclude paths that go through any node with the highvalue property set to true
---------------
UNWIND ["360totalsecurity", "acronis", "adaware", "aegislab", "ahnlab", "alienvault", "altavista", "anti-virus", "antivirus", "antiy", "apexone", "arcabit", "arcsight", "attivo", "avast", "avg", "avira", "baidu", "baiduspider", "barracuda", "bingbot", "bitdefender", "bitdefender", "bluecoat", "bluvector", "canary", "carbon", "carbonblack", "carbonblack", "check", "checkpoint", "clamav", "code42", "comodo", "cortex", "countercept", "countertack", "crowdstrike", "cyberark", "cybereason", "cylance", "cynet360", "cyren", "darktrace", "datadog", "defender", "druva", "drweb", "duckduckbot", "egambit", "emsisoft", "encase", "endgame", "ensilo", "escan", "eset", "exabot", "f-secure", "falcon", "fidelis", "fireeye", "forcepoint", "fortigate", "fortil", "fortinet", "gdata", "gdata", "gravityzone", "honey", "huntress", "ia_archiver", "ikarussecurity", "ivanti", "juniper", "k7antivirus", "k7computing", "kaspersky", "kingsoft", "lightcyber", "lynx", "malwarebytes", "mcafee", "microsoft", "mj12bot", "morphisec", "msnbot", "nanoav", "nessus", "netwitness", "office365", "palo", "paloalto", "paloaltonetworks", "panda", "proofpoint", "qradar", "sandboxe", "scanner", "scanning", "secureage", "secureworks", "security", "sentinelone", "simplepie", "slurp", "sogou", "solarwinds", "sonicwall", "sophos", "splunk", "superantispyware", "symantec", "tachyon", "tencent", "totaldefense", "trapmine", "trend", "trendmicro", "trusteer", "trustlook", "virus", "virustotal", "virustotalcloud", "webroot", "zillya", "zonealarm", "zscaler"] AS word MATCH (n) WHERE toLower(n.name) CONTAINS toLower(word) OR toLower(n.description) CONTAINS toLower(word) RETURN word as keyword, LABELS(n)[1] as type, n.name, n.description, n.distinguishedname ORDER BY n.name
Match objects that are relevant to certain security keywords. Smaller words may get more false positives -- feel free to edit the list (like removing "security")
---------------
UNWIND ["360totalsecurity", "acronis", "adaware", "aegislab", "ahnlab", "alienvault", "altavista", "anti-virus", "antivirus", "antiy", "apexone", "arcabit", "arcsight", "attivo", "avast", "avg", "avira", "baidu", "baiduspider", "barracuda", "bingbot", "bitdefender", "bitdefender", "bluecoat", "bluvector", "canary", "carbon", "carbonblack", "carbonblack", "check", "checkpoint", "clamav", "code42", "comodo", "cortex", "countercept", "countertack", "crowdstrike", "cyberark", "cybereason", "cylance", "cynet360", "cyren", "darktrace", "datadog", "defender", "druva", "drweb", "duckduckbot", "edr", "egambit", "emsisoft", "encase", "endgame", "ensilo", "escan", "eset", "exabot", "f-secure", "f5", "falcon", "fidelis", "fireeye", "forcepoint", "fortigate", "fortil", "fortinet", "gdata", "gdata", "gravityzone", "honey", "huntress", "ia_archiver", "ikarussecurity", "ivanti", "juniper", "k7antivirus", "k7computing", "kaspersky", "kingsoft", "lightcyber", "lynx", "malwarebytes", "mcafee", "microsoft", "mj12bot", "morphisec", "msnbot", "nanoav", "nessus", "netwitness", "office365", "palo", "paloalto", "paloaltonetworks", "panda", "proofpoint", "qradar", "sandboxe", "scanner", "scanning", "secureage", "secureworks", "security", "sentinelone", "simplepie", "slurp", "sogou", "solarwinds", "sonicwall", "sophos", "splunk", "superantispyware", "symantec", "tachyon", "tencent", "totaldefense", "trapmine", "trend", "trendmicro", "trusteer", "trustlook", "virus", "virustotal", "virustotalcloud", "webroot", "zillya", "zonealarm", "zscaler"] AS word MATCH (n) WHERE toLower(n.name) CONTAINS toLower(word) OR toLower(n.description) CONTAINS toLower(word) OR toLower(n.distinguishedname) CONTAINS toLower(word) RETURN word as keyword, LABELS(n)[1] as type, n.name, n.description, n.distinguishedname ORDER BY n.name
Original version of the above, as shared by mgeeky on BloodHoundGang Slack
@RooieRakkert
Copy link

Thanks for sharing, useful stuff!

@Jason92s
Copy link

Jason92s commented Dec 5, 2019

Thanks, this is very helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment