Explore Kerberoastable Users with BloodHound¶
Author: Roberto Rodriguez (@Cyb3rWard0g)
Project: Infosec Jupyter Book
Public Organization: Open Threat Research
License: Creative Commons Attribution-ShareAlike 4.0 International
Reference: https://youtu.be/fqYoOoghqdE?t=1218
Count Users with Service Principal Name Set¶
When sharphound finds a user with a Service Principal Name set, it property named hasspn
in the User node to True
. Therefore, if we want to count the number users with that property set, we just need to query for users with hasspn = True
.
g = Graph("bolt://206.189.85.93:7687", auth=("neo4j", "BloodHound"))
users_hasspn_count = g.run("""
MATCH (u:User {hasspn:true})
RETURN COUNT(u)
""").to_data_frame()
users_hasspn_count
COUNT(u) | |
---|---|
0 | 6 |
g.run("""
MATCH (u:User {hasspn:true})
RETURN u.name
""").to_data_frame()
u.name | |
---|---|
0 | SQLSVC@TOKYO.JAPAN.LOCAL |
1 | SCANSERVICE@TOKYO.JAPAN.LOCAL |
2 | KRBTGT@JAPAN.LOCAL |
3 | BACKUPLDAP@TOKYO.JAPAN.LOCAL |
4 | KRBTGT@TOKYO.JAPAN.LOCAL |
5 | KRBTGT@SINGAPORE.LOCAL |
Retrieve Kerberoastable Users with Path to DA¶
We can limit our results and return only Kereberoastable users with paths to DA. We can find Kerberoastable users with a path to DA and also see the length of the path to see which one is the closest.
krb_users_path_to_DA = g.run("""
MATCH (u:User {hasspn:true})
MATCH (g:Group {name:'DOMAIN ADMINS@JAPAN.LOCAL'})
MATCH p = shortestPath(
(u)-[*1..]->(g)
)
RETURN u.name,LENGTH(p)
ORDER BY LENGTH(p) ASC
""").to_data_frame()
krb_users_path_to_DA
u.name | LENGTH(p) | |
---|---|---|
0 | SQLSVC@TOKYO.JAPAN.LOCAL | 3 |
1 | BACKUPLDAP@TOKYO.JAPAN.LOCAL | 5 |
Return Most Privileged Kerberoastable users¶
What if we do not have kerberoastable users with a path to DA? We can still look for most privileged Kerberoastable users based on how many computers they have local admins rights on.
privileged_kerberoastable_users = g.run("""
MATCH (u:User {hasspn:true})
OPTIONAL MATCH (u)-[:AdminTo]->(c1:Computer)
OPTIONAL MATCH (u)-[:MemberOf*1..]->(:Group)-[:AdminTo]->(c2:Computer)
WITH u,COLLECT(c1) + COLLECT(c2) AS tempVar
UNWIND tempVar AS comps
RETURN u.name,COUNT(DISTINCT(comps))
ORDER BY COUNT(DISTINCT(comps)) DESC
""").to_data_frame()
privileged_kerberoastable_users
u.name | COUNT(DISTINCT(comps)) | |
---|---|---|
0 | SQLSVC@TOKYO.JAPAN.LOCAL | 1 |