From a435dacae05d4b4ab4b8ec69f15686e46863a1f1 Mon Sep 17 00:00:00 2001 From: Martin Date: Wed, 10 Sep 2025 18:46:18 +0200 Subject: [PATCH 01/22] Update edge to new name: RemoteInteractiveLogonRight Edge was renamed in a BloodHound update. --- .../All incoming and local paths for a specific computer.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries/All incoming and local paths for a specific computer.yml b/queries/All incoming and local paths for a specific computer.yml index e5604cf..9505ef5 100644 --- a/queries/All incoming and local paths for a specific computer.yml +++ b/queries/All incoming and local paths for a specific computer.yml @@ -6,11 +6,11 @@ category: Domain Information description: All incoming and local paths for a specific computer; incoming from domain objects and paths local inside the computer. query: |- // Replace 'HOSTNAME' with the computer's shortname eg. 'SRV01', not FQDN - MATCH p=(n:Base)-[:RemoteInteractiveLogonPrivilege|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base) + MATCH p=(n:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base) WHERE m.name CONTAINS 'HOSTNAME' AND m.name CONTAINS '.' // Only see computer-related objects (eg. not AD Groups) RETURN p -revision: 1 +revision: 2 resources: acknowledgements: Martin Sohn Christensen, @martinsohndk From bf1c339db629f64e2569e9788a4b1540b4d3cd3d Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 12 Sep 2025 10:53:31 +0200 Subject: [PATCH 02/22] Create Locations of Owned objects - AZ.yml Similar to the query "Locations of Tier Zero / High-Value objects" for AD --- queries/Locations of Owned objects - AZ.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 queries/Locations of Owned objects - AZ.yml diff --git a/queries/Locations of Owned objects - AZ.yml b/queries/Locations of Owned objects - AZ.yml new file mode 100644 index 0000000..df528f2 --- /dev/null +++ b/queries/Locations of Owned objects - AZ.yml @@ -0,0 +1,15 @@ +name: Locations of Owned objects +guid: 350b8b8a-ea4c-44f3-874b-c9316de6c41b +prebuilt: false +platforms: Azure +category: General +description: +query: |- + MATCH p = (t:AZBase)<-[:AZContains*1..]-(:AZTenant) + WHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned') + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + From 4ea1c8fbc931cd0c8c776879f478a1fd68d0bc92 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 12 Sep 2025 10:53:50 +0200 Subject: [PATCH 03/22] Create Locations of Owned objects - AD.yml Similar to the query "Locations of Tier Zero / High-Value objects" for AD --- queries/Locations of Owned objects - AD.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 queries/Locations of Owned objects - AD.yml diff --git a/queries/Locations of Owned objects - AD.yml b/queries/Locations of Owned objects - AD.yml new file mode 100644 index 0000000..81e2154 --- /dev/null +++ b/queries/Locations of Owned objects - AD.yml @@ -0,0 +1,15 @@ +name: Locations of Owned objects +guid: c88bfab4-3da0-4b36-b71d-7b324ebd2243 +prebuilt: false +platforms: Active Directory +category: Domain Information +description: +query: |- + MATCH p = (t:Base)<-[:Contains*1..]-(:Domain) + WHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned') + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + From 2630d9e01e53e595a4260f6ad23b04877b3f7d98 Mon Sep 17 00:00:00 2001 From: Martin Date: Fri, 12 Sep 2025 10:54:24 +0200 Subject: [PATCH 04/22] Fix category: Map Azure Management structure --- queries/Map Azure Management structure.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries/Map Azure Management structure.yml b/queries/Map Azure Management structure.yml index a1b1049..180e1a2 100644 --- a/queries/Map Azure Management structure.yml +++ b/queries/Map Azure Management structure.yml @@ -2,13 +2,13 @@ name: Map Azure Management structure guid: c1bb109e-e6a4-4c91-864f-f78e1e42615e prebuilt: false platforms: Azure -category: Kerberos Interaction +category: General description: Maps the structure of Azure Management query: |- MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup) RETURN p LIMIT 1000 -revision: 1 +revision: 2 resources: https://learn.microsoft.com/en-us/azure/governance/management-groups/overview acknowledgements: Martin Sohn Christensen, @martinsohndk From 6a93807c3541fa29d19ec6b8fd866ebce1901817 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 7 Oct 2025 17:26:28 +0200 Subject: [PATCH 05/22] Update name from 'Account' to 'Object' --- queries/Non-Tier Zero account with excessive control.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries/Non-Tier Zero account with excessive control.yml b/queries/Non-Tier Zero account with excessive control.yml index 12af951..4437149 100644 --- a/queries/Non-Tier Zero account with excessive control.yml +++ b/queries/Non-Tier Zero account with excessive control.yml @@ -1,4 +1,4 @@ -name: Non-Tier Zero account with excessive control +name: Non-Tier Zero object with excessive control guid: 944cecfe-519b-4318-b226-e8520161b454 prebuilt: false platforms: Active Directory @@ -11,7 +11,7 @@ query: |- WITH n, COLLECT(DISTINCT(m)) AS endNodes WHERE SIZE(endNodes) >= 1000 RETURN n -revision: 3 +revision: 4 resources: acknowledgements: Martin Sohn Christensen, @martinsohndk From 75bf6ab355b77049c1ae91c798905f83a223dcd8 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 7 Oct 2025 19:10:15 +0200 Subject: [PATCH 06/22] Update queries to match BloodHound prebuilt query --- queries/All Global Administrators.yml | 5 +++-- queries/Computers with membership in Protected Users.yml | 4 ++-- queries/Dangerous privileges for Domain Users groups.yml | 5 +++-- ...s where any user can join a computer to the domain.yml | 8 ++++---- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/queries/All Global Administrators.yml b/queries/All Global Administrators.yml index 7077923..4d30e57 100644 --- a/queries/All Global Administrators.yml +++ b/queries/All Global Administrators.yml @@ -5,10 +5,11 @@ platforms: Azure category: General description: query: |- - MATCH p = (:AZBase)-[:AZGlobalAdmin*1..]->(:AZTenant) + MATCH p=(:AZBase)-[:AZHasRole*1..]->(t:AZRole) + WHERE t.name =~ '(?i)Global Administrator.*' RETURN p LIMIT 1000 -revision: 1 +revision: 2 resources: acknowledgements: diff --git a/queries/Computers with membership in Protected Users.yml b/queries/Computers with membership in Protected Users.yml index 4fb7a4d..d9e8b73 100644 --- a/queries/Computers with membership in Protected Users.yml +++ b/queries/Computers with membership in Protected Users.yml @@ -6,9 +6,9 @@ category: NTLM Relay Attacks description: query: |- MATCH p = (:Base)-[:MemberOf*1..]->(g:Group) - WHERE g.objectid ENDS WITH "-525" + WHERE g.objectid ENDS WITH '-525' RETURN p LIMIT 1000 -revision: 1 +revision: 2 resources: acknowledgements: diff --git a/queries/Dangerous privileges for Domain Users groups.yml b/queries/Dangerous privileges for Domain Users groups.yml index fdf2e01..8746be2 100644 --- a/queries/Dangerous privileges for Domain Users groups.yml +++ b/queries/Dangerous privileges for Domain Users groups.yml @@ -5,11 +5,12 @@ platforms: Active Directory category: Dangerous Privileges description: query: |- - MATCH p=(s:Group)-[:AD_ATTACK_PATHS]->(:Base) + MATCH p=(s:Group)-[r:AD_ATTACK_PATHS]->(:Base) WHERE s.objectid ENDS WITH '-513' + AND NOT r:MemberOf RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: diff --git a/queries/Domains where any user can join a computer to the domain.yml b/queries/Domains where any user can join a computer to the domain.yml index d46f849..f1ff6b8 100644 --- a/queries/Domains where any user can join a computer to the domain.yml +++ b/queries/Domains where any user can join a computer to the domain.yml @@ -5,10 +5,10 @@ platforms: Active Directory category: Active Directory Hygiene description: query: |- - MATCH (n:Domain) - WHERE n.machineaccountquota > 0 - RETURN n -revision: 1 + MATCH (d:Domain) + WHERE d.machineaccountquota > 0 + RETURN d +revision: 2 resources: - https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/default-workstation-numbers-join-domain - https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/add-workstations-to-domain From daf610e4e4896339718c14d702021a219ddaa940 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 7 Oct 2025 19:16:25 +0200 Subject: [PATCH 07/22] Add support for node labels vs legacy system_tags --- .../Kerberoastable members of Tier Zero High Value groups.yml | 4 ++-- queries/Shortest paths from Owned objects.yml | 4 ++-- queries/Shortest paths to Tier Zero High Value targets.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/queries/Kerberoastable members of Tier Zero High Value groups.yml b/queries/Kerberoastable members of Tier Zero High Value groups.yml index 08c6abe..3b1f2ac 100644 --- a/queries/Kerberoastable members of Tier Zero High Value groups.yml +++ b/queries/Kerberoastable members of Tier Zero High Value groups.yml @@ -6,14 +6,14 @@ category: Kerberos Interaction description: query: |- MATCH (u:User) - WHERE (u:Tag_Tier_Zero) AND u.hasspn=true + WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.hasspn=true AND u.enabled = true AND NOT u.objectid ENDS WITH '-502' AND NOT COALESCE(u.gmsa, false) = true AND NOT COALESCE(u.msa, false) = true RETURN u LIMIT 100 -revision: 1 +revision: 2 resources: https://attack.mitre.org/techniques/T1558/003/ acknowledgements: diff --git a/queries/Shortest paths from Owned objects.yml b/queries/Shortest paths from Owned objects.yml index 10e86aa..e6183e8 100644 --- a/queries/Shortest paths from Owned objects.yml +++ b/queries/Shortest paths from Owned objects.yml @@ -6,11 +6,11 @@ category: Shortest Paths description: query: |- MATCH p=shortestPath((s:Base)-[:AD_ATTACK_PATHS*1..]->(t:Base)) - WHERE (s:Tag_Owned) + WHERE ((s:Tag_Owned) OR COALESCE(s.system_tags, '') CONTAINS 'owned') AND s<>t RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: diff --git a/queries/Shortest paths to Tier Zero High Value targets.yml b/queries/Shortest paths to Tier Zero High Value targets.yml index 580a030..2d1bfcb 100644 --- a/queries/Shortest paths to Tier Zero High Value targets.yml +++ b/queries/Shortest paths to Tier Zero High Value targets.yml @@ -5,11 +5,11 @@ platforms: Active Directory category: Shortest Paths description: query: |- - MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Tag_Tier_Zero)) + MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')) WHERE s<>t RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: From a9a58af64476e1b429ab9e1ed4e9207f9d8da360 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 7 Oct 2025 21:54:59 +0200 Subject: [PATCH 08/22] Pull in new BloodHound queries --- ...re smart account passwords do not expire.yml | 15 +++++++++++++++ ...Holder to protected objects relationship.yml | 13 +++++++++++++ ...CA Administrators and CA Managers (ESC7).yml | 13 +++++++++++++ ...omising permissions on ADCS nodes (ESC5).yml | 17 +++++++++++++++++ ...A with User Specified SAN enabled (ESC6).yml | 14 ++++++++++++++ ... with vulnerable HTTP(S) endpoint (ESC8).yml | 14 ++++++++++++++ ... with Entra Admin Role approval (direct).yml | 12 ++++++++++++ ...ra Admin Role approval (group delegated).yml | 12 ++++++++++++ ...with Entra Admin Role direct eligibility.yml | 12 ++++++++++++ ... Admin Roles group delegated eligibility.yml | 12 ++++++++++++ ...ation of AdminSDHolder Protected objects.yml | 14 ++++++++++++++ ... with Entra Admin Role approval (direct).yml | 14 ++++++++++++++ ...ra Admin Role approval (group delegated).yml | 14 ++++++++++++++ ...with Entra Admin Role direct eligibility.yml | 14 ++++++++++++++ ... Admin Roles group delegated eligibility.yml | 14 ++++++++++++++ ...ncipals without AdminSDHolder protection.yml | 15 +++++++++++++++ 16 files changed, 219 insertions(+) create mode 100644 queries/Accounts with smart card required in domains where smart account passwords do not expire.yml create mode 100644 queries/AdminSDHolder to protected objects relationship.yml create mode 100644 queries/CA Administrators and CA Managers (ESC7).yml create mode 100644 queries/Compromising permissions on ADCS nodes (ESC5).yml create mode 100644 queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6).yml create mode 100644 queries/Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8).yml create mode 100644 queries/Entra Users with Entra Admin Role approval (direct).yml create mode 100644 queries/Entra Users with Entra Admin Role approval (group delegated).yml create mode 100644 queries/Entra Users with Entra Admin Role direct eligibility.yml create mode 100644 queries/Entra Users with Entra Admin Roles group delegated eligibility.yml create mode 100644 queries/Location of AdminSDHolder Protected objects.yml create mode 100644 queries/Synced Entra Users with Entra Admin Role approval (direct).yml create mode 100644 queries/Synced Entra Users with Entra Admin Role approval (group delegated).yml create mode 100644 queries/Synced Entra Users with Entra Admin Role direct eligibility.yml create mode 100644 queries/Synced Entra Users with Entra Admin Roles group delegated eligibility.yml create mode 100644 queries/Tier Zero principals without AdminSDHolder protection.yml diff --git a/queries/Accounts with smart card required in domains where smart account passwords do not expire.yml b/queries/Accounts with smart card required in domains where smart account passwords do not expire.yml new file mode 100644 index 0000000..bcdbab2 --- /dev/null +++ b/queries/Accounts with smart card required in domains where smart account passwords do not expire.yml @@ -0,0 +1,15 @@ +name: Accounts with smart card required in domains where smart account passwords do not expire +guid: bba7985e-f32a-4c62-b1b0-0365bf1455e6 +prebuilt: true +platforms: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(s:Domain)-[:Contains*1..]->(t:Base) + WHERE s.expirepasswordsonsmartcardonlyaccounts = false + AND t.enabled = true + AND t.smartcardrequired = true + RETURN p +revision: 1 +resources: +acknowledgements: diff --git a/queries/AdminSDHolder to protected objects relationship.yml b/queries/AdminSDHolder to protected objects relationship.yml new file mode 100644 index 0000000..df1d9cd --- /dev/null +++ b/queries/AdminSDHolder to protected objects relationship.yml @@ -0,0 +1,13 @@ +name: AdminSDHolder to protected objects relationship +guid: c751f95c-8bb0-4be4-b027-84f5709c91d2 +prebuilt: true +platforms: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n)-[:ProtectAdminGroups]->(m) + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: diff --git a/queries/CA Administrators and CA Managers (ESC7).yml b/queries/CA Administrators and CA Managers (ESC7).yml new file mode 100644 index 0000000..0d6f522 --- /dev/null +++ b/queries/CA Administrators and CA Managers (ESC7).yml @@ -0,0 +1,13 @@ +name: CA Administrators and CA Managers (ESC7) +guid: 77a708b8-962e-4c3d-ad70-e994126aaeba +prebuilt: true +platforms: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA) + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Compromising permissions on ADCS nodes (ESC5).yml b/queries/Compromising permissions on ADCS nodes (ESC5).yml new file mode 100644 index 0000000..0eedaa6 --- /dev/null +++ b/queries/Compromising permissions on ADCS nodes (ESC5).yml @@ -0,0 +1,17 @@ +name: Compromising permissions on ADCS nodes (ESC5) +guid: 396c7b67-fb5d-4c04-bb13-8007f0dfc9b1 +prebuilt: true +platforms: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (n:Base)-[:Owns|WriteOwner|WriteDacl|GenericAll|GenericWrite]->(m:Base) + WHERE m.distinguishedname CONTAINS "PUBLIC KEY SERVICES" + AND NOT n.objectid ENDS WITH "-512" // Domain Admins + AND NOT n.objectid ENDS WITH "-519" // Enterprise Admins + AND NOT n.objectid ENDS WITH "-544" // Administrators + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6).yml b/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6).yml new file mode 100644 index 0000000..3fadf6f --- /dev/null +++ b/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6).yml @@ -0,0 +1,14 @@ +name: Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6) +guid: ab14e9dc-996c-4737-878c-583c19cdbf5a +prebuilt: true +platforms: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA) + WHERE eca.isuserspecifiessanenabled = True + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8).yml b/queries/Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8).yml new file mode 100644 index 0000000..a02e6e9 --- /dev/null +++ b/queries/Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8).yml @@ -0,0 +1,14 @@ +name: Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8) +guid: 1c1435b1-bad0-49f2-ba7d-932e047c0af4 +prebuilt: true +platforms: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA) + WHERE eca.hasvulnerableendpoint = True + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Entra Users with Entra Admin Role approval (direct).yml b/queries/Entra Users with Entra Admin Role approval (direct).yml new file mode 100644 index 0000000..9f0ff56 --- /dev/null +++ b/queries/Entra Users with Entra Admin Role approval (direct).yml @@ -0,0 +1,12 @@ +name: Entra Users with Entra Admin Role approval (direct) +guid: 74d7993c-24af-4df7-8402-5c6fb22d088c +prebuilt: true +platforms: Azure +category: General +description: +query: |- + MATCH p = (:AZUser)-[:AZRoleApprover]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Entra Users with Entra Admin Role approval (group delegated).yml b/queries/Entra Users with Entra Admin Role approval (group delegated).yml new file mode 100644 index 0000000..b7a9f1a --- /dev/null +++ b/queries/Entra Users with Entra Admin Role approval (group delegated).yml @@ -0,0 +1,12 @@ +name: Entra Users with Entra Admin Role approval (group delegated) +guid: b70a6512-21e1-4d6e-926a-fba44646085d +prebuilt: true +platforms: Azure +category: General +description: +query: |- + MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Entra Users with Entra Admin Role direct eligibility.yml b/queries/Entra Users with Entra Admin Role direct eligibility.yml new file mode 100644 index 0000000..12625c5 --- /dev/null +++ b/queries/Entra Users with Entra Admin Role direct eligibility.yml @@ -0,0 +1,12 @@ +name: Entra Users with Entra Admin Role direct eligibility +guid: b87899ce-3a51-401a-ae39-ef271b566e3d +prebuilt: true +platforms: Azure +category: General +description: +query: |- + MATCH p = (:AZUser)-[:AZRoleEligible]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Entra Users with Entra Admin Roles group delegated eligibility.yml b/queries/Entra Users with Entra Admin Roles group delegated eligibility.yml new file mode 100644 index 0000000..8009438 --- /dev/null +++ b/queries/Entra Users with Entra Admin Roles group delegated eligibility.yml @@ -0,0 +1,12 @@ +name: Entra Users with Entra Admin Roles group delegated eligibility +guid: 2e36c81b-25ed-40ba-afec-5f5f6443e095 +prebuilt: true +platforms: Azure +category: General +description: +query: |- + MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Location of AdminSDHolder Protected objects.yml b/queries/Location of AdminSDHolder Protected objects.yml new file mode 100644 index 0000000..a060f9c --- /dev/null +++ b/queries/Location of AdminSDHolder Protected objects.yml @@ -0,0 +1,14 @@ +name: Location of AdminSDHolder Protected objects +guid: 3408ccaf-1f42-4c10-b09a-e986661f84d7 +prebuilt: true +platforms: Active Directory +category: Domain Information +description: +query: |- + MATCH p = (n:Base)<-[:Contains*1..]-(:Domain) + WHERE n.adminsdholderprotected = True + RETURN p + LIMIT 1000 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Synced Entra Users with Entra Admin Role approval (direct).yml b/queries/Synced Entra Users with Entra Admin Role approval (direct).yml new file mode 100644 index 0000000..9363770 --- /dev/null +++ b/queries/Synced Entra Users with Entra Admin Role approval (direct).yml @@ -0,0 +1,14 @@ +name: Synced Entra Users with Entra Admin Role approval (direct) +guid: 1bfe2d75-0a51-4dbe-abc6-178cc0e4476f +prebuilt: true +platforms: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleApprover]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Synced Entra Users with Entra Admin Role approval (group delegated).yml b/queries/Synced Entra Users with Entra Admin Role approval (group delegated).yml new file mode 100644 index 0000000..ab42435 --- /dev/null +++ b/queries/Synced Entra Users with Entra Admin Role approval (group delegated).yml @@ -0,0 +1,14 @@ +name: Synced Entra Users with Entra Admin Role approval (group delegated) +guid: ead56ecb-fb88-427c-8f39-75e774bb9a0a +prebuilt: true +platforms: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Synced Entra Users with Entra Admin Role direct eligibility.yml b/queries/Synced Entra Users with Entra Admin Role direct eligibility.yml new file mode 100644 index 0000000..db1d12a --- /dev/null +++ b/queries/Synced Entra Users with Entra Admin Role direct eligibility.yml @@ -0,0 +1,14 @@ +name: Synced Entra Users with Entra Admin Role direct eligibility +guid: ea82e359-725c-4881-83e9-35007e859cf5 +prebuilt: true +platforms: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleEligible]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Synced Entra Users with Entra Admin Roles group delegated eligibility.yml b/queries/Synced Entra Users with Entra Admin Roles group delegated eligibility.yml new file mode 100644 index 0000000..00b51b1 --- /dev/null +++ b/queries/Synced Entra Users with Entra Admin Roles group delegated eligibility.yml @@ -0,0 +1,14 @@ +name: Synced Entra Users with Entra Admin Roles group delegated eligibility +guid: bc610e20-e5c0-41f3-9e8e-7378f87a3f71 +prebuilt: true +platforms: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole) + RETURN p LIMIT 100 +revision: 1 +resources: +acknowledgements: diff --git a/queries/Tier Zero principals without AdminSDHolder protection.yml b/queries/Tier Zero principals without AdminSDHolder protection.yml new file mode 100644 index 0000000..7f49533 --- /dev/null +++ b/queries/Tier Zero principals without AdminSDHolder protection.yml @@ -0,0 +1,15 @@ +name: Tier Zero principals without AdminSDHolder protection +guid: 82ce5e2e-415b-489d-b891-304e8bb25998 +prebuilt: true +platforms: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Base) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND n.adminsdholderprotected = false + RETURN n + LIMIT 500 +revision: 1 +resources: +acknowledgements: From bdeaaa961b907ed54fac1fb89a487fbbb20a3766 Mon Sep 17 00:00:00 2001 From: Martin Date: Tue, 7 Oct 2025 21:58:39 +0200 Subject: [PATCH 09/22] Add warning to description of many-to-many query --- queries/Shortest paths from Owned objects to Tier Zero.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/queries/Shortest paths from Owned objects to Tier Zero.yml b/queries/Shortest paths from Owned objects to Tier Zero.yml index a307398..9d6dffc 100644 --- a/queries/Shortest paths from Owned objects to Tier Zero.yml +++ b/queries/Shortest paths from Owned objects to Tier Zero.yml @@ -3,7 +3,7 @@ guid: dfaa8e8f-2c79-4e92-a291-b1347f6e83b0 prebuilt: true platforms: Active Directory category: Shortest Paths -description: +description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- // MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE MATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base)) @@ -11,7 +11,7 @@ query: |- AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: From 19cf74f5108e2d6f0208346b6ae1cd2699cdbb78 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 9 Oct 2025 10:51:09 +0200 Subject: [PATCH 10/22] Update name from 'Account' to 'Object' --- docs/security-assessment-mapping.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/security-assessment-mapping.json b/docs/security-assessment-mapping.json index f45f5ad..5b3e351 100644 --- a/docs/security-assessment-mapping.json +++ b/docs/security-assessment-mapping.json @@ -1242,7 +1242,7 @@ { "bloodhound_query": { "guid": "944cecfe-519b-4318-b226-e8520161b454", - "name": "Non-Tier Zero account with excessive control" + "name": "Non-Tier Zero object with excessive control" }, "maps_to": [ { From 78a4305131119d599332723f8da85748d560241e Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 9 Oct 2025 10:51:38 +0200 Subject: [PATCH 11/22] Delete Collection health of specific computer.yml Query was duplicate of 'All incoming and local paths for a specific computer' - https://queries.specterops.io/?input=1f67e538-19d4-4020-89c8-5b39b31571bd --- .../Collection health of specific computer.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 queries/Collection health of specific computer.yml diff --git a/queries/Collection health of specific computer.yml b/queries/Collection health of specific computer.yml deleted file mode 100644 index 943d6f6..0000000 --- a/queries/Collection health of specific computer.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Collection health of specific computer -guid: bb95c9c5-984c-4057-a430-000d684c069a -prebuilt: false -platforms: Active Directory -category: Domain Information -description: Returns Local groups and their members, and Principals with privileges -query: |- - MATCH p=(m:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(n:Base) - - // Insert computer FQDN - WHERE m.name ENDS WITH "HOSTNAME.DOMAIN.LOCAL" - - RETURN p -revision: 1 -resources: -acknowledgements: Martin Sohn Christensen, @martinsohndk - From b23f7b6292a2734d30a5164d4b8d89f52fe5ce91 Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 9 Oct 2025 10:55:11 +0200 Subject: [PATCH 12/22] address failed test: yaml.scanner.ScannerError: mapping values are not allowed here in "queries/Shortest paths from Owned objects to Tier Zero.yml", line 6, column 21 --- queries/Shortest paths from Owned objects to Tier Zero.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/queries/Shortest paths from Owned objects to Tier Zero.yml b/queries/Shortest paths from Owned objects to Tier Zero.yml index 9d6dffc..f99d1b6 100644 --- a/queries/Shortest paths from Owned objects to Tier Zero.yml +++ b/queries/Shortest paths from Owned objects to Tier Zero.yml @@ -3,7 +3,7 @@ guid: dfaa8e8f-2c79-4e92-a291-b1347f6e83b0 prebuilt: true platforms: Active Directory category: Shortest Paths -description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING - MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- // MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE MATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base)) From fe165c91c0933645781bf24e7ce85d4dc82b793c Mon Sep 17 00:00:00 2001 From: Martin Date: Thu, 9 Oct 2025 11:00:21 +0200 Subject: [PATCH 13/22] address failed test: Failed: Parsing failed for file queries/Shortest paths to Tier Zero High Value targets.yml: Syntax error at line: 1 --- queries/Shortest paths to Tier Zero High Value targets.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/queries/Shortest paths to Tier Zero High Value targets.yml b/queries/Shortest paths to Tier Zero High Value targets.yml index 2d1bfcb..50fb685 100644 --- a/queries/Shortest paths to Tier Zero High Value targets.yml +++ b/queries/Shortest paths to Tier Zero High Value targets.yml @@ -5,8 +5,9 @@ platforms: Active Directory category: Shortest Paths description: query: |- - MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')) - WHERE s<>t + MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Base)) + WHERE ((t:Tag_Tier_Zero) OR (COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')) + AND s<>t RETURN p LIMIT 1000 revision: 3 From f244967c06e4d138bb96596a7887bf077eeb8b5e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 9 Oct 2025 09:01:10 +0000 Subject: [PATCH 14/22] Update combined queries --- Queries.json | 2416 +++++++++++++++++++++++++++----------------------- 1 file changed, 1330 insertions(+), 1086 deletions(-) diff --git a/Queries.json b/Queries.json index 30a1005..5c8a3f8 100644 --- a/Queries.json +++ b/Queries.json @@ -1,4 +1,48 @@ [ + { + "name": "CA administrators and CA managers", + "guid": "fd35e3d8-0c74-4b5a-a847-c0dd1f1c9f19", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Principals with passwords stored using reversible encryption", + "guid": "ab900835-b2b8-4674-87b4-8b5141e80439", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:Base)\nWHERE n.encryptedtextpwdallowed = true\nRETURN n", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Tier Zero users with email", + "guid": "9654c0d4-f1e8-4393-a2d1-53a5554a9de8", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": "Tier Zero accounts with email access have an increased attack surface.", + "query": "MATCH (n)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.email <> \"\"\nAND n.enabled = true\nAND NOT toUpper(n.email) ENDS WITH \".ONMICROSOFT.COM\"\nAND NOT (\n (toUpper(n.email) STARTS WITH \"HEALTHMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERYMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERY\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHAPPROVAL\"\n OR toUpper(n.email) STARTS WITH \"FEDERATEDEMAIL\"\n OR toUpper(n.email) STARTS WITH \"SYSTEMMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MIGRATION.\")\n AND\n (n.name STARTS WITH \"SM_\"\n OR n.name STARTS WITH \"HEALTHMAILBOX\")\n)\nRETURN n", + "revision": 1, + "resources": [], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, { "name": "Computers without Windows LAPS", "guid": "7c50f724-c467-4005-8e3f-9a6ce1461db0", @@ -18,31 +62,49 @@ ] }, { - "name": "Domains with functional level not the latest version", - "guid": "3da9d14a-f1cb-4df7-b3da-8d73ff5c401b", + "name": "Foreign Service Principals With Group Memberships", + "guid": "327ef6a5-bfa8-4c92-b35a-d3df85264a24", "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (n:Domain)\nWHERE toString(n.functionallevel) IN ['2008','2003','2003 Interim','2000 Mixed/Native']\nRETURN n", + "category": "Azure Hygiene", + "description": "Review each to validate whether their presence is expected and whether the assigned group memberships are appropriate for the foreign service principal.", + "query": "MATCH p = (sp:AZServicePrincipal)-[:AZMemberOf]->(g:AZGroup)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(g.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", "revision": 1, + "resources": [ + "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" + ], + "acknowledgements": [ + "Stephen Hinck" + ] + }, + { + "name": "All incoming and local paths for a specific computer", + "guid": "1f67e538-19d4-4020-89c8-5b39b31571bd", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Domain Information", + "description": "All incoming and local paths for a specific computer; incoming from domain objects and paths local inside the computer.", + "query": "// Replace 'HOSTNAME' with the computer's shortname eg. 'SRV01', not FQDN\nMATCH p=(n:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base)\nWHERE m.name CONTAINS 'HOSTNAME'\nAND m.name CONTAINS '.' // Only see computer-related objects (eg. not AD Groups)\nRETURN p", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Kerberos-enabled service account member of built-in Admins groups", - "guid": "42a856fc-257a-4142-9592-ca95fd49e579", + "name": "Non-Tier Zero account with unconstrained delegation", + "guid": "e7e9a927-3f34-42c7-b921-d8bcf626011e", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(g:Group)\nWHERE (\n g.objectid ENDS WITH '-512' // Domain Admins\n OR g.objectid ENDS WITH '-519' // Enterprise Admins\n OR g.objectid ENDS WITH '-518' // Schema Admins\n)\nAND n.hasspn = true\nRETURN p", + "query": "MATCH (n:Base)\nWHERE n.unconstraineddelegation = true\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -50,38 +112,44 @@ ] }, { - "name": "Shortest paths to privileged roles", - "guid": "3dc73dd8-4873-4aeb-a88f-56a58c77f512", - "prebuilt": true, + "name": "Circular AZ group memberships", + "guid": "b005669c-d8af-47ae-a0f1-4f36cd5334ab", + "prebuilt": false, "platforms": [ "Azure" ], - "category": "Shortest Paths", - "description": null, - "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole))\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] + "category": "Azure Hygiene", + "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", + "query": "MATCH p=(x:AZGroup)-[:AZMemberOf*2..]->(y:AZGroup)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", + "revision": 1, + "resources": [ + "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Tier Zero users with passwords not rotated in over 1 year", - "guid": "5e0d69b1-37d1-43ae-ac5d-f297f312fab5", + "name": "Non-Tier Zero principals with BadSuccessor rights (no prerequisites check)", + "guid": "2b9fb71e-73ad-4061-a2df-40c7132b044d", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": null, - "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", + "category": "Dangerous Privileges", + "description": "Finds non-Tier Zero principals with BadSuccessor rights with no prerequisites check (DC2025 & KDC key).", + "query": "// Find OU control\nMATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p LIMIT 1000", "revision": 1, - "resources": [], + "resources": [ + "https://bsky.app/profile/specterops.io/post/3lpua65qeu22l" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "On-Prem Users synced to Entra Users with Azure RM Roles (group delegated)", - "guid": "e4f2eada-8a89-4ba9-89eb-abbee4efbc7a", + "name": "On-Prem Users synced to Entra Users that Own Entra Objects", + "guid": "4baf1026-e64c-4e31-afeb-2090b8090130", "prebuilt": true, "platforms": [ "Active Directory", @@ -89,35 +157,37 @@ ], "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwns]->(:AZBase)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled", - "guid": "96e70597-2d74-4503-a624-f1e30b642894", - "prebuilt": true, + "name": "Domains without Microsoft LAPS computers", + "guid": "f9b440b5-732c-4ed3-b6d2-83857db17e1a", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Domain Information", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", + "query": "MATCH (d:Domain)\nOPTIONAL MATCH (c:Computer)\nWHERE c.domainsid = d.objectid AND c.haslaps = true\nWITH d, COLLECT(c) AS computers\nWHERE SIZE(computers) = 0\nRETURN d", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Domains allowing authenticated domain enumeration", - "guid": "1e1e6fdd-6973-4547-906c-a494b5fbdcba", + "name": "Accounts with SID History to a same-domain account", + "guid": "275d2d58-0cad-4cad-8103-e0874cece666", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", + "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE n.domainsid = m.domainsid\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -125,15 +195,15 @@ ] }, { - "name": "Unresolved SID with outbound control", - "guid": "4e8429f9-cba2-41e9-bac6-0c42f96b2c57", + "name": "Domains allowing authenticated domain enumeration", + "guid": "1e1e6fdd-6973-4547-906c-a494b5fbdcba", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Base)-[r]->(:Base)\nWHERE r.isacl\nAND n.name CONTAINS \"S-1-5-21-\" // Unresolved SID\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -141,15 +211,15 @@ ] }, { - "name": "Large default groups with outbound control of OUs", - "guid": "310b3626-f8e6-4ab0-832c-72df6048597f", + "name": "All Operators", + "guid": "3dfd0843-1ff9-4c21-aa67-feae08d109de", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Domain Information", "description": null, - "query": "MATCH p=(n:Group)-[]->(:OU)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", + "query": "MATCH p=(:Base)-[:MemberOf]->(n:Group)\nWHERE (\n n.objectid ENDS WITH 'S-1-5-32-551' OR // Backup Operators\n n.objectid ENDS WITH 'S-1-5-32-556' OR // Network Configuration Operators\n n.objectid ENDS WITH 'S-1-5-32-549' OR // Server Operators\n n.objectid ENDS WITH 'S-1-5-32-579' OR // Access Control Assistance Operators\n n.objectid ENDS WITH 'S-1-5-32-548' OR // Account Operators\n n.objectid ENDS WITH 'S-1-5-32-569' OR // Cryptographic Operators\n n.objectid ENDS WITH 'S-1-5-32-550' // Print Operators\n)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -157,74 +227,66 @@ ] }, { - "name": "Shortest paths to Tier Zero / High Value targets", - "guid": "237aac58-8641-4703-a9f7-001d69546fd8", + "name": "All coerce and NTLM relay edges", + "guid": "15c5ff3b-856c-44d1-a731-a8cb72512dd1", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Tag_Tier_Zero))\nWHERE s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], + "query": "MATCH p = (n:Base)-[:CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|CoerceAndRelayNTLMToADCS|CoerceAndRelayNTLMToSMB]->(:Base)\nRETURN p LIMIT 500", + "revision": 1, + "resources": [ + "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/" + ], "acknowledgements": [] }, { - "name": "Domain Controllers allowing NTLMv1 or LM authentication", - "guid": "4b42513c-f89d-47ff-8d98-908af49d2b48", + "name": "Entra ID SSO accounts not rolling Kerberos decryption key", + "guid": "1867abf8-08e3-4ea8-8f65-8366079d35c4", "prebuilt": false, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "NTLM Relay Attacks", - "description": null, - "query": "MATCH (dc:Computer)\nWHERE dc.isdc = true\nAND (dc.lmcompatibilitylevel IS NOT NULL AND NOT dc.lmcompatibilitylevel = 5)\nRETURN dc", + "category": "Configuration Weakness", + "description": "Microsoft highly recommends that you roll over the Entra ID SSO Kerberos decryption key at least every 30 days.", + "query": "MATCH (n:Computer)\nWHERE n.name STARTS WITH \"AZUREADSSOACC.\"\nAND n.pwdlastset < (datetime().epochseconds - (30 * 86400))\nRETURN n", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso-faq#how-can-i-roll-over-the-kerberos-decryption-key-of-the--azureadsso--computer-account-" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Principals with DES-only Kerberos authentication", - "guid": "d03ea1ef-70f0-439b-b1ef-d7f94ceb2af3", - "prebuilt": true, + "name": "Domains with more than 50 Tier Zero accounts", + "guid": "f046e95a-5f84-4e83-bcda-6e83f3d8e21a", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE n.enabled = true\nAND n.usedeskeyonly = true\nRETURN n", - "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "On-Prem Users synced to Entra Users with Azure RM Roles (direct)", - "guid": "8569113b-e42e-49b0-a968-53bcf0ccd970", - "prebuilt": true, - "platforms": [ - "Active Directory", - "Azure" - ], - "category": "Cross Platform Attack Paths", - "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)\nRETURN p\nLIMIT 1000", + "query": "MATCH (d:Domain)-[:Contains*1..]->(n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH d, COUNT(n) AS adminCount\nWHERE adminCount > 50\nRETURN d", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Domains with List Object mode enabled", - "guid": "05e2a94b-5ee6-47ec-b715-3982f30af01b", + "name": "Domains not mitigating CVE-2021-42291", + "guid": "02202726-d86d-46c2-891c-9770c635f76f", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Checks the fDoListObject flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{2}[^0].*\"\nRETURN n", + "category": "Active Directory Hygiene", + "description": "Checks the AttributeAuthorizationOnLDAPAdd flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \"^(.{0,27}|.{27}[^1].*)$\"\nRETURN n", "revision": 1, "resources": [ "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" @@ -234,112 +296,116 @@ ] }, { - "name": "CA administrators and CA managers", - "guid": "fd35e3d8-0c74-4b5a-a847-c0dd1f1c9f19", + "name": "Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8)", + "guid": "1c1435b1-bad0-49f2-ba7d-932e047c0af4", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.hasvulnerableendpoint = True\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers with unsupported operating systems", - "guid": "a87b558c-5746-4a90-9f83-c86e7b924a52", - "prebuilt": false, + "name": "Foreign principals in Tier Zero / High Value targets", + "guid": "95bec736-86ef-4017-8465-9b9b66548b17", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "Azure Hygiene", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c\nLIMIT 100", + "query": "MATCH (n:AZServicePrincipal)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT toUpper(n.appownerorganizationid) = toUpper(n.tenantid)\nAND n.appownerorganizationid CONTAINS '-'\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "All ADCS ESC privilege escalation edges", - "guid": "49db8edc-8421-438f-b97b-23c042959bef", - "prebuilt": false, + "name": "On-Prem Users synced to Entra Users with Azure RM Roles (group delegated)", + "guid": "e4f2eada-8a89-4ba9-89eb-abbee4efbc7a", + "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Active Directory Certificate Services", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p=(:Base)-[:ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|GoldenCert|CoerceAndRelayNTLMToADCS]->(:Base)\nRETURN p", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://posts.specterops.io/certified-pre-owned-d95910965cd2", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-1-799f3d3b03cf", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac", - "https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53", - "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/#:~:text=Introducing%20the%20CoerceAndRelayNTLMToADCS%20Edge" - ], - "acknowledgements": [ - "Jonas B\u00fclow Knudsen, @Jonas_B_K" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Tier Zero / High Value users with non-expiring passwords", - "guid": "4eca1b69-00a2-48a0-abb3-b94ea647cf6b", + "name": "Shortest paths from Owned objects", + "guid": "e370a01d-c129-4f19-b88d-9479cbe00028", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Shortest Paths", "description": null, - "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", - "revision": 1, + "query": "MATCH p=shortestPath((s:Base)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE ((s:Tag_Owned) OR COALESCE(s.system_tags, '') CONTAINS 'owned')\nAND s<>t\nRETURN p\nLIMIT 1000", + "revision": 3, "resources": [], "acknowledgements": [] }, { - "name": "Principals with foreign domain group membership", - "guid": "8fb3214a-5a75-4ecd-b293-c121abd94b4b", + "name": "Kerberoastable members of Tier Zero / High Value groups", + "guid": "e6da7800-ae06-41cb-80a6-d5421ab2143a", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Kerberos Interaction", "description": null, - "query": "MATCH p=(s:Base)-[:MemberOf]->(t:Group)\nWHERE s.domainsid<>t.domainsid\nRETURN p\nLIMIT 1000", + "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true \nRETURN u\nLIMIT 100", + "revision": 2, + "resources": [ + "https://attack.mitre.org/techniques/T1558/003/" + ], + "acknowledgements": [] + }, + { + "name": "Enrollment rights on published enrollment agent certificate templates", + "guid": "8483bf5b-89f1-4723-abb2-c48295f6393e", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE '1.3.6.1.4.1.311.20.2.1' IN ct.effectiveekus\nOR '2.5.29.37.0' IN ct.effectiveekus\nOR SIZE(ct.effectiveekus) = 0\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero accounts not members of Denied RODC Password Replication Group", - "guid": "e9613406-e346-410b-a033-690a6cf0c708", - "prebuilt": false, + "name": "Entra Users with Entra Admin Role approval (group delegated)", + "guid": "b70a6512-21e1-4d6e-926a-fba44646085d", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "General", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND (n:User or n:Computer)\nWITH n\nOPTIONAL MATCH (n)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH '-519'\nWITH n, m\nWHERE m IS NULL\nRETURN n", + "query": "MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Collection health of specific computer", - "guid": "bb95c9c5-984c-4057-a430-000d684c069a", + "name": "Domains affected by Exchange privilege escalation risk", + "guid": "f2d09c94-b6f2-4901-9a2d-f8bacd61edc7", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Returns Local groups and their members, and Principals with privileges", - "query": "MATCH p=(m:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(n:Base)\n\n// Insert computer FQDN\nWHERE m.name ENDS WITH \"HOSTNAME.DOMAIN.LOCAL\"\n\nRETURN p", + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(n:Group)-[r:WriteDacl|ForceChangePassword|AddMember]->(m:Base)\nWHERE n.name STARTS WITH \"EXCHANGE \"\nAND ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -347,73 +413,77 @@ ] }, { - "name": "Tier Zero users with email", - "guid": "9654c0d4-f1e8-4393-a2d1-53a5554a9de8", + "name": "Circular AD group memberships", + "guid": "fcaa5ffc-3d22-481f-a2a2-18a4eec30058", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Tier Zero accounts with email access have an increased attack surface.", - "query": "MATCH (n)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.email <> \"\"\nAND n.enabled = true\nAND NOT toUpper(n.email) ENDS WITH \".ONMICROSOFT.COM\"\nAND NOT (\n (toUpper(n.email) STARTS WITH \"HEALTHMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERYMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERY\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHAPPROVAL\"\n OR toUpper(n.email) STARTS WITH \"FEDERATEDEMAIL\"\n OR toUpper(n.email) STARTS WITH \"SYSTEMMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MIGRATION.\")\n AND\n (n.name STARTS WITH \"SM_\"\n OR n.name STARTS WITH \"HEALTHMAILBOX\")\n)\nRETURN n", + "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", + "query": "MATCH p=(x:Group)-[:MemberOf*2..]->(y:Group)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", "revision": 1, - "resources": [], + "resources": [ + "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domain Admins logons to non-Domain Controllers", - "guid": "e2f3fd0a-1df2-4089-b0a4-272ad6e369a9", + "name": "Map domain trusts", + "guid": "268d3d26-5bc2-4820-a6ed-09d20f3d5413", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Domain Information", "description": null, - "query": "MATCH (s)-[:MemberOf*0..]->(g:Group)\nWHERE g.objectid ENDS WITH '-516'\nWITH COLLECT(s) AS exclude\nMATCH p = (c:Computer)-[:HasSession]->(:User)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-512' AND NOT c IN exclude\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Domain)-[:SameForestTrust|CrossForestTrust]->(:Domain)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Domains with smart card accounts where smart account passwords do not expire", - "guid": "97e05e67-5961-4aba-a8e7-fe5f92334035", - "prebuilt": true, + "name": "Locations of Owned objects", + "guid": "350b8b8a-ea4c-44f3-874b-c9316de6c41b", + "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "General", "description": null, - "query": "MATCH (s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN s", + "query": "MATCH p = (t:AZBase)<-[:AZContains*1..]-(:AZTenant)\nWHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Enabled Tier Zero / High Value principals inactive for 60 days", - "guid": "72550bcb-3c4f-463d-8973-91a49163dc5a", + "name": "Enrollment rights on published certificate templates with no security extension", + "guid": "0677b70c-4e04-4e89-a6a2-f5764604a6a7", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "WITH 60 as inactive_days\nMATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.nosecurityextension = true\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enabled computers inactive for 180 days", - "guid": "0768e810-1e1e-4319-a216-76d9c2058644", + "name": "All Schema Admins", + "guid": "76d8e61d-7a86-40ff-8a85-fd37f1e2563f", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n\nLIMIT 1000", + "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE (n:User OR n:Computer)\nAND m.objectid ENDS WITH \"-518\" // Schema Admins\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -421,79 +491,57 @@ ] }, { - "name": "Users with logon scripts stored in a trusted domain", - "guid": "8d94d3f3-3d53-4939-a206-3c0a4dd3f646", - "prebuilt": false, + "name": "All service principals with Microsoft Graph App Role assignments", + "guid": "74440269-eb41-476b-8dec-b4095569b029", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "Microsoft Graph", "description": null, - "query": "MATCH (n:User)\nWHERE n.logonscript IS NOT NULL\nMATCH (d:Domain)<-[:SameForestTrust|CrossForestTrust]-(:Domain)-[:Contains*1..]->(n)\nWITH n,last(split(d.name, '@')) AS domain\nWHERE toUpper(n.logonscript) STARTS WITH (\"\\\\\\\\\" + domain + \"\\\\\")\nRETURN n", - "revision": 2, + "query": "MATCH p=(:AZServicePrincipal)-[:AZMGAppRoleAssignment_ReadWrite_All|AZMGApplication_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGGroupMember_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory|AZMGServicePrincipalEndpoint_ReadWrite_All]->(:AZServicePrincipal)\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Workstations where Domain Users can RDP", - "guid": "9486e0e6-2617-4595-b969-cf57ca21fc86", + "name": "Map OU structure", + "guid": "8f14084b-5065-43d8-865a-a6ac52da25d1", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Domain Information", "description": null, - "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND NOT toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Domain)-[:Contains*1..]->(:OU)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Computers with non-default Primary Group membership", - "guid": "5862dc4e-6f6f-4321-9474-d838968495ed", - "prebuilt": false, + "name": "Enrollment rights on CertTemplates with OIDGroupLink", + "guid": "140a68eb-d21c-4b75-971f-309225fb2d75", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-515\" // Domain Computers\nAND NOT g.objectid ENDS WITH \"-516\" // Domain Controllers\nAND NOT g.objectid ENDS WITH \"-521\" // Read-Only Domain Controllers\nAND r.isprimarygroup = true\nRETURN p", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:ExtendedByPolicy]->(:IssuancePolicy)-[:OIDGroupLink]->(:Group)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Domains with a minimum default password policy length less than 15 characters", - "guid": "7d258d2d-a43d-4a90-85d7-71c946ae5fd7", + "name": "Unresolved SID with outbound control", + "guid": "4e8429f9-cba2-41e9-bac6-0c42f96b2c57", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Domain)\nWHERE n.minpwdlength < 15\nRETURN n", - "revision": 1, - "resources": [ - "https://pages.nist.gov/800-63-3/sp800-63b.html" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Domain migration groups", - "guid": "f39c4953-ae92-4d67-bb50-eb1a161d4d3f", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Domain Information", - "description": null, - "query": "MATCH (n:Group)\nWHERE n.name CONTAINS \"$$$@\"\nRETURN n", + "query": "MATCH p=(n:Base)-[r]->(:Base)\nWHERE r.isacl\nAND n.name CONTAINS \"S-1-5-21-\" // Unresolved SID\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -501,45 +549,45 @@ ] }, { - "name": "PKI hierarchy", - "guid": "928acc23-ee4c-40a5-bde7-64c05cc1491d", + "name": "Principals with foreign domain group membership", + "guid": "8fb3214a-5a75-4ecd-b293-c121abd94b4b", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=()-[:HostsCAService|IssuedSignedBy|EnterpriseCAFor|RootCAFor|TrustedForNTAuth|NTAuthStoreFor*..]->(:Domain)\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(s:Base)-[:MemberOf]->(t:Group)\nWHERE s.domainsid<>t.domainsid\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Kerberos-enabled service accounts without AES encryption support", - "guid": "cb8cf96e-21c9-422b-9439-390a13446ca6", + "name": "Tier Zero computers at risk of constrained delegation", + "guid": "8641e593-f2f2-48ba-bd45-fbc86e9f632a", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Accounts without Kerberos AES encryption support, or passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", - "query": "MATCH (n:Base)\nWHERE n.hasspn = true\nAND ((\n n.supportedencryptiontypes <> ['Not defined']\n OR n.supportedencryptiontypes <> []\n OR NONE(type IN n.supportedencryptiontypes WHERE type CONTAINS 'AES128' OR type CONTAINS 'AES256')\n)\nOR (n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008\nAND NOT n.pwdlastset IN [-1.0, 0.0]\n))\nRETURN n\nLIMIT 100", - "revision": 2, + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p = (n:Computer)<-[:AllowedToDelegate]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains allowing unauthenticated domain enumeration", - "guid": "41a08d76-f8a5-4296-ad19-464c4c5c69fe", + "name": "Domains with a single-point-of-failure Domain Controller", + "guid": "3359a295-7cfd-491f-976b-c5a68647431c", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nOR n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", + "query": "MATCH (n:Group)<-[:MemberOf]-(:Computer)\nWHERE n.objectid ENDS WITH '-516'\nWITH n, COUNT(n) AS dcCount\nWHERE dcCount = 1\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -547,157 +595,167 @@ ] }, { - "name": "Collection health of CA Registry Data", - "guid": "c8dd3479-8063-450a-9456-557bc5f39e10", - "prebuilt": false, + "name": "Shortest paths from Owned objects to Tier Zero", + "guid": "dfaa8e8f-2c79-4e92-a291-b1347f6e83b0", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured CA to potentially a full forest compromise by any principal. CAs returned by this query have not been collected.", - "query": "MATCH p=(eca:EnterpriseCA)<-[:HostsCAService]-(c:Computer)\nWHERE (\n eca.isuserspecifiessanenabledcollected = false\n OR eca.casecuritycollected = false\n OR eca.enrollmentagentrestrictionscollected = false\n OR eca.roleseparationenabledcollected = false\n)\n// Exclude inactive CAs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", - "revision": 1, - "resources": [ - "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#ca-registry" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "category": "Shortest Paths", + "description": "WARNING - MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "query": "// MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE\nMATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 3, + "resources": [], + "acknowledgements": [] }, { - "name": "Enabled computers inactive for 180 days - MSSQL Failover Cluster", - "guid": "d263e621-7f1b-4efb-ad25-098fc7d4fb72", - "prebuilt": false, + "name": "Shortest paths from Domain Users to Tier Zero / High Value targets", + "guid": "469dc0f3-71b8-41b0-a03b-b4af7874665d", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Shortest Paths", "description": null, - "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND ANY(type IN n.serviceprincipalnames WHERE \n toLower(type) CONTAINS 'mssqlservercluster' OR \n toLower(type) CONTAINS 'mssqlserverclustermgmtapi' OR \n toLower(type) CONTAINS 'msclustervirtualserver')\nRETURN n\nLIMIT 1000", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/troubleshoot/windows-server/high-availability/troubleshoot-issues-accounts-used-failover-clusters#troubleshoot-password-issues-with-the-cluster-name-account" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] }, { - "name": "Principals with passwords stored using reversible encryption", - "guid": "ab900835-b2b8-4674-87b4-8b5141e80439", + "name": "Principals with DES-only Kerberos authentication", + "guid": "d03ea1ef-70f0-439b-b1ef-d7f94ceb2af3", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE n.encryptedtextpwdallowed = true\nRETURN n", + "query": "MATCH (n:Base)\nWHERE n.enabled = true\nAND n.usedeskeyonly = true\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero users not member of Protected Users", - "guid": "543eb01d-9fa3-4b8f-a936-b46bbfdaa2ae", - "prebuilt": false, + "name": "Synced Entra Users with Entra Admin Role approval (group delegated)", + "guid": "ead56ecb-fb88-427c-8f39-75e774bb9a0a", + "prebuilt": true, + "platforms": [ + "Active Directory", + "Azure" + ], + "category": "Cross Platform Attack Paths", + "description": null, + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Domain controllers with weak certificate binding enabled", + "guid": "a2444d99-10b5-412d-8fea-4b063cfddd2c", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (m:User)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nOPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)\nWHERE g.objectid ENDS WITH '-525'\nWITH m, COLLECT(n) AS matchingNs\nWHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)\nRETURN m", + "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.strongcertificatebindingenforcementraw = 0 OR s.strongcertificatebindingenforcementraw = 1\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Microsoft Entra Connect accounts with passwords not rotated in over 90 days", - "guid": "97fb1310-d15d-4d63-82a2-8788056250f1", + "name": "Computer owners who can obtain LAPS passwords", + "guid": "92aa81d6-b08e-4abb-ae39-ecbe5735a74c", "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Micosoft recommends to change the password of MSOL accounts every 90 days to prevent attackers from allowing use of the high privileges", - "query": "WITH 90 as days_since_change\nMATCH (u:User)\nWHERE u.name STARTS WITH \"MSOL_\"\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u", + "category": "Dangerous Privileges", + "description": "Creators of computer objects get abusable rights on the computer object. If the owner is not explicitly granted ReadLAPSPassword they can still compromise the computer with the abusable owner rights.", + "query": "MATCH p = (c:Computer)<-[:GenericAll|Owns|WriteDacl|WriteOwner|AllExtendedRights]-(n:User)\nWHERE c.haslaps = true AND c.ownersid = n.objectid\nRETURN p", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/defender-for-identity/rotate-password-microsoft-entra-connect" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Map OU structure", - "guid": "8f14084b-5065-43d8-865a-a6ac52da25d1", + "name": "Potential GPO 'Apply' misconfiguration", + "guid": "f5f2455e-afdc-4708-9a34-98f539ce52d8", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": null, - "query": "MATCH p = (:Domain)-[:Contains*1..]->(:OU)\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Dangerous Privileges", + "description": "In Active Directory, GPO's are applied to objects in the Group Policy Management Console by ticking \"Allow - Apply group policy\", but administrators can mistakenly tick \"Allow - Write\" or \"Allow - Full Control\" resulting in a misconfigured GPO that allows a principal to compromise other principals the GPO also applies to. Results are potential risks and must be audited for for correctness.", + "query": "MATCH p=(n:Base)-[:GenericAll|GenericWrite]->(g:GPO)\n\n// Exclude Enterprise Admins and Domain Admins\nWHERE NOT n.objectid =~ \"-(519|512)$\"\n\n// Exclude unresolved SIDs\nAND NOT (n.distinguishedname IS NULL)\n\n// Asset description may reveal if it's a delegation group (false-positive) or a filter group (true-positive)\n//AND n.description is not null\n//AND n.description =~ \"(?i)apply\"\n\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "On-Prem Users synced to Entra Users that Own Entra Objects", - "guid": "4baf1026-e64c-4e31-afeb-2090b8090130", - "prebuilt": true, + "name": "Domains with List Object mode enabled", + "guid": "05e2a94b-5ee6-47ec-b715-3982f30af01b", + "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", - "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwns]->(:AZBase)\nRETURN p\nLIMIT 1000", + "category": "Domain Information", + "description": "Checks the fDoListObject flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{2}[^0].*\"\nRETURN n", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Computers with the outgoing NTLM setting set to Deny all", - "guid": "a9ddca74-feeb-4dbf-8b0f-de08b3cfa8a6", + "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (direct)", + "guid": "de717635-d31f-4fbd-930b-b4dac0f22118", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "NTLM Relay Attacks", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.restrictoutboundntlm = True\nRETURN c LIMIT 1000", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Disabled Tier Zero / High Value principals", - "guid": "d65a801f-d3ef-4b7e-8030-99ebfd6dad12", - "prebuilt": true, + "name": "Enabled built-in guest user accounts", + "guid": "bb0f620d-6a55-4413-ac74-4c82905e8598", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nAND NOT n.objectid ENDS WITH '-502' // Removes false positive, KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 100", + "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-501\"\nAND n.enabled = true\nRETURN n", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Domains affected by AdPrep privilege escalation risk", - "guid": "815ff190-f6f3-4757-a516-2f4bf589b705", + "name": "Large default groups with outbound control of OUs", + "guid": "310b3626-f8e6-4ab0-832c-72df6048597f", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Group)-[r:GenericAll]->(m:Domain)\nWHERE n.objectid ENDS WITH \"-527\" // Enterprise Key Admins\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH p=(n:Group)-[]->(:OU)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -705,95 +763,73 @@ ] }, { - "name": "Computers with unsupported operating systems", - "guid": "d06d3b14-0318-4fa9-9639-4b79ccaf3c2c", + "name": "Enrollment rights on published ESC1 certificate templates", + "guid": "2af855bc-f48f-4b22-9839-627d8231e425", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nRETURN c\nLIMIT 100", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = True\nAND ct.requiresmanagerapproval = False\nAND (ct.authorizedsignatures = 0 OR ct.schemaversion = 1)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "AS-REP Roastable Tier Zero users (DontReqPreAuth)", - "guid": "6d51e4dc-e1ad-477a-b6c6-324f18f03120", - "prebuilt": false, + "name": "Users which do not require password to authenticate", + "guid": "23bdc2ad-6739-4b2b-85d3-258e3f424eb2", + "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.dontreqpreauth = true\nRETURN n", + "query": "MATCH (u:User)\nWHERE u.passwordnotreqd = true\nRETURN u\nLIMIT 100", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/004/" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Foreign Service Principals With any Abusable MS Graph App Role Assignment", - "guid": "d7a180c8-5624-4fc1-a407-deeb2ad3054c", - "prebuilt": false, + "name": "Domain Admins logons to non-Domain Controllers", + "guid": "e2f3fd0a-1df2-4089-b0a4-272ad6e369a9", + "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], "category": "Dangerous Privileges", - "description": "MS Graph app role assignments provide significant power within an Entra ID tenant, similar to an Admin role.", - "query": "MATCH p = (sp1:AZServicePrincipal)-[r:AZMGGroupMember_ReadWrite_All|AZMGServicePrincipalEndpoint_ReadWrite_All|AZMGAppRoleAssignment_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory]->(sp2:AZServicePrincipal)\nWHERE toUpper(sp1.appownerorganizationid) <> toUpper(sp1.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp1.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", + "description": null, + "query": "MATCH (s)-[:MemberOf*0..]->(g:Group)\nWHERE g.objectid ENDS WITH '-516'\nWITH COLLECT(s) AS exclude\nMATCH p = (c:Computer)-[:HasSession]->(:User)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-512' AND NOT c IN exclude\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" - ], - "acknowledgements": [ - "Stephen Hinck" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Computer owners who can obtain LAPS passwords", - "guid": "92aa81d6-b08e-4abb-ae39-ecbe5735a74c", + "name": "Kerberos-enabled service accounts without AES encryption support", + "guid": "cb8cf96e-21c9-422b-9439-390a13446ca6", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": "Creators of computer objects get abusable rights on the computer object. If the owner is not explicitly granted ReadLAPSPassword they can still compromise the computer with the abusable owner rights.", - "query": "MATCH p = (c:Computer)<-[:GenericAll|Owns|WriteDacl|WriteOwner|AllExtendedRights]-(n:User)\nWHERE c.haslaps = true AND c.ownersid = n.objectid\nRETURN p", - "revision": 1, + "category": "Active Directory Hygiene", + "description": "Accounts without Kerberos AES encryption support, or passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", + "query": "MATCH (n:Base)\nWHERE n.hasspn = true\nAND ((\n n.supportedencryptiontypes <> ['Not defined']\n OR n.supportedencryptiontypes <> []\n OR NONE(type IN n.supportedencryptiontypes WHERE type CONTAINS 'AES128' OR type CONTAINS 'AES256')\n)\nOR (n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008\nAND NOT n.pwdlastset IN [-1.0, 0.0]\n))\nRETURN n\nLIMIT 100", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Foreign principals in Tier Zero / High Value targets", - "guid": "95bec736-86ef-4017-8465-9b9b66548b17", - "prebuilt": true, - "platforms": [ - "Azure" - ], - "category": "Azure Hygiene", - "description": null, - "query": "MATCH (n:AZServicePrincipal)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT toUpper(n.appownerorganizationid) = toUpper(n.tenantid)\nAND n.appownerorganizationid CONTAINS '-'\nRETURN n\nLIMIT 100", - "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Enabled users inactive for 180 days", - "guid": "71972f3c-b32d-4023-a841-5cc8cc1c1867", + "name": "ACEs across trusts", + "guid": "c902d3b4-1a75-4335-acd7-28246dab746d", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": null, - "query": "WITH 180 as inactive_days\nMATCH (n:User)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 1000", + "category": "Domain Information", + "description": "ACEs granted across a trust, the ACEs are set on trusting objects and the rights are granted to objects from trusted domains.", + "query": "MATCH p=(trustedDomainPrincipal:Base)-[r]->(trustingDomainPrincipal:Base)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nAND r.isacl\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -801,87 +837,92 @@ ] }, { - "name": "Non-default permissions on IssuancePolicy nodes", - "guid": "b2280665-c91b-448c-8c0f-97d1f38b6f59", - "prebuilt": true, + "name": "Usage of built-in domain Administrator account", + "guid": "35b1206f-871b-44aa-a601-c5258060dfcf", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", - "description": null, - "query": "MATCH p = (s:Base)-[:GenericAll|GenericWrite|Owns|WriteOwner|WriteDacl]->(:IssuancePolicy)\nWHERE NOT s.objectid ENDS WITH '-512' AND NOT s.objectid ENDS WITH '-519'\nRETURN p\nLIMIT 1000", + "category": "Active Directory Hygiene", + "description": "Usage of Active Directory's built-in Administrator account is a sign that the account is not only used for break-glass purposes.", + "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-500\"\nAND (\n n.lastlogontimestamp > (datetime().epochseconds - (60 * 86400)) OR\n n.lastlogon > (datetime().epochseconds - (60 * 86400))\n)\nAND NOT n.whencreated > (datetime().epochseconds - (60 * 86400))\nRETURN n", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "All service principals with Microsoft Graph App Role assignments", - "guid": "74440269-eb41-476b-8dec-b4095569b029", + "name": "Synced Entra Users with Entra Admin Roles group delegated eligibility", + "guid": "bc610e20-e5c0-41f3-9e8e-7378f87a3f71", "prebuilt": true, "platforms": [ + "Active Directory", "Azure" ], - "category": "Microsoft Graph", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p=(:AZServicePrincipal)-[:AZMGAppRoleAssignment_ReadWrite_All|AZMGApplication_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGGroupMember_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory|AZMGServicePrincipalEndpoint_ReadWrite_All]->(:AZServicePrincipal)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Map domain trusts", - "guid": "268d3d26-5bc2-4820-a6ed-09d20f3d5413", + "name": "Computers with membership in Protected Users", + "guid": "a26372f4-2e92-49f6-8993-6657fbc1569a", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p = (:Domain)-[:SameForestTrust|CrossForestTrust]->(:Domain)\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p = (:Base)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-525'\nRETURN p LIMIT 1000", + "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "Locations of Tier Zero / High Value objects", - "guid": "18a83a17-b451-4343-acfe-7620516e2968", - "prebuilt": true, + "name": "Non-default members in Pre-Windows 2000 Compatible Access", + "guid": "091995b9-7254-473a-996f-6b8368d20431", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE NOT n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND NOT (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nAND NOT n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Trace ACE inheritance", - "guid": "8c5454df-3ae8-412c-b271-3c4c55df7141", + "name": "Domain migration groups", + "guid": "f39c4953-ae92-4d67-bb50-eb1a161d4d3f", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Domain Information", - "description": "When BloodHound shows that an inherited ACE applies to an object it does not show the source/where it is inherited from from (OU, Container, Domain root) - the source is where it should be remediated. This query can sometimes find the source of an inherited ACE, but only works if the ACE is set to also apply to the source itself.", - "query": "// Replace INSERT_OBJECT_ID with the affected principal\n// Replace 'GenericAll' with the specific edge you're tracing\nWITH \"INSERT_OBJECT_ID\" as OID\nMATCH p=()-[:GenericAll {isacl:true,isinherited:false}]->()-[:Contains*1..]->(:Base{objectid:OID})\nWHERE NONE(ou in NODES(p) WHERE ou:OU AND ou.isaclprotected IS NOT NULL)\nRETURN p", + "description": null, + "query": "MATCH (n:Group)\nWHERE n.name CONTAINS \"$$$@\"\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ - "Walter.Legowski, @SadProcessor" + "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains with a single-point-of-failure Domain Controller", - "guid": "3359a295-7cfd-491f-976b-c5a68647431c", + "name": "Non-default delegation on MicrosoftDNS container", + "guid": "008792c0-4458-46a1-a10d-50cdaf95af1e", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Group)<-[:MemberOf]-(:Computer)\nWHERE n.objectid ENDS WITH '-516'\nWITH n, COUNT(n) AS dcCount\nWHERE dcCount = 1\nRETURN n", + "query": "MATCH p=(n:Base)-[r]->(m:Container)\nWHERE m.distinguishedname STARTS WITH \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\"\nAND NOT n.name STARTS WITH \"DNSADMINS@\"\nAND NOT n.objectid =~ \"-(512|544|519|9)$\"\nAND r.isacl\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -889,38 +930,53 @@ ] }, { - "name": "Domains exempting privileged groups from AdminSDHolder protections", - "guid": "79f8d8f9-8291-4bf7-a13a-15989018075f", + "name": "Non-Tier Zero account with 'Admin Count' flag", + "guid": "e7f703b3-5dba-4aef-8346-4d589be2c828", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Checks the dwAdminSDExMask flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{15}[^0].*\"\nRETURN n", + "description": "Users who were a member of one of AD's built-in administrative groups but are not currently Tier Zero.", + "query": "MATCH (n:User)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.admincount = true\nRETURN n", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + "https://learn.microsoft.com/en-us/windows/win32/adschema/a-admincount" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains affected by Exchange privilege escalation risk", - "guid": "f2d09c94-b6f2-4901-9a2d-f8bacd61edc7", - "prebuilt": false, + "name": "Tier Zero principals without AdminSDHolder protection", + "guid": "82ce5e2e-415b-489d-b891-304e8bb25998", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[r:WriteDacl|ForceChangePassword|AddMember]->(m:Base)\nWHERE n.name STARTS WITH \"EXCHANGE \"\nAND ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.adminsdholderprotected = false\nRETURN n\nLIMIT 500", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] + }, + { + "name": "Domains where any user can join a computer to the domain", + "guid": "421921fa-bc0f-4659-9680-b7481adcb132", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (d:Domain)\nWHERE d.machineaccountquota > 0\nRETURN d", + "revision": 2, + "resources": [ + "https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/default-workstation-numbers-join-domain", + "https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/add-workstations-to-domain" + ], + "acknowledgements": [] }, { "name": "Tier Zero accounts that can be delegated", @@ -939,33 +995,52 @@ ] }, { - "name": "Shortest paths from Azure Applications to Tier Zero / High Value targets", - "guid": "60ff7c58-a98e-4bc1-9e32-8378d2db0c43", - "prebuilt": true, + "name": "Members of Allowed RODC Password Replication Group", + "guid": "19fc5acd-e30a-4038-a5b5-2e0494f93373", + "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Shortest Paths", + "category": "Domain Information", "description": null, - "query": "MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(:Base)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH \"-571\"\nRETURN p", "revision": 2, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "All Kerberoastable users", - "guid": "14ab4eaa-b73b-49c4-b2d1-1e020757c995", + "name": "Map Azure Management structure", + "guid": "c1bb109e-e6a4-4c91-864f-f78e1e42615e", + "prebuilt": false, + "platforms": [ + "Azure" + ], + "category": "General", + "description": "Maps the structure of Azure Management", + "query": "MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup)\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [ + "https://learn.microsoft.com/en-us/azure/governance/management-groups/overview" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated)", + "guid": "609d648f-7fb8-42d3-ad99-626f9ce1f121", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Kerberos Interaction", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (u:User)\nWHERE u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true\nRETURN u\nLIMIT 100", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/003/" - ], + "resources": [], "acknowledgements": [] }, { @@ -983,87 +1058,159 @@ "acknowledgements": [] }, { - "name": "Enrollment rights on published enrollment agent certificate templates", - "guid": "8483bf5b-89f1-4723-abb2-c48295f6393e", + "name": "Paths from Domain Users to Tier Zero / High Value targets", + "guid": "977bec40-565c-40b8-90c8-e3e122c291cd", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE '1.3.6.1.4.1.311.20.2.1' IN ct.effectiveekus\nOR '2.5.29.37.0' IN ct.effectiveekus\nOR SIZE(ct.effectiveekus) = 0\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "All Global Administrators", - "guid": "94d7d765-6837-4eb8-aa33-e1c9ef262cdc", + "name": "Kerberoastable users with most admin privileges", + "guid": "9907b208-494c-4ba6-846d-485e6de14e17", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "General", + "category": "Kerberos Interaction", "description": null, - "query": "MATCH p = (:AZBase)-[:AZGlobalAdmin*1..]->(:AZTenant)\nRETURN p\nLIMIT 1000", + "query": "MATCH (u:User)\nWHERE u.hasspn = true\n AND u.enabled = true\n AND NOT u.objectid ENDS WITH '-502'\n AND NOT COALESCE(u.gmsa, false) = true\n AND NOT COALESCE(u.msa, false) = true\nMATCH (u)-[:MemberOf|AdminTo*1..]->(c:Computer)\nWITH DISTINCT u, COUNT(c) AS adminCount\nRETURN u\nORDER BY adminCount DESC\nLIMIT 100", + "revision": 1, + "resources": [ + "https://attack.mitre.org/techniques/T1558/003/" + ], + "acknowledgements": [] + }, + { + "name": "AdminSDHolder protected Accounts and Groups", + "guid": "5ee2f40e-a55c-4140-ab8a-91746ba3752b", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Domain Information", + "description": "Objects whose permissions are set by SDProp to the template AdminSDHolder object as per MS-ADTS 3.1.1.6.1.2 Protected Objects. Does not exclude objects if specified in dSHeuristics dwAdminSDExMask", + "query": "MATCH (n:Base)-[:MemberOf*0..]->(m:Group)\nWHERE (\n n.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Groups\n OR m.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Members of groups\n OR n.objectid =~ \".*-(500|502|516|521)$\" // Direct objects\n)\nRETURN n", + "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a0d0b4fa-2895-4c64-b182-ba64ad0f84b8", + "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Nested groups within Tier Zero / High Value", + "guid": "8e541e75-df1d-423f-b429-4bbf0403a338", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH p=(t:Group)<-[:MemberOf*..]-(s:Group)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT s.objectid ENDS WITH '-512' // Domain Admins\nAND NOT s.objectid ENDS WITH '-519' // Enterprise Admins\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Devices with unsupported operating systems", - "guid": "e3f2b53a-7ce6-4e52-9c74-68b69338288b", + "name": "Entra Users with Entra Admin Roles group delegated eligibility", + "guid": "2e36c81b-25ed-40ba-afec-5f5f6443e095", "prebuilt": true, "platforms": [ "Azure" ], - "category": "Azure Hygiene", + "category": "General", "description": null, - "query": "MATCH (n:AZDevice)\nWHERE n.operatingsystem CONTAINS 'WINDOWS'\nAND n.operatingsystemversion =~ '(10.0.19044|10.0.22000|10.0.19043|10.0.19042|10.0.19041|10.0.18363|10.0.18362|10.0.17763|10.0.17134|10.0.16299|10.0.15063|10.0.14393|10.0.10586|10.0.10240|6.3.9600|6.2.9200|6.1.7601|6.0.6200|5.1.2600|6.0.6003|5.2.3790|5.0.2195).?.*'\nRETURN n\nLIMIT 100", + "query": "MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enrollment rights on published certificate templates with no security extension", - "guid": "0677b70c-4e04-4e89-a6a2-f5764604a6a7", + "name": "Principals with DCSync privileges", + "guid": "6e9beb8a-ad14-43de-bda1-644d174a5906", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.nosecurityextension = true\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(:Base)-[:DCSync|AllExtendedRights|GenericAll]->(:Domain)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enabled built-in guest user accounts", - "guid": "bb0f620d-6a55-4413-ac74-4c82905e8598", + "name": "Collection health of DC Registry Data", + "guid": "3f0fa2f3-fbdf-42c0-9e7d-97e689009161", "prebuilt": false, "platforms": [ "Active Directory" ], + "category": "Domain Information", + "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured DC to potentially a full forest compromise by any principal. DCs returned by this query have not been collected.", + "query": "MATCH p=(:Domain)<-[:DCFor]-(c:Computer)\nWHERE c.strongcertificatebindingenforcementraw IS NULL\n// Exclude inactive DCs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", + "revision": 1, + "resources": [ + "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#dc-registry" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Microsoft Entra Connect accounts with passwords not rotated in over 90 days", + "guid": "97fb1310-d15d-4d63-82a2-8788056250f1", + "prebuilt": false, + "platforms": [ + "Active Directory", + "Azure" + ], "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-501\"\nAND n.enabled = true\nRETURN n", + "description": "Micosoft recommends to change the password of MSOL accounts every 90 days to prevent attackers from allowing use of the high privileges", + "query": "WITH 90 as days_since_change\nMATCH (u:User)\nWHERE u.name STARTS WITH \"MSOL_\"\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u", "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/defender-for-identity/rotate-password-microsoft-entra-connect" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Non-Tier Zero object with excessive control", + "guid": "944cecfe-519b-4318-b226-e8520161b454", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Dangerous Privileges", + "description": "Returns non-Tier Zero principals with >= 1000 direct rights to other principals. This does not include rights from group memberships.", + "query": "MATCH (n:Base)-[r:AD_ATTACK_PATHS]->(m:Base)\nWHERE NOT r:MemberOf\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH n, COLLECT(DISTINCT(m)) AS endNodes\nWHERE SIZE(endNodes) >= 1000\nRETURN n", + "revision": 4, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "KRBTGT accounts with passwords not rotated in over 1 year", - "guid": "1b3ae310-ffa7-4ce5-a37f-6111aef600c8", + "name": "Computers with non-default Primary Group membership", + "guid": "5862dc4e-6f6f-4321-9474-d838968495ed", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:User)\nWHERE (n.objectid ENDS WITH '-502'\nOR n.name STARTS WITH 'AZUREADKERBEROS.'\nOR n.name STARTS WITH 'KRBTGT_AZUREAD@')\nAND n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nRETURN n", + "query": "MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-515\" // Domain Computers\nAND NOT g.objectid ENDS WITH \"-516\" // Domain Controllers\nAND NOT g.objectid ENDS WITH \"-521\" // Read-Only Domain Controllers\nAND r.isprimarygroup = true\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1071,152 +1218,245 @@ ] }, { - "name": "Computers not requiring inbound SMB signing", - "guid": "6b1fcfb6-b010-41a2-9d31-f9872fe994ff", + "name": "Accounts with weak password storage encryption", + "guid": "8bd6fcf2-3f3c-414c-857a-4caf28e49def", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": "Accounts with passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", + "query": "MATCH (n:Base)\nWHERE n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008 release\nRETURN n\nLIMIT 100", + "revision": 2, + "resources": [ + "https://techcommunity.microsoft.com/blog/coreinfrastructureandsecurityblog/decrypting-the-selection-of-supported-kerberos-encryption-types/1628797" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Domains allowing unauthenticated rootDSE searches and binds", + "guid": "ebc79aa4-e816-4be8-93fe-a0b30dbc771d", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": "Checks the fLDAPBlockAnonOps flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{6}[^2].*\"\nRETURN n", + "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "DCs vulnerable to NTLM relay to LDAP attacks", + "guid": "3f87e0b0-fc06-4986-a94c-e08781253dc8", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nRETURN n", + "query": "MATCH p = (dc:Computer)-[:DCFor]->(:Domain)\nWHERE (dc.ldapavailable = True AND dc.ldapsigning = False)\nOR (dc.ldapsavailable = True AND dc.ldapsepa = False)\nOR (dc.ldapavailable = True AND dc.ldapsavailable = True AND dc.ldapsigning = False and dc.ldapsepa = True)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers at risk of resource-based constrained delegation", - "guid": "4dc97cf4-3c03-4fe6-8a8b-4f665c67e1e5", + "name": "All ADCS ESC privilege escalation edges", + "guid": "49db8edc-8421-438f-b97b-23c042959bef", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (n:Computer)<-[:AllowedToAct]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH p=(:Base)-[:ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|GoldenCert|CoerceAndRelayNTLMToADCS]->(:Base)\nRETURN p", + "revision": 1, + "resources": [ + "https://posts.specterops.io/certified-pre-owned-d95910965cd2", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-1-799f3d3b03cf", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac", + "https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53", + "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/#:~:text=Introducing%20the%20CoerceAndRelayNTLMToADCS%20Edge" + ], + "acknowledgements": [ + "Jonas B\u00fclow Knudsen, @Jonas_B_K" + ] + }, + { + "name": "Principals with weak supported Kerberos encryption types", + "guid": "ca329573-2157-41da-ab17-4d122c54b11d", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (u:Base)\nWHERE 'DES-CBC-CRC' IN u.supportedencryptiontypes\nOR 'DES-CBC-MD5' IN u.supportedencryptiontypes\nOR 'RC4-HMAC-MD5' IN u.supportedencryptiontypes\nRETURN u", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Synced Entra Users with Entra Admin Role approval (direct)", + "guid": "1bfe2d75-0a51-4dbe-abc6-178cc0e4476f", + "prebuilt": true, + "platforms": [ + "Active Directory", + "Azure" + ], + "category": "Cross Platform Attack Paths", + "description": null, + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Object name conflict", + "guid": "c561c4f8-ea45-453f-85a2-3fc2e20e7f8c", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": "When two objects are created with the same Relative Distinguished Name (RDN) in the same parent Organizational Unit or container, the conflict is recognized by the system when one of the new objects replicates to another domain controller. When this happens, one of the objects is renamed with 'CNF'", + "query": "MATCH (n:Base)\nWHERE n.distinguishedname CONTAINS 'CNF:'\nRETURN n", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/archive/technet-wiki/15435.active-directory-duplicate-object-name-resolution" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Enrollment rights on published ESC2 certificate templates", - "guid": "ebc77984-1ceb-4ed2-a395-ce1067847941", + "name": "Domain controllers with UPN certificate mapping enabled", + "guid": "799ea3ce-572b-4594-98c4-041aa2ae6176", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(c:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE c.requiresmanagerapproval = false\nAND (c.effectiveekus = [''] OR '2.5.29.37.0' IN c.effectiveekus OR c.effectiveekus IS NULL)\nAND (c.authorizedsignatures = 0 OR c.schemaversion = 1)\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.certificatemappingmethodsraw IN [4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31]\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [ - "https://posts.specterops.io/certified-pre-owned-d95910965cd2", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547" + "https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16", + "https://specterops.io/blog/2024/02/28/adcs-esc14-abuse-technique/" ], - "acknowledgements": [] + "acknowledgements": [ + "Jonas B\u00fclow Knudsen, @Jonas_B_K" + ] }, { - "name": "Users which do not require password to authenticate", - "guid": "23bdc2ad-6739-4b2b-85d3-258e3f424eb2", + "name": "Entra Users synced from On-Prem Users added to Domain Admins group", + "guid": "62722d5f-bd93-4d11-beeb-9be261827e4e", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Active Directory Hygiene", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (u:User)\nWHERE u.passwordnotreqd = true\nRETURN u\nLIMIT 100", + "query": "MATCH p = (:AZUser)-[:SyncedToADUser]->(:User)-[:MemberOf]->(t:Group)\nWHERE t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Large default groups with outbound control", - "guid": "a334f21a-3d7f-448e-b7ea-1465a3127bce", + "name": "Tier Zero computers with passwords older than the default maximum password age", + "guid": "b6d6d0bf-130e-4719-996b-adc29bba36e9", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC5|ADCSESC6a|ADCSESC6b|ADCSESC7|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", - "revision": 1, + "query": "MATCH (n:Computer)\nWHERE n.enabled = true\nAND n.whencreated < (datetime().epochseconds - (60 * 3 * 86400))\nAND n.pwdlastset < (datetime().epochseconds - (60 * 3 * 86400))\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Shortest paths to Azure Subscriptions", - "guid": "4785b305-c101-461c-80fc-3fb3ff67a8ce", + "name": "PKI hierarchy", + "guid": "928acc23-ee4c-40a5-bde7-64c05cc1491d", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Shortest Paths", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription))\nWHERE s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p=()-[:HostsCAService|IssuedSignedBy|EnterpriseCAFor|RootCAFor|TrustedForNTAuth|NTAuthStoreFor*..]->(:Domain)\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Disabled Tier Zero / High Value principals", - "guid": "860d5c2d-84fe-4c85-80de-e0a9badbd0e7", + "name": "Cross-forest trusts with abusable configuration", + "guid": "5cf1f354-80d4-420e-bc4b-424fabc21a56", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Azure Hygiene", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:AZBase)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nRETURN n\nLIMIT 100", + "query": "MATCH p=(n:Domain)-[:CrossForestTrust|SpoofSIDHistory|AbuseTGTDelegation]-(m:Domain)\nWHERE (n)-[:SpoofSIDHistory|AbuseTGTDelegation]-(m)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "All service principals with Microsoft Graph privilege to grant arbitrary App Roles", - "guid": "e6d6b5da-89da-4514-a409-2d6e368397da", + "name": "CA Administrators and CA Managers (ESC7)", + "guid": "77a708b8-962e-4c3d-ad70-e994126aaeba", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Microsoft Graph", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p=(:AZServicePrincipal)-[:AZMGGrantAppRoles]->(:AZTenant)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Accounts with weak password storage encryption", - "guid": "8bd6fcf2-3f3c-414c-857a-4caf28e49def", - "prebuilt": true, + "name": "Domains exempting privileged groups from AdminSDHolder protections", + "guid": "79f8d8f9-8291-4bf7-a13a-15989018075f", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Accounts with passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", - "query": "MATCH (n:Base)\nWHERE n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008 release\nRETURN n\nLIMIT 100", - "revision": 2, + "description": "Checks the dwAdminSDExMask flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{15}[^0].*\"\nRETURN n", + "revision": 1, "resources": [ - "https://techcommunity.microsoft.com/blog/coreinfrastructureandsecurityblog/decrypting-the-selection-of-supported-kerberos-encryption-types/1628797" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Non-Tier Zero accounts with SID History of Tier Zero accounts", - "guid": "59744dfe-9411-4daf-b342-1203dc62acd4", + "name": "Tier Zero accounts not members of Denied RODC Password Replication Group", + "guid": "e9613406-e346-410b-a033-690a6cf0c708", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND (n:User or n:Computer)\nWITH n\nOPTIONAL MATCH (n)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH '-519'\nWITH n, m\nWHERE m IS NULL\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -1224,15 +1464,29 @@ ] }, { - "name": "Accounts with SID History to a non-existent domain", - "guid": "2710401a-c4c2-4d2c-9edb-d7625045f2e8", + "name": "Shortest paths to Domain Admins from Kerberoastable users", + "guid": "bd163361-1e05-47c7-908b-962aef251535", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Shortest Paths", + "description": null, + "query": "MATCH p=shortestPath((s:User)-[:AD_ATTACK_PATHS*1..]->(t:Group))\nWHERE s.hasspn=true\nAND s.enabled = true\nAND NOT s.objectid ENDS WITH '-502'\nAND NOT COALESCE(s.gmsa, false) = true\nAND NOT COALESCE(s.msa, false) = true\nAND t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Kerberos-enabled service account member of built-in Admins groups", + "guid": "42a856fc-257a-4142-9592-ca95fd49e579", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (d:Domain)\nWITH collect(d.objectid) AS domainSIDs\nMATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE NOT n.domainsid IN domainSIDs\nRETURN p", + "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(g:Group)\nWHERE (\n g.objectid ENDS WITH '-512' // Domain Admins\n OR g.objectid ENDS WITH '-519' // Enterprise Admins\n OR g.objectid ENDS WITH '-518' // Schema Admins\n)\nAND n.hasspn = true\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1256,130 +1510,77 @@ ] }, { - "name": "Circular AZ group memberships", - "guid": "b005669c-d8af-47ae-a0f1-4f36cd5334ab", + "name": "Enabled computers inactive for 180 days - MSSQL Failover Cluster", + "guid": "d263e621-7f1b-4efb-ad25-098fc7d4fb72", "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Azure Hygiene", - "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", - "query": "MATCH p=(x:AZGroup)-[:AZMemberOf*2..]->(y:AZGroup)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", + "category": "Active Directory Hygiene", + "description": null, + "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND ANY(type IN n.serviceprincipalnames WHERE \n toLower(type) CONTAINS 'mssqlservercluster' OR \n toLower(type) CONTAINS 'mssqlserverclustermgmtapi' OR \n toLower(type) CONTAINS 'msclustervirtualserver')\nRETURN n\nLIMIT 1000", "revision": 1, "resources": [ - "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + "https://learn.microsoft.com/en-us/troubleshoot/windows-server/high-availability/troubleshoot-issues-accounts-used-failover-clusters#troubleshoot-password-issues-with-the-cluster-name-account" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Shortest paths from Domain Users to Tier Zero / High Value targets", - "guid": "469dc0f3-71b8-41b0-a03b-b4af7874665d", - "prebuilt": true, - "platforms": [ - "Active Directory" - ], - "category": "Shortest Paths", - "description": null, - "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] - }, - { - "name": "AdminSDHolder protected Accounts and Groups", - "guid": "5ee2f40e-a55c-4140-ab8a-91746ba3752b", + "name": "Large default groups with outbound control", + "guid": "a334f21a-3d7f-448e-b7ea-1465a3127bce", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Objects whose permissions are set by SDProp to the template AdminSDHolder object as per MS-ADTS 3.1.1.6.1.2 Protected Objects. Does not exclude objects if specified in dSHeuristics dwAdminSDExMask", - "query": "MATCH (n:Base)-[:MemberOf*0..]->(m:Group)\nWHERE (\n n.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Groups\n OR m.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Members of groups\n OR n.objectid =~ \".*-(500|502|516|521)$\" // Direct objects\n)\nRETURN n", + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(n:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC5|ADCSESC6a|ADCSESC6b|ADCSESC7|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a0d0b4fa-2895-4c64-b182-ba64ad0f84b8", - "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Shortest paths from Entra Users to Tier Zero / High Value targets", - "guid": "58089b28-54e0-4fd2-bf66-3db480b00e2f", + "name": "All Global Administrators", + "guid": "94d7d765-6837-4eb8-aa33-e1c9ef262cdc", "prebuilt": true, "platforms": [ "Azure" ], - "category": "Shortest Paths", + "category": "General", "description": null, - "query": "MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE (t:AZBase) AND t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(:AZBase)-[:AZHasRole*1..]->(t:AZRole)\nWHERE t.name =~ '(?i)Global Administrator.*'\nRETURN p\nLIMIT 1000", "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "Large default group added to computer-local group", - "guid": "dde133d2-b4d2-4de9-a656-905f3bf066f3", - "prebuilt": false, + "name": "Computers with unsupported operating systems", + "guid": "d06d3b14-0318-4fa9-9639-4b79ccaf3c2c", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOfLocalGroup]->(m:ADLocalGroup)-[:LocalToComputer]->(:Computer)\nWHERE n.objectid =~ \".*-(S-1-5-11|S-1-1-0|S-1-5-32-545|S-1-5-7|-513|-515)$\" // Authenticated Users, Everyone, Users, Anonymous, Domain Users, Domain Computers\nAND NOT m.objectid =~ \".*-(545|574|554)$\" // Users, Certificate Service DCOM Access, Pre-Windows 2000 Compatible Access\nRETURN p", - "revision": 1, - "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Non-Tier Zero principals with BadSuccessor rights (no prerequisites check)", - "guid": "2b9fb71e-73ad-4061-a2df-40c7132b044d", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Dangerous Privileges", - "description": "Finds non-Tier Zero principals with BadSuccessor rights with no prerequisites check (DC2025 & KDC key).", - "query": "// Find OU control\nMATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p LIMIT 1000", + "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nRETURN c\nLIMIT 100", "revision": 1, - "resources": [ - "https://bsky.app/profile/specterops.io/post/3lpua65qeu22l" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Tier Zero computers not owned by Tier Zero", - "guid": "99d29ded-223a-442b-a0e0-f8b5694c6441", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Dangerous Privileges", - "description": null, - "query": "MATCH p=(n:Base)-[:Owns]->(:Computer)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", - "revision": 2, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Principals with weak supported Kerberos encryption types", - "guid": "ca329573-2157-41da-ab17-4d122c54b11d", + "name": "ESC8-vulnerable Enterprise CAs", + "guid": "60881923-296c-4702-adf7-a4f059dc9bb8", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (u:Base)\nWHERE 'DES-CBC-CRC' IN u.supportedencryptiontypes\nOR 'DES-CBC-MD5' IN u.supportedencryptiontypes\nOR 'RC4-HMAC-MD5' IN u.supportedencryptiontypes\nRETURN u", + "query": "MATCH (n:EnterpriseCA)\nWHERE n.hasvulnerableendpoint=true\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [] @@ -1403,15 +1604,34 @@ ] }, { - "name": "Accounts with clear-text password attributes", - "guid": "e303498f-e3d4-489d-8a34-b68e187bc4e7", + "name": "Enrollment rights on published ESC15 certificate templates", + "guid": "78d59fe1-e1a0-4813-adc9-c3c96ac08b66", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Certificate Services", + "description": "Enrollment rights on certificate templates that meet the requirements for the ADCS ESC15 (EKUwu) attack.", + "query": "MATCH p=(:Base)-[:Enroll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)-[:TrustedForNTAuth]->(:NTAuthStore)-[:NTAuthStoreFor]->(:Domain)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = False\nAND ct.requiresmanagerapproval = False\nAND ct.schemaversion = 1\nRETURN p", + "revision": 1, + "resources": [ + "https://x.com/SpecterOps/status/1844800558151901639", + "https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2024-49019" + ], + "acknowledgements": [ + "Jonas B\u00fclow Knudsen, @Jonas_B_K" + ] + }, + { + "name": "Users with non-expiring passwords", + "guid": "212c2a98-53d9-4dfa-b177-42c601452dd1", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE n.userpassword IS NOT NULL\nOR n.unixpassword IS NOT NULL\nOR n.unicodepwd IS NOT NULL\nOR n.msSFU30Password IS NOT NULL\nRETURN n", + "query": "MATCH (u:User)\nWHERE u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [ @@ -1419,33 +1639,31 @@ ] }, { - "name": "Non-Tier Zero account with 'Admin Count' flag", - "guid": "e7f703b3-5dba-4aef-8346-4d589be2c828", + "name": "Tier Zero computers not requiring inbound SMB signing", + "guid": "13485477-f026-4b1f-906d-4f2e37364ba4", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Users who were a member of one of AD's built-in administrative groups but are not currently Tier Zero.", - "query": "MATCH (n:User)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.admincount = true\nRETURN n", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/windows/win32/adschema/a-admincount" - ], + "category": "NTLM Relay Attacks", + "description": null, + "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "revision": 1, + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Non-default delegation on MicrosoftDNS container", - "guid": "008792c0-4458-46a1-a10d-50cdaf95af1e", + "name": "Users with non-default Primary Group membership", + "guid": "93890f88-df2c-4167-a945-a53961d08d00", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Base)-[r]->(m:Container)\nWHERE m.distinguishedname STARTS WITH \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\"\nAND NOT n.name STARTS WITH \"DNSADMINS@\"\nAND NOT n.objectid =~ \"-(512|544|519|9)$\"\nAND r.isacl\nRETURN p", + "query": "MATCH p=(n:User)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-513\" // Domain Users\nAND r.isprimarygroup = true\nAND NOT n.objectid ENDS WITH \"-501\" // Guests account, as it has primaryGroup to Guests\nAND (n.gmsa IS NULL OR n.gmsa = false) // Not gMSA, as it has primaryGroup to Domain Computers\nAND (n.msa IS NULL OR n.msa = false) // Not MSA, as it has primaryGroup to Domain Computers\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1453,91 +1671,133 @@ ] }, { - "name": "Domain controllers with weak certificate binding enabled", - "guid": "a2444d99-10b5-412d-8fea-4b063cfddd2c", + "name": "Shortest paths from Azure Applications to Tier Zero / High Value targets", + "guid": "60ff7c58-a98e-4bc1-9e32-8378d2db0c43", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "Shortest Paths", + "description": null, + "query": "MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Compromising permissions on ADCS nodes (ESC5)", + "guid": "396c7b67-fb5d-4c04-bb13-8007f0dfc9b1", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.strongcertificatebindingenforcementraw = 0 OR s.strongcertificatebindingenforcementraw = 1\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (n:Base)-[:Owns|WriteOwner|WriteDacl|GenericAll|GenericWrite]->(m:Base)\nWHERE m.distinguishedname CONTAINS \"PUBLIC KEY SERVICES\"\nAND NOT n.objectid ENDS WITH \"-512\" // Domain Admins\nAND NOT n.objectid ENDS WITH \"-519\" // Enterprise Admins\nAND NOT n.objectid ENDS WITH \"-544\" // Administrators\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "DCs vulnerable to NTLM relay to LDAP attacks", - "guid": "3f87e0b0-fc06-4986-a94c-e08781253dc8", + "name": "Shortest paths from Entra Users to Tier Zero / High Value targets", + "guid": "58089b28-54e0-4fd2-bf66-3db480b00e2f", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "Shortest Paths", + "description": null, + "query": "MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE (t:AZBase) AND t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Enrollment rights on published certificate templates", + "guid": "a4ae2e54-aad3-4bfd-a12d-90cb8a9cbc86", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (dc:Computer)-[:DCFor]->(:Domain)\nWHERE (dc.ldapavailable = True AND dc.ldapsigning = False)\nOR (dc.ldapsavailable = True AND dc.ldapsepa = False)\nOR (dc.ldapavailable = True AND dc.ldapsavailable = True AND dc.ldapsigning = False and dc.ldapsepa = True)\nRETURN p", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers at risk of constrained delegation", - "guid": "8641e593-f2f2-48ba-bd45-fbc86e9f632a", + "name": "Non-Tier Zero principals with control of AdminSDHolder", + "guid": "4c1e0137-5b7f-48d8-bd09-9db7674bca61", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (n:Computer)<-[:AllowedToDelegate]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH p=(n:Group)-[r:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteOwnerLimitedRights|OwnsLimitedRights]->(m:Container)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND m.name STARTS WITH \"ADMINSDHOLDER@\"\nRETURN p", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#adminsdholder" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Non-Tier Zero principals with BadSuccessor rights (with prerequisites check)", - "guid": "74daaebe-6040-4f7a-9c9a-416faf73dcc3", + "name": "Accounts with clear-text password attributes", + "guid": "e303498f-e3d4-489d-8a34-b68e187bc4e7", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": "Finds non-Tier Zero principals with BadSuccessor rights after checking prerequisites check (DC2025 & KDC key).", - "query": "// Find 2025 DCs\nMATCH (dc:Computer)\nWHERE dc.isdc = true AND dc.operatingsystem CONTAINS '2025'\n// Find gMSAs\nMATCH (m:User)\nWHERE m.gmsa = true\n// Find OU control\nMATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)\n// Confirm domain has a 2025 DC\nWHERE ou.domain = dc.domain\n// Confirm domain KDC key\nAND ou.domain = m.domain\n// Exclude Tier Zero\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p LIMIT 1000", + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:Base)\nWHERE n.userpassword IS NOT NULL\nOR n.unixpassword IS NOT NULL\nOR n.unicodepwd IS NOT NULL\nOR n.msSFU30Password IS NOT NULL\nRETURN n", "revision": 1, - "resources": [ - "https://bsky.app/profile/specterops.io/post/3lpua65qeu22l" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Servers where Domain Users can RDP", - "guid": "b9a330ae-1d89-44d4-8f74-9ca18e93eb92", + "name": "Shortest paths to Domain Admins", + "guid": "f40cb34b-5ec7-44bc-9aa8-a200a4a41f22", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Shortest Paths", "description": null, - "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p=shortestPath((t:Group)<-[:AD_ATTACK_PATHS*1..]-(s:Base))\nWHERE t.objectid ENDS WITH '-512' AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers not requiring inbound SMB signing", - "guid": "13485477-f026-4b1f-906d-4f2e37364ba4", + "name": "Shortest paths to Azure Subscriptions", + "guid": "4785b305-c101-461c-80fc-3fb3ff67a8ce", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "Shortest Paths", + "description": null, + "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription))\nWHERE s<>t\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Enabled users inactive for 180 days", + "guid": "71972f3c-b32d-4023-a841-5cc8cc1c1867", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "query": "WITH 180 as inactive_days\nMATCH (n:User)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -1545,79 +1805,73 @@ ] }, { - "name": "Paths from Domain Users to Tier Zero / High Value targets", - "guid": "977bec40-565c-40b8-90c8-e3e122c291cd", - "prebuilt": true, + "name": "Tier Zero users not member of Protected Users", + "guid": "543eb01d-9fa3-4b8f-a936-b46bbfdaa2ae", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH (m:User)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nOPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)\nWHERE g.objectid ENDS WITH '-525'\nWITH m, COLLECT(n) AS matchingNs\nWHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)\nRETURN m", + "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated)", - "guid": "609d648f-7fb8-42d3-ad99-626f9ce1f121", + "name": "Location of AdminSDHolder Protected objects", + "guid": "3408ccaf-1f42-4c10-b09a-e986661f84d7", "prebuilt": true, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", + "category": "Domain Information", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (n:Base)<-[:Contains*1..]-(:Domain)\nWHERE n.adminsdholderprotected = True\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Kerberoastable members of Tier Zero / High Value groups", - "guid": "e6da7800-ae06-41cb-80a6-d5421ab2143a", + "name": "Computers with the outgoing NTLM setting set to Deny all", + "guid": "a9ddca74-feeb-4dbf-8b0f-de08b3cfa8a6", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Kerberos Interaction", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (u:User)\nWHERE (u:Tag_Tier_Zero) AND u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true \nRETURN u\nLIMIT 100", + "query": "MATCH (c:Computer)\nWHERE c.restrictoutboundntlm = True\nRETURN c LIMIT 1000", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/003/" - ], + "resources": [], "acknowledgements": [] }, { - "name": "Domain controllers with UPN certificate mapping enabled", - "guid": "799ea3ce-572b-4594-98c4-041aa2ae6176", + "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6)", + "guid": "ab14e9dc-996c-4737-878c-583c19cdbf5a", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.certificatemappingmethodsraw IN [4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31]\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16", - "https://specterops.io/blog/2024/02/28/adcs-esc14-abuse-technique/" - ], - "acknowledgements": [ - "Jonas B\u00fclow Knudsen, @Jonas_B_K" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Users with non-expiring passwords", - "guid": "212c2a98-53d9-4dfa-b177-42c601452dd1", + "name": "Locations of Owned objects", + "guid": "c88bfab4-3da0-4b36-b71d-7b324ebd2243", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "MATCH (u:User)\nWHERE u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", + "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -1625,95 +1879,93 @@ ] }, { - "name": "Object name conflict", - "guid": "c561c4f8-ea45-453f-85a2-3fc2e20e7f8c", - "prebuilt": false, + "name": "Users with passwords not rotated in over 1 year", + "guid": "be70d1bd-b7eb-40b0-971c-eefc50eca032", + "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "When two objects are created with the same Relative Distinguished Name (RDN) in the same parent Organizational Unit or container, the conflict is recognized by the system when one of the new objects replicates to another domain controller. When this happens, one of the objects is renamed with 'CNF'", - "query": "MATCH (n:Base)\nWHERE n.distinguishedname CONTAINS 'CNF:'\nRETURN n", + "description": null, + "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/archive/technet-wiki/15435.active-directory-duplicate-object-name-resolution" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Enrollment rights on published ESC1 certificate templates", - "guid": "2af855bc-f48f-4b22-9839-627d8231e425", - "prebuilt": true, + "name": "Tier Zero users with passwords not rotated in over 1 year", + "guid": "5e0d69b1-37d1-43ae-ac5d-f297f312fab5", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = True\nAND ct.requiresmanagerapproval = False\nAND (ct.authorizedsignatures = 0 OR ct.schemaversion = 1)\nRETURN p\nLIMIT 1000", + "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "All members of high privileged roles", - "guid": "3df24d92-dd12-4125-811b-e696b098f60e", + "name": "Entra Users with Entra Admin Role direct eligibility", + "guid": "b87899ce-3a51-401a-ae39-ef271b566e3d", "prebuilt": true, "platforms": [ "Azure" ], "category": "General", "description": null, - "query": "MATCH p=(t:AZRole)<-[:AZHasRole|AZMemberOf*1..2]-(:AZBase)\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator'\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:AZUser)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Potential GPO 'Apply' misconfiguration", - "guid": "f5f2455e-afdc-4708-9a34-98f539ce52d8", - "prebuilt": true, + "name": "Trace ACE inheritance", + "guid": "8c5454df-3ae8-412c-b271-3c4c55df7141", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": "In Active Directory, GPO's are applied to objects in the Group Policy Management Console by ticking \"Allow - Apply group policy\", but administrators can mistakenly tick \"Allow - Write\" or \"Allow - Full Control\" resulting in a misconfigured GPO that allows a principal to compromise other principals the GPO also applies to. Results are potential risks and must be audited for for correctness.", - "query": "MATCH p=(n:Base)-[:GenericAll|GenericWrite]->(g:GPO)\n\n// Exclude Enterprise Admins and Domain Admins\nWHERE NOT n.objectid =~ \"-(519|512)$\"\n\n// Exclude unresolved SIDs\nAND NOT (n.distinguishedname IS NULL)\n\n// Asset description may reveal if it's a delegation group (false-positive) or a filter group (true-positive)\n//AND n.description is not null\n//AND n.description =~ \"(?i)apply\"\n\nRETURN p\nLIMIT 1000", - "revision": 2, + "category": "Domain Information", + "description": "When BloodHound shows that an inherited ACE applies to an object it does not show the source/where it is inherited from from (OU, Container, Domain root) - the source is where it should be remediated. This query can sometimes find the source of an inherited ACE, but only works if the ACE is set to also apply to the source itself.", + "query": "// Replace INSERT_OBJECT_ID with the affected principal\n// Replace 'GenericAll' with the specific edge you're tracing\nWITH \"INSERT_OBJECT_ID\" as OID\nMATCH p=()-[:GenericAll {isacl:true,isinherited:false}]->()-[:Contains*1..]->(:Base{objectid:OID})\nWHERE NONE(ou in NODES(p) WHERE ou:OU AND ou.isaclprotected IS NOT NULL)\nRETURN p", + "revision": 1, "resources": [], "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" + "Walter.Legowski, @SadProcessor" ] }, { - "name": "Principal with SPN keyword", - "guid": "38a9c4c9-3d70-453f-a017-cbfd35ed9917", + "name": "Foreign Service Principals With any Abusable MS Graph App Role Assignment", + "guid": "d7a180c8-5624-4fc1-a407-deeb2ad3054c", "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Kerberos Interaction", - "description": "Finds service accounts used with a specific Kerberos-enabled service or all service accounts running on a Kerberos-enabled service on a specific server.", - "query": "// Replace keyword with a service type or server name (not FQDN)\nWITH \"KEYWORD\" as SPNKeyword\nMATCH (n:User)\nWHERE ANY(keyword IN n.serviceprincipalnames WHERE toUpper(keyword) CONTAINS toUpper(SPNKeyword))\nRETURN n", + "category": "Dangerous Privileges", + "description": "MS Graph app role assignments provide significant power within an Entra ID tenant, similar to an Admin role.", + "query": "MATCH p = (sp1:AZServicePrincipal)-[r:AZMGGroupMember_ReadWrite_All|AZMGServicePrincipalEndpoint_ReadWrite_All|AZMGAppRoleAssignment_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory]->(sp2:AZServicePrincipal)\nWHERE toUpper(sp1.appownerorganizationid) <> toUpper(sp1.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp1.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [ - "https://adsecurity.org/?page_id=183" + "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" ], "acknowledgements": [ - "Ryan, @haus3c" + "Stephen Hinck" ] }, { - "name": "All Schema Admins", - "guid": "76d8e61d-7a86-40ff-8a85-fd37f1e2563f", + "name": "Domains with functional level not the latest version", + "guid": "3da9d14a-f1cb-4df7-b3da-8d73ff5c401b", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE (n:User OR n:Computer)\nAND m.objectid ENDS WITH \"-518\" // Schema Admins\nRETURN p", + "query": "MATCH (n:Domain)\nWHERE toString(n.functionallevel) IN ['2008','2003','2003 Interim','2000 Mixed/Native']\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -1721,88 +1973,95 @@ ] }, { - "name": "Members of Allowed RODC Password Replication Group", - "guid": "19fc5acd-e30a-4038-a5b5-2e0494f93373", + "name": "KRBTGT accounts with passwords not rotated in over 1 year", + "guid": "1b3ae310-ffa7-4ce5-a37f-6111aef600c8", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(:Base)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH \"-571\"\nRETURN p", - "revision": 2, + "query": "MATCH (n:User)\nWHERE (n.objectid ENDS WITH '-502'\nOR n.name STARTS WITH 'AZUREADKERBEROS.'\nOR n.name STARTS WITH 'KRBTGT_AZUREAD@')\nAND n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nRETURN n", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Tier Zero / High Value enabled users not requiring smart card authentication", - "guid": "867f9f17-c149-4c4b-ad84-9a807622ff8c", - "prebuilt": true, + "name": "Tier Zero computers at risk of resource-based constrained delegation", + "guid": "4dc97cf4-3c03-4fe6-8a8b-4f665c67e1e5", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.enabled = true\nAND u.smartcardrequired = false\nAND NOT u.name STARTS WITH 'MSOL_' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'PROVAGENTGMSA' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'ADSYNCMSA_' // Removes false positive, Entra sync\nRETURN u", + "query": "MATCH p = (n:Computer)<-[:AllowedToAct]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Computers with the WebClient running", - "guid": "51107ad1-f0bc-43d3-a561-5cee471ca196", + "name": "Domains with smart card accounts where smart account passwords do not expire", + "guid": "97e05e67-5961-4aba-a8e7-fe5f92334035", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nRETURN c LIMIT 1000", + "query": "MATCH (s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN s", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "On-Prem Users synced to Entra Users with Entra Group Membership", - "guid": "edb575df-2048-4ef0-a0e4-168544a496e9", - "prebuilt": true, + "name": "Domains allowing unauthenticated domain enumeration", + "guid": "41a08d76-f8a5-4296-ad19-464c4c5c69fe", + "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nOR n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Computers where Domain Users can read LAPS passwords", - "guid": "aa4bfa95-e7b9-4d56-8f35-f34f04d7b6f4", - "prebuilt": true, + "name": "Computers with passwords older than the default maximum password age", + "guid": "185c5010-8d4f-4f9b-b24e-831707dddfca", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": null, - "query": "MATCH p=(s:Group)-[:AllExtendedRights|ReadLAPSPassword]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", + "category": "Active Directory Hygiene", + "description": "Machine account passwords are regularly changed for security purposes. Starting with Windows 2000-based computers, the machine account password automatically changes every 30 days.", + "query": "WITH 60 as rotation_period\nMATCH (n:Computer)\nWHERE n.pwdlastset < (datetime().epochseconds - (rotation_period * 86400)) // password not rotated\nAND n.enabled = true // enabled computers\nAND n.whencreated < (datetime().epochseconds - (rotation_period * 86400)) // exclude recently created computers\nAND n.lastlogontimestamp > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Replicated value)\nAND n.lastlogon > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Non-replicated value)\nRETURN n", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/disable-machine-account-password" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Domains without Protected Users group", - "guid": "8c3e0811-a31b-45b4-a29d-1dce80fa2c5f", + "name": "Sessions across trusts", + "guid": "aea7ac64-1f51-407b-b0ee-19fd30075794", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Domain Information", - "description": null, - "query": "MATCH (n:Domain)\nWHERE n.collected = true\nOPTIONAL MATCH (m:Group)\nWHERE m.name ENDS WITH n.name\nAND m.objectid ENDS WITH '-525'\nWITH n, m\nWHERE m IS NULL\nRETURN n", + "description": "Users logging on across a trust, the users originate from trusted domains.", + "query": "MATCH p=(trustedDomainPrincipal:Computer)-[r:HasSession]->(trustingDomainPrincipal:User)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -1810,97 +2069,128 @@ ] }, { - "name": "Shortest paths from Owned objects to Tier Zero", - "guid": "dfaa8e8f-2c79-4e92-a291-b1347f6e83b0", + "name": "AdminSDHolder to protected objects relationship", + "guid": "c751f95c-8bb0-4be4-b027-84f5709c91d2", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", + "category": "Active Directory Hygiene", "description": null, - "query": "// MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE\nMATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p=(n)-[:ProtectAdminGroups]->(m)\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "All Domain Admins", - "guid": "0596dba7-9180-49a0-aa54-00243240037c", + "name": "Disabled Tier Zero / High Value principals", + "guid": "d65a801f-d3ef-4b7e-8030-99ebfd6dad12", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (t:Group)<-[:MemberOf*1..]-(a)\nWHERE (a:User or a:Computer) and t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nAND NOT n.objectid ENDS WITH '-502' // Removes false positive, KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Domains allowing unauthenticated rootDSE searches and binds", - "guid": "ebc79aa4-e816-4be8-93fe-a0b30dbc771d", + "name": "Domains with a minimum default password policy length less than 15 characters", + "guid": "7d258d2d-a43d-4a90-85d7-71c946ae5fd7", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Checks the fLDAPBlockAnonOps flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{6}[^2].*\"\nRETURN n", + "description": null, + "query": "MATCH (n:Domain)\nWHERE n.minpwdlength < 15\nRETURN n", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + "https://pages.nist.gov/800-63-3/sp800-63b.html" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Map Azure Management structure", - "guid": "c1bb109e-e6a4-4c91-864f-f78e1e42615e", + "name": "Domains allowing unauthenticated NSPI RPC binds", + "guid": "a950fdab-5934-4c69-a88b-e2e0e3da9d52", "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Kerberos Interaction", - "description": "Maps the structure of Azure Management", - "query": "MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup)\nRETURN p\nLIMIT 1000", + "category": "Active Directory Hygiene", + "description": "Checks the fAllowAnonNSPI flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{7}[^0].*\"\nRETURN n", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/azure/governance/management-groups/overview" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Foreign Service Principals With an EntraID Admin Role", - "guid": "b6235820-4e0d-4dfa-af5b-729b5644feb5", + "name": "Accounts with smart card required in domains where smart account passwords do not expire", + "guid": "bba7985e-f32a-4c62-b1b0-0365bf1455e6", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH p=(s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN p", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Overprivileged Microsoft Entra Connect accounts", + "guid": "9e6e75b4-9ecc-45d4-a39b-b6427b813f0a", "prebuilt": false, "platforms": [ + "Active Directory", "Azure" ], - "category": "Dangerous Privileges", - "description": "Entra ID admin roles grant significant control over a tenant environment, even if the role is not a default Tier Zero / High Value role", - "query": "MATCH p = (sp:AZServicePrincipal)-[:AZHasRole]->(r:AZRole)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(sp.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", + "category": "Active Directory Hygiene", + "description": "Legacy MSOL accounts were by default deployed with Domain Admins or Enterprise Admins membership.", + "query": "MATCH p=(n:User)-[:MemberOf*1..]->(g:Group)\nWHERE n.name STARTS WITH \"MSOL_\"\nAND (g.objectid ENDS WITH \"-512\" // Domain Admins\nOR g.objectid ENDS WITH \"-519\") // Entterprise Admins\nRETURN p", "revision": 1, "resources": [ - "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" + "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/reference-connect-accounts-permissions" ], "acknowledgements": [ - "Stephen Hinck" + "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "All DNSAdmins", - "guid": "183fb320-f3ae-4ab3-a090-3f9a7db692e1", + "name": "Users with logon scripts stored in a trusted domain", + "guid": "8d94d3f3-3d53-4939-a206-3c0a4dd3f646", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:User)\nWHERE n.logonscript IS NOT NULL\nMATCH (d:Domain)<-[:SameForestTrust|CrossForestTrust]-(:Domain)-[:Contains*1..]->(n)\nWITH n,last(split(d.name, '@')) AS domain\nWHERE toUpper(n.logonscript) STARTS WITH (\"\\\\\\\\\" + domain + \"\\\\\")\nRETURN n", + "revision": 2, + "resources": [], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Domains without Protected Users group", + "guid": "8c3e0811-a31b-45b4-a29d-1dce80fa2c5f", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Domain Information", "description": null, - "query": "MATCH p=(n:Base)-[:MemberOf]->(g:Group) \nWHERE n.name STARTS WITH \"DNSADMINS@\"\nRETURN p", + "query": "MATCH (n:Domain)\nWHERE n.collected = true\nOPTIONAL MATCH (m:Group)\nWHERE m.name ENDS WITH n.name\nAND m.objectid ENDS WITH '-525'\nWITH n, m\nWHERE m IS NULL\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -1908,25 +2198,24 @@ ] }, { - "name": "Domains where any user can join a computer to the domain", - "guid": "421921fa-bc0f-4659-9680-b7481adcb132", + "name": "AS-REP Roastable users (DontReqPreAuth)", + "guid": "2570e359-dec1-419d-b0dc-a204bd64ee42", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Kerberos Interaction", "description": null, - "query": "MATCH (n:Domain)\nWHERE n.machineaccountquota > 0\nRETURN n", + "query": "MATCH (u:User)\nWHERE u.dontreqpreauth = true\nAND u.enabled = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/default-workstation-numbers-join-domain", - "https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/add-workstations-to-domain" + "https://attack.mitre.org/techniques/T1558/004/" ], "acknowledgements": [] }, { - "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (direct)", - "guid": "de717635-d31f-4fbd-930b-b4dac0f22118", + "name": "On-Prem Users synced to Entra Users with Azure RM Roles (direct)", + "guid": "8569113b-e42e-49b0-a968-53bcf0ccd970", "prebuilt": true, "platforms": [ "Active Directory", @@ -1934,174 +2223,141 @@ ], "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers with passwords older than the default maximum password age", - "guid": "b6d6d0bf-130e-4719-996b-adc29bba36e9", + "name": "Foreign Service Principals With an EntraID Admin Role", + "guid": "b6235820-4e0d-4dfa-af5b-729b5644feb5", "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" + ], + "category": "Dangerous Privileges", + "description": "Entra ID admin roles grant significant control over a tenant environment, even if the role is not a default Tier Zero / High Value role", + "query": "MATCH p = (sp:AZServicePrincipal)-[:AZHasRole]->(r:AZRole)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(sp.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", + "revision": 1, + "resources": [ + "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" ], - "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (n:Computer)\nWHERE n.enabled = true\nAND n.whencreated < (datetime().epochseconds - (60 * 3 * 86400))\nAND n.pwdlastset < (datetime().epochseconds - (60 * 3 * 86400))\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", - "revision": 2, - "resources": [], "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" + "Stephen Hinck" ] }, { - "name": "Shortest paths from Owned objects", - "guid": "e370a01d-c129-4f19-b88d-9479cbe00028", - "prebuilt": true, - "platforms": [ - "Active Directory" - ], - "category": "Shortest Paths", - "description": null, - "query": "MATCH p=shortestPath((s:Base)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE (s:Tag_Owned)\nAND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Shortest paths to Domain Admins from Kerberoastable users", - "guid": "bd163361-1e05-47c7-908b-962aef251535", - "prebuilt": true, - "platforms": [ - "Active Directory" - ], - "category": "Shortest Paths", - "description": null, - "query": "MATCH p=shortestPath((s:User)-[:AD_ATTACK_PATHS*1..]->(t:Group))\nWHERE s.hasspn=true\nAND s.enabled = true\nAND NOT s.objectid ENDS WITH '-502'\nAND NOT COALESCE(s.gmsa, false) = true\nAND NOT COALESCE(s.msa, false) = true\nAND t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Usage of built-in domain Administrator account", - "guid": "35b1206f-871b-44aa-a601-c5258060dfcf", + "name": "Direct Principal Rights Assignment", + "guid": "1d9c6ae3-38fc-4089-b5ad-fc3be0fa8eec", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Usage of Active Directory's built-in Administrator account is a sign that the account is not only used for break-glass purposes.", - "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-500\"\nAND (\n n.lastlogontimestamp > (datetime().epochseconds - (60 * 86400)) OR\n n.lastlogon > (datetime().epochseconds - (60 * 86400))\n)\nAND NOT n.whencreated > (datetime().epochseconds - (60 * 86400))\nRETURN n", + "description": "This query identifies rights assigned directly to users or computers instead of groups. Active Directory best practice requires granting rights to groups, then adding users as group members. This role-based access control (RBAC) approach ensures permissions are easily auditable and manageable. Results include inherited rights, which must be modified at the parent container level.", + "query": "MATCH p=(n:Base)-[r:GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE (n:User OR n:Computer) \nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [], + "resources": [ + "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Enrollment rights on published ESC15 certificate templates", - "guid": "78d59fe1-e1a0-4813-adc9-c3c96ac08b66", - "prebuilt": false, + "name": "Public Key Services container", + "guid": "07e94492-71aa-4665-ab8c-e7aec25906cd", + "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", - "description": "Enrollment rights on certificate templates that meet the requirements for the ADCS ESC15 (EKUwu) attack.", - "query": "MATCH p=(:Base)-[:Enroll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)-[:TrustedForNTAuth]->(:NTAuthStore)-[:NTAuthStoreFor]->(:Domain)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = False\nAND ct.requiresmanagerapproval = False\nAND ct.schemaversion = 1\nRETURN p", + "description": null, + "query": "MATCH p = (c:Container)-[:Contains*..]->(:Base)\nWHERE c.distinguishedname starts with 'CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC='\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://x.com/SpecterOps/status/1844800558151901639", - "https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2024-49019" - ], - "acknowledgements": [ - "Jonas B\u00fclow Knudsen, @Jonas_B_K" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Tier Zero / High Value external Entra ID users", - "guid": "20e07417-d286-4dca-a962-568f2b262f65", + "name": "Enabled Tier Zero / High Value principals inactive for 60 days", + "guid": "72550bcb-3c4f-463d-8973-91a49163dc5a", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Azure Hygiene", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:AZUser)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.name CONTAINS '#EXT#@'\nRETURN n\nLIMIT 100", + "query": "WITH 60 as inactive_days\nMATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "ACEs across trusts", - "guid": "c902d3b4-1a75-4335-acd7-28246dab746d", - "prebuilt": false, + "name": "Computers not requiring inbound SMB signing", + "guid": "6b1fcfb6-b010-41a2-9d31-f9872fe994ff", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "ACEs granted across a trust, the ACEs are set on trusting objects and the rights are granted to objects from trusted domains.", - "query": "MATCH p=(trustedDomainPrincipal:Base)-[r]->(trustingDomainPrincipal:Base)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nAND r.isacl\nRETURN p\nLIMIT 1000", + "category": "NTLM Relay Attacks", + "description": null, + "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nRETURN n", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Public Key Services container", - "guid": "07e94492-71aa-4665-ab8c-e7aec25906cd", + "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled", + "guid": "96e70597-2d74-4503-a624-f1e30b642894", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (c:Container)-[:Contains*..]->(:Base)\nWHERE c.distinguishedname starts with 'CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC='\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Computers where Domain Users are local administrators", - "guid": "d43a7bdc-33c6-4a39-a3bb-24115749e595", + "name": "Servers where Domain Users can RDP", + "guid": "b9a330ae-1d89-44d4-8f74-9ca18e93eb92", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(s:Group)-[:AdminTo]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Accounts with SID History to a same-domain account", - "guid": "275d2d58-0cad-4cad-8103-e0874cece666", - "prebuilt": false, + "name": "Entra Users with Entra Admin Role approval (direct)", + "guid": "74d7993c-24af-4df7-8402-5c6fb22d088c", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Dangerous Privileges", + "category": "General", "description": null, - "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE n.domainsid = m.domainsid\nRETURN p", + "query": "MATCH p = (:AZUser)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Users with non-default Primary Group membership", - "guid": "93890f88-df2c-4167-a945-a53961d08d00", + "name": "Accounts with SID History", + "guid": "8172d52c-a975-49bd-9180-5b6efc59c9ab", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:User)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-513\" // Domain Users\nAND r.isprimarygroup = true\nAND NOT n.objectid ENDS WITH \"-501\" // Guests account, as it has primaryGroup to Guests\nAND (n.gmsa IS NULL OR n.gmsa = false) // Not gMSA, as it has primaryGroup to Domain Computers\nAND (n.msa IS NULL OR n.msa = false) // Not MSA, as it has primaryGroup to Domain Computers\nRETURN p", + "query": "MATCH p=(:Base)-[:HasSIDHistory]->(:Base)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2109,63 +2365,59 @@ ] }, { - "name": "Domains without Microsoft LAPS computers", - "guid": "f9b440b5-732c-4ed3-b6d2-83857db17e1a", - "prebuilt": false, + "name": "Disabled Tier Zero / High Value principals", + "guid": "860d5c2d-84fe-4c85-80de-e0a9badbd0e7", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Domain Information", + "category": "Azure Hygiene", "description": null, - "query": "MATCH (d:Domain)\nOPTIONAL MATCH (c:Computer)\nWHERE c.domainsid = d.objectid AND c.haslaps = true\nWITH d, COLLECT(c) AS computers\nWHERE SIZE(computers) = 0\nRETURN d", + "query": "MATCH (n:AZBase)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Enrollment rights on published certificate templates", - "guid": "a4ae2e54-aad3-4bfd-a12d-90cb8a9cbc86", + "name": "Shortest paths to Tier Zero / High Value targets", + "guid": "237aac58-8641-4703-a9f7-001d69546fd8", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Shortest Paths", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE ((t:Tag_Tier_Zero) OR (COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0'))\nAND s<>t\nRETURN p\nLIMIT 1000", + "revision": 3, "resources": [], "acknowledgements": [] }, { - "name": "Computers with passwords older than the default maximum password age", - "guid": "185c5010-8d4f-4f9b-b24e-831707dddfca", + "name": "Tier Zero computers with the WebClient running", + "guid": "27a6f917-8ed4-4e2e-9b38-41a4b6de1b14", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Machine account passwords are regularly changed for security purposes. Starting with Windows 2000-based computers, the machine account password automatically changes every 30 days.", - "query": "WITH 60 as rotation_period\nMATCH (n:Computer)\nWHERE n.pwdlastset < (datetime().epochseconds - (rotation_period * 86400)) // password not rotated\nAND n.enabled = true // enabled computers\nAND n.whencreated < (datetime().epochseconds - (rotation_period * 86400)) // exclude recently created computers\nAND n.lastlogontimestamp > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Replicated value)\nAND n.lastlogon > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Non-replicated value)\nRETURN n", + "description": null, + "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c LIMIT 1000", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/disable-machine-account-password" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Smart card accounts with passwords not rotated in over 1 year", - "guid": "7e56f2e7-79c3-4f0d-aa3e-14cf3de7ab73", + "name": "Domain Controllers allowing NTLMv1 or LM authentication", + "guid": "4b42513c-f89d-47ff-8d98-908af49d2b48", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (n:Base)\nWHERE n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nAND n.enabled = true\nAND n.smartcardrequired = true\nRETURN n", + "query": "MATCH (dc:Computer)\nWHERE dc.isdc = true\nAND (dc.lmcompatibilitylevel IS NOT NULL AND NOT dc.lmcompatibilitylevel = 5)\nRETURN dc", "revision": 1, "resources": [], "acknowledgements": [ @@ -2173,89 +2425,90 @@ ] }, { - "name": "Users with passwords not rotated in over 1 year", - "guid": "be70d1bd-b7eb-40b0-971c-eefc50eca032", + "name": "Computers where Domain Users are local administrators", + "guid": "d43a7bdc-33c6-4a39-a3bb-24115749e595", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", + "query": "MATCH p=(s:Group)-[:AdminTo]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Shortest paths to Domain Admins", - "guid": "f40cb34b-5ec7-44bc-9aa8-a200a4a41f22", - "prebuilt": true, + "name": "AS-REP Roastable Tier Zero users (DontReqPreAuth)", + "guid": "6d51e4dc-e1ad-477a-b6c6-324f18f03120", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=shortestPath((t:Group)<-[:AD_ATTACK_PATHS*1..]-(s:Base))\nWHERE t.objectid ENDS WITH '-512' AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.dontreqpreauth = true\nRETURN n", + "revision": 1, + "resources": [ + "https://attack.mitre.org/techniques/T1558/004/" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Shortest paths to systems trusted for unconstrained delegation", - "guid": "16a9e47b-45f8-4514-b409-771bb5186142", + "name": "All Domain Admins", + "guid": "0596dba7-9180-49a0-aa54-00243240037c", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", + "category": "Domain Information", "description": null, - "query": "MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Computer))\nWHERE t.unconstraineddelegation = true AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p = (t:Group)<-[:MemberOf*1..]-(a)\nWHERE (a:User or a:Computer) and t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Nested groups within Tier Zero / High Value", - "guid": "8e541e75-df1d-423f-b429-4bbf0403a338", + "name": "All service principals with Microsoft Graph privilege to grant arbitrary App Roles", + "guid": "e6d6b5da-89da-4514-a409-2d6e368397da", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "Microsoft Graph", "description": null, - "query": "MATCH p=(t:Group)<-[:MemberOf*..]-(s:Group)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT s.objectid ENDS WITH '-512' // Domain Admins\nAND NOT s.objectid ENDS WITH '-519' // Enterprise Admins\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(:AZServicePrincipal)-[:AZMGGrantAppRoles]->(:AZTenant)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Collection health of DC Registry Data", - "guid": "3f0fa2f3-fbdf-42c0-9e7d-97e689009161", - "prebuilt": false, + "name": "On-Prem Users synced to Entra Users with Entra Group Membership", + "guid": "edb575df-2048-4ef0-a0e4-168544a496e9", + "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Domain Information", - "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured DC to potentially a full forest compromise by any principal. DCs returned by this query have not been collected.", - "query": "MATCH p=(:Domain)<-[:DCFor]-(c:Computer)\nWHERE c.strongcertificatebindingenforcementraw IS NULL\n// Exclude inactive DCs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", + "category": "Cross Platform Attack Paths", + "description": null, + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#dc-registry" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Domains with more than 50 Tier Zero accounts", - "guid": "f046e95a-5f84-4e83-bcda-6e83f3d8e21a", + "name": "Enabled computers inactive for 180 days", + "guid": "0768e810-1e1e-4319-a216-76d9c2058644", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (d:Domain)-[:Contains*1..]->(n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH d, COUNT(n) AS adminCount\nWHERE adminCount > 50\nRETURN d", + "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -2263,61 +2516,78 @@ ] }, { - "name": "Non-Tier Zero account with excessive control", - "guid": "944cecfe-519b-4318-b226-e8520161b454", + "name": "Principal with SPN keyword", + "guid": "38a9c4c9-3d70-453f-a017-cbfd35ed9917", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": "Returns non-Tier Zero principals with >= 1000 direct rights to other principals. This does not include rights from group memberships.", - "query": "MATCH (n:Base)-[r:AD_ATTACK_PATHS]->(m:Base)\nWHERE NOT r:MemberOf\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH n, COLLECT(DISTINCT(m)) AS endNodes\nWHERE SIZE(endNodes) >= 1000\nRETURN n", - "revision": 3, - "resources": [], + "category": "Kerberos Interaction", + "description": "Finds service accounts used with a specific Kerberos-enabled service or all service accounts running on a Kerberos-enabled service on a specific server.", + "query": "// Replace keyword with a service type or server name (not FQDN)\nWITH \"KEYWORD\" as SPNKeyword\nMATCH (n:User)\nWHERE ANY(keyword IN n.serviceprincipalnames WHERE toUpper(keyword) CONTAINS toUpper(SPNKeyword))\nRETURN n", + "revision": 1, + "resources": [ + "https://adsecurity.org/?page_id=183" + ], "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" + "Ryan, @haus3c" ] }, { - "name": "AS-REP Roastable users (DontReqPreAuth)", - "guid": "2570e359-dec1-419d-b0dc-a204bd64ee42", + "name": "Non-default permissions on IssuancePolicy nodes", + "guid": "b2280665-c91b-448c-8c0f-97d1f38b6f59", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Kerberos Interaction", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (u:User)\nWHERE u.dontreqpreauth = true\nAND u.enabled = true\nRETURN u\nLIMIT 100", + "query": "MATCH p = (s:Base)-[:GenericAll|GenericWrite|Owns|WriteOwner|WriteDacl]->(:IssuancePolicy)\nWHERE NOT s.objectid ENDS WITH '-512' AND NOT s.objectid ENDS WITH '-519'\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/004/" - ], + "resources": [], "acknowledgements": [] }, { - "name": "Dangerous privileges for Domain Users groups", - "guid": "9b8b9c18-f8c6-4c54-a20f-de0f7a7edbe0", + "name": "Shortest paths to systems trusted for unconstrained delegation", + "guid": "16a9e47b-45f8-4514-b409-771bb5186142", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Shortest Paths", "description": null, - "query": "MATCH p=(s:Group)-[:AD_ATTACK_PATHS]->(:Base)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", + "query": "MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Computer))\nWHERE t.unconstraineddelegation = true AND s<>t\nRETURN p\nLIMIT 1000", "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "All Operators", - "guid": "3dfd0843-1ff9-4c21-aa67-feae08d109de", + "name": "Enrollment rights on published ESC2 certificate templates", + "guid": "ebc77984-1ceb-4ed2-a395-ce1067847941", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(c:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE c.requiresmanagerapproval = false\nAND (c.effectiveekus = [''] OR '2.5.29.37.0' IN c.effectiveekus OR c.effectiveekus IS NULL)\nAND (c.authorizedsignatures = 0 OR c.schemaversion = 1)\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [ + "https://posts.specterops.io/certified-pre-owned-d95910965cd2", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547" + ], + "acknowledgements": [] + }, + { + "name": "Large default group added to computer-local group", + "guid": "dde133d2-b4d2-4de9-a656-905f3bf066f3", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(:Base)-[:MemberOf]->(n:Group)\nWHERE (\n n.objectid ENDS WITH 'S-1-5-32-551' OR // Backup Operators\n n.objectid ENDS WITH 'S-1-5-32-556' OR // Network Configuration Operators\n n.objectid ENDS WITH 'S-1-5-32-549' OR // Server Operators\n n.objectid ENDS WITH 'S-1-5-32-579' OR // Access Control Assistance Operators\n n.objectid ENDS WITH 'S-1-5-32-548' OR // Account Operators\n n.objectid ENDS WITH 'S-1-5-32-569' OR // Cryptographic Operators\n n.objectid ENDS WITH 'S-1-5-32-550' // Print Operators\n)\nRETURN p", + "query": "MATCH p=(n:Group)-[:MemberOfLocalGroup]->(m:ADLocalGroup)-[:LocalToComputer]->(:Computer)\nWHERE n.objectid =~ \".*-(S-1-5-11|S-1-1-0|S-1-5-32-545|S-1-5-7|-513|-515)$\" // Authenticated Users, Everyone, Users, Anonymous, Domain Users, Domain Computers\nAND NOT m.objectid =~ \".*-(545|574|554)$\" // Users, Certificate Service DCOM Access, Pre-Windows 2000 Compatible Access\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2325,85 +2595,91 @@ ] }, { - "name": "Accounts with SID History", - "guid": "8172d52c-a975-49bd-9180-5b6efc59c9ab", - "prebuilt": false, + "name": "Locations of Tier Zero / High Value objects", + "guid": "18a83a17-b451-4343-acfe-7620516e2968", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "MATCH p=(:Base)-[:HasSIDHistory]->(:Base)\nRETURN p", + "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Circular AD group memberships", - "guid": "fcaa5ffc-3d22-481f-a2a2-18a4eec30058", + "name": "Tier Zero / High Value external Entra ID users", + "guid": "20e07417-d286-4dca-a962-568f2b262f65", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "Azure Hygiene", + "description": null, + "query": "MATCH (n:AZUser)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.name CONTAINS '#EXT#@'\nRETURN n\nLIMIT 100", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Non-Tier Zero principals with BadSuccessor rights (with prerequisites check)", + "guid": "74daaebe-6040-4f7a-9c9a-416faf73dcc3", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", - "query": "MATCH p=(x:Group)-[:MemberOf*2..]->(y:Group)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", + "category": "Dangerous Privileges", + "description": "Finds non-Tier Zero principals with BadSuccessor rights after checking prerequisites check (DC2025 & KDC key).", + "query": "// Find 2025 DCs\nMATCH (dc:Computer)\nWHERE dc.isdc = true AND dc.operatingsystem CONTAINS '2025'\n// Find gMSAs\nMATCH (m:User)\nWHERE m.gmsa = true\n// Find OU control\nMATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)\n// Confirm domain has a 2025 DC\nWHERE ou.domain = dc.domain\n// Confirm domain KDC key\nAND ou.domain = m.domain\n// Exclude Tier Zero\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p LIMIT 1000", "revision": 1, "resources": [ - "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + "https://bsky.app/profile/specterops.io/post/3lpua65qeu22l" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Foreign Service Principals With Group Memberships", - "guid": "327ef6a5-bfa8-4c92-b35a-d3df85264a24", - "prebuilt": false, + "name": "Shortest paths to privileged roles", + "guid": "3dc73dd8-4873-4aeb-a88f-56a58c77f512", + "prebuilt": true, "platforms": [ "Azure" ], - "category": "Azure Hygiene", - "description": "Review each to validate whether their presence is expected and whether the assigned group memberships are appropriate for the foreign service principal.", - "query": "MATCH p = (sp:AZServicePrincipal)-[:AZMemberOf]->(g:AZGroup)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(g.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [ - "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" - ], - "acknowledgements": [ - "Stephen Hinck" - ] + "category": "Shortest Paths", + "description": null, + "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole))\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] }, { - "name": "Direct Principal Rights Assignment", - "guid": "1d9c6ae3-38fc-4089-b5ad-fc3be0fa8eec", - "prebuilt": false, + "name": "All Kerberoastable users", + "guid": "14ab4eaa-b73b-49c4-b2d1-1e020757c995", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "This query identifies rights assigned directly to users or computers instead of groups. Active Directory best practice requires granting rights to groups, then adding users as group members. This role-based access control (RBAC) approach ensures permissions are easily auditable and manageable. Results include inherited rights, which must be modified at the parent container level.", - "query": "MATCH p=(n:Base)-[r:GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE (n:User OR n:Computer) \nRETURN p\nLIMIT 1000", + "category": "Kerberos Interaction", + "description": null, + "query": "MATCH (u:User)\nWHERE u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [ - "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + "https://attack.mitre.org/techniques/T1558/003/" ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Tier Zero computers with the WebClient running", - "guid": "27a6f917-8ed4-4e2e-9b38-41a4b6de1b14", + "name": "All DNSAdmins", + "guid": "183fb320-f3ae-4ab3-a090-3f9a7db692e1", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c LIMIT 1000", + "query": "MATCH p=(n:Base)-[:MemberOf]->(g:Group) \nWHERE n.name STARTS WITH \"DNSADMINS@\"\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2411,131 +2687,107 @@ ] }, { - "name": "Principals with DCSync privileges", - "guid": "6e9beb8a-ad14-43de-bda1-644d174a5906", + "name": "Devices with unsupported operating systems", + "guid": "e3f2b53a-7ce6-4e52-9c74-68b69338288b", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Dangerous Privileges", + "category": "Azure Hygiene", "description": null, - "query": "MATCH p=(:Base)-[:DCSync|AllExtendedRights|GenericAll]->(:Domain)\nRETURN p\nLIMIT 1000", + "query": "MATCH (n:AZDevice)\nWHERE n.operatingsystem CONTAINS 'WINDOWS'\nAND n.operatingsystemversion =~ '(10.0.19044|10.0.22000|10.0.19043|10.0.19042|10.0.19041|10.0.18363|10.0.18362|10.0.17763|10.0.17134|10.0.16299|10.0.15063|10.0.14393|10.0.10586|10.0.10240|6.3.9600|6.2.9200|6.1.7601|6.0.6200|5.1.2600|6.0.6003|5.2.3790|5.0.2195).?.*'\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "ESC8-vulnerable Enterprise CAs", - "guid": "60881923-296c-4702-adf7-a4f059dc9bb8", + "name": "Workstations where Domain Users can RDP", + "guid": "9486e0e6-2617-4595-b969-cf57ca21fc86", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:EnterpriseCA)\nWHERE n.hasvulnerableendpoint=true\nRETURN n", + "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND NOT toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Entra ID SSO accounts not rolling Kerberos decryption key", - "guid": "1867abf8-08e3-4ea8-8f65-8366079d35c4", - "prebuilt": false, - "platforms": [ - "Active Directory", - "Azure" - ], - "category": "Configuration Weakness", - "description": "Microsoft highly recommends that you roll over the Entra ID SSO Kerberos decryption key at least every 30 days.", - "query": "MATCH (n:Computer)\nWHERE n.name STARTS WITH \"AZUREADSSOACC.\"\nAND n.pwdlastset < (datetime().epochseconds - (30 * 86400))\nRETURN n", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso-faq#how-can-i-roll-over-the-kerberos-decryption-key-of-the--azureadsso--computer-account-" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Sessions across trusts", - "guid": "aea7ac64-1f51-407b-b0ee-19fd30075794", + "name": "Tier Zero computers not owned by Tier Zero", + "guid": "99d29ded-223a-442b-a0e0-f8b5694c6441", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Users logging on across a trust, the users originate from trusted domains.", - "query": "MATCH p=(trustedDomainPrincipal:Computer)-[r:HasSession]->(trustingDomainPrincipal:User)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(n:Base)-[:Owns]->(:Computer)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains not mitigating CVE-2021-42291", - "guid": "02202726-d86d-46c2-891c-9770c635f76f", + "name": "Uncommon permission on containers", + "guid": "018c2b45-e30f-47d8-a751-22419c3d0736", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Checks the AttributeAuthorizationOnLDAPAdd flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \"^(.{0,27}|.{27}[^1].*)$\"\nRETURN n", + "description": "BloodHound typically identifies risk on Active Directory objects stored in OUs, however behind the scenes; Active Directory has a hieracy of containers e.g. CN=SYSTEM and CN=CONFIGURATION, on which control can lead to risk. Results are prone to false-positives but can assist auditing containers permissions.", + "query": "MATCH p=(:Domain)-[:Contains*1..]->(c:Container)<-[r]-(n:Base)\n\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\n\n// Scope edges to ACLs\nAND r.isacl\n\n// Exclude CN=Users and CN=Computers containers\nAND NOT c.distinguishedname STARTS WITH \"CN=COMPUTERS,DC=\"\nAND NOT c.distinguishedname STARTS WITH \"CN=USERS,DC=\"\n\n// Exclude same-domain unresolved SIDs\nAND NOT (n.distinguishedname IS NULL AND n.domainsid = c.domainsid)\n\n// Exclude default: Cert Publishers\nAND NOT (c.distinguishedname CONTAINS \",CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC=\" AND n.objectid ENDS WITH \"-517\")\n\n// Exclude default: RAS and IAS Servers\nAND NOT (c.distinguishedname CONTAINS \"CN=RAS AND IAS SERVERS ACCESS CHECK,CN=SYSTEM,DC=\" AND n.objectid ENDS WITH \"-553\")\n\n// Exclude default: DNS\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\" AND n.name STARTS WITH \"DNSADMINS@\")\n\n// Exclude default: ConfigMgr\nAND NOT (c.distinguishedname STARTS WITH \"CN=SYSTEM MANAGEMENT,CN=SYSTEM,DC=\" AND n.samaccountname ENDS WITH \"$\")\n\n// Exclude default: Exchange pt1\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" AND (n.name STARTS WITH \"EXCHANGE TRUSTED SUBSYSTEM@\" OR n.name STARTS WITH \"ORGANIZATION MANAGEMENT@\" OR n.name STARTS WITH \"EXCHANGE SERVICES@\"))\n\n// Exclude default: Exchange pt2\nAND NOT ((c.distinguishedname CONTAINS \"CN=MONITORING MAILBOXES,CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\") AND n.name STARTS WITH \"EXCHANGE ENTERPRISE SERVERS@\")\n\n// Exclude default: Exchange pt3\nAND NOT ((c.distinguishedname CONTAINS \"CN=ACTIVE DIRECTORY CONNECTIONS,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname =~ \"CN=RECIPIENT UPDATE SERVICES,CN=ADDRESS LISTS CONTAINER,CN=.*,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\") AND n.name STARTS WITH \"EXCHANGE DOMAIN SERVERS@\")\n\nRETURN p\nLIMIT 2000", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "All coerce and NTLM relay edges", - "guid": "15c5ff3b-856c-44d1-a731-a8cb72512dd1", + "name": "Computers with the WebClient running", + "guid": "51107ad1-f0bc-43d3-a561-5cee471ca196", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p = (n:Base)-[:CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|CoerceAndRelayNTLMToADCS|CoerceAndRelayNTLMToSMB]->(:Base)\nRETURN p LIMIT 500", + "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nRETURN c LIMIT 1000", "revision": 1, - "resources": [ - "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/" - ], + "resources": [], "acknowledgements": [] }, { - "name": "Overprivileged Microsoft Entra Connect accounts", - "guid": "9e6e75b4-9ecc-45d4-a39b-b6427b813f0a", + "name": "Collection health of CA Registry Data", + "guid": "c8dd3479-8063-450a-9456-557bc5f39e10", "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Legacy MSOL accounts were by default deployed with Domain Admins or Enterprise Admins membership.", - "query": "MATCH p=(n:User)-[:MemberOf*1..]->(g:Group)\nWHERE n.name STARTS WITH \"MSOL_\"\nAND (g.objectid ENDS WITH \"-512\" // Domain Admins\nOR g.objectid ENDS WITH \"-519\") // Entterprise Admins\nRETURN p", + "category": "Domain Information", + "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured CA to potentially a full forest compromise by any principal. CAs returned by this query have not been collected.", + "query": "MATCH p=(eca:EnterpriseCA)<-[:HostsCAService]-(c:Computer)\nWHERE (\n eca.isuserspecifiessanenabledcollected = false\n OR eca.casecuritycollected = false\n OR eca.enrollmentagentrestrictionscollected = false\n OR eca.roleseparationenabledcollected = false\n)\n// Exclude inactive CAs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/reference-connect-accounts-permissions" + "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#ca-registry" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Non-Tier Zero account with unconstrained delegation", - "guid": "e7e9a927-3f34-42c7-b921-d8bcf626011e", + "name": "Non-Tier Zero accounts with SID History of Tier Zero accounts", + "guid": "59744dfe-9411-4daf-b342-1203dc62acd4", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:Base)\nWHERE n.unconstraineddelegation = true\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2543,61 +2795,60 @@ ] }, { - "name": "Computers with membership in Protected Users", - "guid": "a26372f4-2e92-49f6-8993-6657fbc1569a", - "prebuilt": true, + "name": "Accounts with SID History to a non-existent domain", + "guid": "2710401a-c4c2-4d2c-9edb-d7625045f2e8", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:Base)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH \"-525\"\nRETURN p LIMIT 1000", + "query": "MATCH (d:Domain)\nWITH collect(d.objectid) AS domainSIDs\nMATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE NOT n.domainsid IN domainSIDs\nRETURN p", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Non-Tier Zero principals with control of AdminSDHolder", - "guid": "4c1e0137-5b7f-48d8-bd09-9db7674bca61", - "prebuilt": false, + "name": "Synced Entra Users with Entra Admin Role direct eligibility", + "guid": "ea82e359-725c-4881-83e9-35007e859cf5", + "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Dangerous Privileges", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p=(n:Group)-[r:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteOwnerLimitedRights|OwnsLimitedRights]->(m:Container)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND m.name STARTS WITH \"ADMINSDHOLDER@\"\nRETURN p", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#adminsdholder" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Enrollment rights on CertTemplates with OIDGroupLink", - "guid": "140a68eb-d21c-4b75-971f-309225fb2d75", + "name": "Tier Zero / High Value enabled users not requiring smart card authentication", + "guid": "867f9f17-c149-4c4b-ad84-9a807622ff8c", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:ExtendedByPolicy]->(:IssuancePolicy)-[:OIDGroupLink]->(:Group)\nRETURN p\nLIMIT 1000", + "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.enabled = true\nAND u.smartcardrequired = false\nAND NOT u.name STARTS WITH 'MSOL_' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'PROVAGENTGMSA' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'ADSYNCMSA_' // Removes false positive, Entra sync\nRETURN u", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Non-default members in Pre-Windows 2000 Compatible Access", - "guid": "091995b9-7254-473a-996f-6b8368d20431", + "name": "Tier Zero computers with unsupported operating systems", + "guid": "a87b558c-5746-4a90-9f83-c86e7b924a52", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE NOT n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND NOT (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nAND NOT n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", + "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [ @@ -2605,62 +2856,57 @@ ] }, { - "name": "All incoming and local paths for a specific computer", - "guid": "1f67e538-19d4-4020-89c8-5b39b31571bd", - "prebuilt": false, + "name": "Tier Zero / High Value users with non-expiring passwords", + "guid": "4eca1b69-00a2-48a0-abb3-b94ea647cf6b", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "All incoming and local paths for a specific computer; incoming from domain objects and paths local inside the computer.", - "query": "// Replace 'HOSTNAME' with the computer's shortname eg. 'SRV01', not FQDN\nMATCH p=(n:Base)-[:RemoteInteractiveLogonPrivilege|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base)\nWHERE m.name CONTAINS 'HOSTNAME'\nAND m.name CONTAINS '.' // Only see computer-related objects (eg. not AD Groups)\nRETURN p", + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Entra Users synced from On-Prem Users added to Domain Admins group", - "guid": "62722d5f-bd93-4d11-beeb-9be261827e4e", + "name": "All members of high privileged roles", + "guid": "3df24d92-dd12-4125-811b-e696b098f60e", "prebuilt": true, "platforms": [ - "Active Directory", "Azure" ], - "category": "Cross Platform Attack Paths", + "category": "General", "description": null, - "query": "MATCH p = (:AZUser)-[:SyncedToADUser]->(:User)-[:MemberOf]->(t:Group)\nWHERE t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(t:AZRole)<-[:AZHasRole|AZMemberOf*1..2]-(:AZBase)\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Kerberoastable users with most admin privileges", - "guid": "9907b208-494c-4ba6-846d-485e6de14e17", + "name": "Computers where Domain Users can read LAPS passwords", + "guid": "aa4bfa95-e7b9-4d56-8f35-f34f04d7b6f4", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Kerberos Interaction", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (u:User)\nWHERE u.hasspn = true\n AND u.enabled = true\n AND NOT u.objectid ENDS WITH '-502'\n AND NOT COALESCE(u.gmsa, false) = true\n AND NOT COALESCE(u.msa, false) = true\nMATCH (u)-[:MemberOf|AdminTo*1..]->(c:Computer)\nWITH DISTINCT u, COUNT(c) AS adminCount\nRETURN u\nORDER BY adminCount DESC\nLIMIT 100", + "query": "MATCH p=(s:Group)-[:AllExtendedRights|ReadLAPSPassword]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/003/" - ], + "resources": [], "acknowledgements": [] }, { - "name": "Uncommon permission on containers", - "guid": "018c2b45-e30f-47d8-a751-22419c3d0736", + "name": "Domains affected by AdPrep privilege escalation risk", + "guid": "815ff190-f6f3-4757-a516-2f4bf589b705", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "BloodHound typically identifies risk on Active Directory objects stored in OUs, however behind the scenes; Active Directory has a hieracy of containers e.g. CN=SYSTEM and CN=CONFIGURATION, on which control can lead to risk. Results are prone to false-positives but can assist auditing containers permissions.", - "query": "MATCH p=(:Domain)-[:Contains*1..]->(c:Container)<-[r]-(n:Base)\n\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\n\n// Scope edges to ACLs\nAND r.isacl\n\n// Exclude CN=Users and CN=Computers containers\nAND NOT c.distinguishedname STARTS WITH \"CN=COMPUTERS,DC=\"\nAND NOT c.distinguishedname STARTS WITH \"CN=USERS,DC=\"\n\n// Exclude same-domain unresolved SIDs\nAND NOT (n.distinguishedname IS NULL AND n.domainsid = c.domainsid)\n\n// Exclude default: Cert Publishers\nAND NOT (c.distinguishedname CONTAINS \",CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC=\" AND n.objectid ENDS WITH \"-517\")\n\n// Exclude default: RAS and IAS Servers\nAND NOT (c.distinguishedname CONTAINS \"CN=RAS AND IAS SERVERS ACCESS CHECK,CN=SYSTEM,DC=\" AND n.objectid ENDS WITH \"-553\")\n\n// Exclude default: DNS\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\" AND n.name STARTS WITH \"DNSADMINS@\")\n\n// Exclude default: ConfigMgr\nAND NOT (c.distinguishedname STARTS WITH \"CN=SYSTEM MANAGEMENT,CN=SYSTEM,DC=\" AND n.samaccountname ENDS WITH \"$\")\n\n// Exclude default: Exchange pt1\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" AND (n.name STARTS WITH \"EXCHANGE TRUSTED SUBSYSTEM@\" OR n.name STARTS WITH \"ORGANIZATION MANAGEMENT@\" OR n.name STARTS WITH \"EXCHANGE SERVICES@\"))\n\n// Exclude default: Exchange pt2\nAND NOT ((c.distinguishedname CONTAINS \"CN=MONITORING MAILBOXES,CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\") AND n.name STARTS WITH \"EXCHANGE ENTERPRISE SERVERS@\")\n\n// Exclude default: Exchange pt3\nAND NOT ((c.distinguishedname CONTAINS \"CN=ACTIVE DIRECTORY CONNECTIONS,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname =~ \"CN=RECIPIENT UPDATE SERVICES,CN=ADDRESS LISTS CONTAINER,CN=.*,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\") AND n.name STARTS WITH \"EXCHANGE DOMAIN SERVERS@\")\n\nRETURN p\nLIMIT 2000", + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(n:Group)-[r:GenericAll]->(m:Domain)\nWHERE n.objectid ENDS WITH \"-527\" // Enterprise Key Admins\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2668,34 +2914,32 @@ ] }, { - "name": "Domains allowing unauthenticated NSPI RPC binds", - "guid": "a950fdab-5934-4c69-a88b-e2e0e3da9d52", + "name": "Smart card accounts with passwords not rotated in over 1 year", + "guid": "7e56f2e7-79c3-4f0d-aa3e-14cf3de7ab73", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Checks the fAllowAnonNSPI flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{7}[^0].*\"\nRETURN n", + "description": null, + "query": "MATCH (n:Base)\nWHERE n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nAND n.enabled = true\nAND n.smartcardrequired = true\nRETURN n", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Cross-forest trusts with abusable configuration", - "guid": "5cf1f354-80d4-420e-bc4b-424fabc21a56", + "name": "Dangerous privileges for Domain Users groups", + "guid": "9b8b9c18-f8c6-4c54-a20f-de0f7a7edbe0", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Domain)-[:CrossForestTrust|SpoofSIDHistory|AbuseTGTDelegation]-(m:Domain)\nWHERE (n)-[:SpoofSIDHistory|AbuseTGTDelegation]-(m)\nRETURN p", - "revision": 1, + "query": "MATCH p=(s:Group)-[r:AD_ATTACK_PATHS]->(:Base)\nWHERE s.objectid ENDS WITH '-513'\nAND NOT r:MemberOf\nRETURN p\nLIMIT 1000", + "revision": 3, "resources": [], "acknowledgements": [] } From 837b12a92b29706e81b768b476e2eb986dc5bae2 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 13 Oct 2025 22:15:19 +0200 Subject: [PATCH 15/22] Update readme - Remove unnecessary chars - Add a BHOP example for testing all queries --- README.md | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a03d8ab..772194e 100644 --- a/README.md +++ b/README.md @@ -80,13 +80,15 @@ Command line usage is easy with the [BloodHound Operator](https://github.com/Sad First load the `Queries.json`: ```powershell -> $queries = Invoke-RestMethod "https://raw.githubusercontent.com/SpecterOps/BloodHoundQueryLibrary/refs/heads/main/Queries.json" +$queries = Invoke-RestMethod "https://raw.githubusercontent.com/SpecterOps/BloodHoundQueryLibrary/refs/heads/main/Queries.json" ``` Example: Run a query in BloodHound: ```powershell -> $queries[0] | BHInvoke +$queries[0] | BHInvoke +``` +``` Name : Tier Zero / High Value external Entra ID users @@ -104,10 +106,32 @@ Timestamp : 17-06-2025 13:55:27 Duration : 00:00:00.0265562 ``` -Example: Import a few queries to BloodHound's Custom Searches: +Example: Import a few queries to BloodHound's Custom Searches: + +```powershell +$queries[0..4] | New-BHPathQuery +``` + +Example: Test all queries ```powershell -> $queries[0..4] | New-BHPathQuery +$results = [System.Collections.ArrayList]::new() +$queries | % { + "$($results.Count + 1)/$($queries.Count) $($_.name)" + $results.Add([PSCustomObject]@{ + Name = $_.name + Time = (Measure-Command { + $errorMsg = $null + try { + $result = $_ | BHInvoke -WarningAction "Stop" + } catch { + $errorMsg = $_.Exception.Message + } + }).TotalSeconds + Result = $result + Error = $errorMsg + }) | Out-Null +} ``` ## Contributing From f926bd678e036a6cabdbad0791ecd6dd2308f507 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 13 Oct 2025 22:16:36 +0200 Subject: [PATCH 16/22] Delete Trace ACE inheritance.yml The query was unnecessary as an ACE tracing feature is now in-product via the Edge Entity Panel, and this query had limited functionality anyway. --- queries/Trace ACE inheritance.yml | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 queries/Trace ACE inheritance.yml diff --git a/queries/Trace ACE inheritance.yml b/queries/Trace ACE inheritance.yml deleted file mode 100644 index a8f01a6..0000000 --- a/queries/Trace ACE inheritance.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: Trace ACE inheritance -guid: 8c5454df-3ae8-412c-b271-3c4c55df7141 -prebuilt: false -platforms: Active Directory -category: Domain Information -description: When BloodHound shows that an inherited ACE applies to an object it does not show the source/where it is inherited from from (OU, Container, Domain root) - the source is where it should be remediated. This query can sometimes find the source of an inherited ACE, but only works if the ACE is set to also apply to the source itself. -query: |- - // Replace INSERT_OBJECT_ID with the affected principal - // Replace 'GenericAll' with the specific edge you're tracing - WITH "INSERT_OBJECT_ID" as OID - MATCH p=()-[:GenericAll {isacl:true,isinherited:false}]->()-[:Contains*1..]->(:Base{objectid:OID}) - WHERE NONE(ou in NODES(p) WHERE ou:OU AND ou.isaclprotected IS NOT NULL) - RETURN p -revision: 1 -resources: -acknowledgements: Walter.Legowski, @SadProcessor From 7ce18f286f8fa4d432b654fa905804d6764f8329 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 13 Oct 2025 22:18:53 +0200 Subject: [PATCH 17/22] Update Computers with non-default Primary Group membership.yml - change DC/RODC ID method Change the identification method for DCs and RODCs to the built-in bool --- ...uters with non-default Primary Group membership.yml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/queries/Computers with non-default Primary Group membership.yml b/queries/Computers with non-default Primary Group membership.yml index 384d31b..4e798d5 100644 --- a/queries/Computers with non-default Primary Group membership.yml +++ b/queries/Computers with non-default Primary Group membership.yml @@ -7,11 +7,13 @@ description: query: |- MATCH p=(n:Computer)-[r:MemberOf]->(g:Group) WHERE NOT g.objectid ENDS WITH "-515" // Domain Computers - AND NOT g.objectid ENDS WITH "-516" // Domain Controllers - AND NOT g.objectid ENDS WITH "-521" // Read-Only Domain Controllers + AND NOT n.isdc = true + AND NOT n.isreadonlydc = true AND r.isprimarygroup = true RETURN p -revision: 1 +revision: 2 resources: +- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ada3/e12954a4-6865-4432-94e6-00c310ca87c0 +- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5dbcf875-e802-4357-a6e2-1bdff19ff9b5 +- https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/73d11ea7-e634-453e-944d-559654cc91c5 acknowledgements: Martin Sohn Christensen, @martinsohndk - From 3dae03baf54f76ee3ddd1599b4c0bb65693bb407 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 13 Oct 2025 22:31:00 +0200 Subject: [PATCH 18/22] Add warning to description of many-to-many queries --- ...rom Azure Applications to Tier Zero High Value targets.yml | 4 ++-- ...paths from Entra Users to Tier Zero High Value targets.yml | 4 ++-- queries/Shortest paths from Owned objects to Tier Zero.yml | 4 ++-- queries/Shortest paths to Azure Subscriptions.yml | 4 ++-- queries/Shortest paths to privileged roles.yml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml b/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml index da0c19a..a50f16f 100644 --- a/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml +++ b/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml @@ -3,13 +3,13 @@ guid: 60ff7c58-a98e-4bc1-9e32-8378d2db0c43 prebuilt: true platforms: Azure category: Shortest Paths -description: +description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase)) WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: diff --git a/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml b/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml index 3f3024a..0ed57af 100644 --- a/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml +++ b/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml @@ -3,14 +3,14 @@ guid: 58089b28-54e0-4fd2-bf66-3db480b00e2f prebuilt: true platforms: Azure category: Shortest Paths -description: +description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase)) WHERE (t:AZBase) AND t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: diff --git a/queries/Shortest paths from Owned objects to Tier Zero.yml b/queries/Shortest paths from Owned objects to Tier Zero.yml index f99d1b6..79eb7f0 100644 --- a/queries/Shortest paths from Owned objects to Tier Zero.yml +++ b/queries/Shortest paths from Owned objects to Tier Zero.yml @@ -3,7 +3,7 @@ guid: dfaa8e8f-2c79-4e92-a291-b1347f6e83b0 prebuilt: true platforms: Active Directory category: Shortest Paths -description: WARNING - MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING - MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- // MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE MATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base)) @@ -11,7 +11,7 @@ query: |- AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') RETURN p LIMIT 1000 -revision: 3 +revision: 4 resources: acknowledgements: diff --git a/queries/Shortest paths to Azure Subscriptions.yml b/queries/Shortest paths to Azure Subscriptions.yml index a17256f..08e05dc 100644 --- a/queries/Shortest paths to Azure Subscriptions.yml +++ b/queries/Shortest paths to Azure Subscriptions.yml @@ -3,13 +3,13 @@ guid: 4785b305-c101-461c-80fc-3fb3ff67a8ce prebuilt: true platforms: Azure category: Shortest Paths -description: +description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription)) WHERE s<>t RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: diff --git a/queries/Shortest paths to privileged roles.yml b/queries/Shortest paths to privileged roles.yml index 52b33b6..d619ab2 100644 --- a/queries/Shortest paths to privileged roles.yml +++ b/queries/Shortest paths to privileged roles.yml @@ -3,13 +3,13 @@ guid: 3dc73dd8-4873-4aeb-a88f-56a58c77f512 prebuilt: true platforms: Azure category: Shortest Paths -description: +description: WARNING: MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole)) WHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t RETURN p LIMIT 1000 -revision: 2 +revision: 3 resources: acknowledgements: From 330547970e2d4a876f4a29395e7c21ffd1f216a4 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 13 Oct 2025 22:33:03 +0200 Subject: [PATCH 19/22] Fixed query: Tier Zero accounts not members of Denied RODC Password Replication Group Was throwing error on PG: WARNING: 500 - ERROR: missing FROM-clause entry for table "s0" (SQLSTATE 42P01) --- ...Denied RODC Password Replication Group.yml | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/queries/Tier Zero accounts not members of Denied RODC Password Replication Group.yml b/queries/Tier Zero accounts not members of Denied RODC Password Replication Group.yml index 2831cc1..9f9e0bb 100644 --- a/queries/Tier Zero accounts not members of Denied RODC Password Replication Group.yml +++ b/queries/Tier Zero accounts not members of Denied RODC Password Replication Group.yml @@ -5,16 +5,22 @@ platforms: Active Directory category: Active Directory Hygiene description: query: |- - MATCH (n:Base) + // Get all Tier Zero accounts that are members of Denied RODC Password Replication Group + MATCH (n:Base)-[:MemberOf*1..]->(m:Group) WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') - AND (n:User or n:Computer) - WITH n - OPTIONAL MATCH (n)-[:MemberOf*1..]->(m:Group) - WHERE m.objectid ENDS WITH '-519' - WITH n, m - WHERE m IS NULL - RETURN n -revision: 1 + AND (n:User OR n:Computer) + AND m.objectid ENDS WITH '-519' + WITH COLLECT(n.objectid) AS MembersOfDeniedGroup + + // Get all Tier Zero accounts + MATCH (x:Base) + WHERE ((x:Tag_Tier_Zero) OR COALESCE(x.system_tags, '') CONTAINS 'admin_tier_0') + AND (x:User OR x:Computer) + + // Filter the members of Denied RODC Password Replication Group + AND NOT x.objectid IN MembersOfDeniedGroup + RETURN x +revision: 2 resources: acknowledgements: Martin Sohn Christensen, @martinsohndk From 7450620f69badbb092bc5c95bce4ed357ab64656 Mon Sep 17 00:00:00 2001 From: Martin Date: Mon, 13 Oct 2025 22:40:49 +0200 Subject: [PATCH 20/22] Fix to pass test FAILED tests/test_cypher_syntax.py::test_cypher_validation[queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml] - yaml.scanner.ScannerError: mapping values are not allowed here --- ... from Azure Applications to Tier Zero High Value targets.yml | 2 +- ...t paths from Entra Users to Tier Zero High Value targets.yml | 2 +- queries/Shortest paths from Owned objects to Tier Zero.yml | 2 +- queries/Shortest paths to Azure Subscriptions.yml | 2 +- queries/Shortest paths to privileged roles.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml b/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml index a50f16f..79d3312 100644 --- a/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml +++ b/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml @@ -3,7 +3,7 @@ guid: 60ff7c58-a98e-4bc1-9e32-8378d2db0c43 prebuilt: true platforms: Azure category: Shortest Paths -description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase)) WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t diff --git a/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml b/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml index 0ed57af..38987fb 100644 --- a/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml +++ b/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml @@ -3,7 +3,7 @@ guid: 58089b28-54e0-4fd2-bf66-3db480b00e2f prebuilt: true platforms: Azure category: Shortest Paths -description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase)) WHERE (t:AZBase) AND t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t diff --git a/queries/Shortest paths from Owned objects to Tier Zero.yml b/queries/Shortest paths from Owned objects to Tier Zero.yml index 79eb7f0..e92b152 100644 --- a/queries/Shortest paths from Owned objects to Tier Zero.yml +++ b/queries/Shortest paths from Owned objects to Tier Zero.yml @@ -3,7 +3,7 @@ guid: dfaa8e8f-2c79-4e92-a291-b1347f6e83b0 prebuilt: true platforms: Active Directory category: Shortest Paths -description: WARNING - MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- // MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE MATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base)) diff --git a/queries/Shortest paths to Azure Subscriptions.yml b/queries/Shortest paths to Azure Subscriptions.yml index 08e05dc..c809a87 100644 --- a/queries/Shortest paths to Azure Subscriptions.yml +++ b/queries/Shortest paths to Azure Subscriptions.yml @@ -3,7 +3,7 @@ guid: 4785b305-c101-461c-80fc-3fb3ff67a8ce prebuilt: true platforms: Azure category: Shortest Paths -description: WARNING: MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription)) WHERE s<>t diff --git a/queries/Shortest paths to privileged roles.yml b/queries/Shortest paths to privileged roles.yml index d619ab2..c63e66b 100644 --- a/queries/Shortest paths to privileged roles.yml +++ b/queries/Shortest paths to privileged roles.yml @@ -3,7 +3,7 @@ guid: 3dc73dd8-4873-4aeb-a88f-56a58c77f512 prebuilt: true platforms: Azure category: Shortest Paths -description: WARNING: MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE +description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE query: |- MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole)) WHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t From d8d7f239ab94cd79026169f38e861fa654a80d48 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 13 Oct 2025 20:41:32 +0000 Subject: [PATCH 21/22] Update combined queries --- Queries.json | 50 +++++++++++++++++++------------------------------- 1 file changed, 19 insertions(+), 31 deletions(-) diff --git a/Queries.json b/Queries.json index 5c8a3f8..667d015 100644 --- a/Queries.json +++ b/Queries.json @@ -602,9 +602,9 @@ "Active Directory" ], "category": "Shortest Paths", - "description": "WARNING - MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", "query": "// MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE\nMATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 3, + "revision": 4, "resources": [], "acknowledgements": [] }, @@ -1210,9 +1210,13 @@ ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-515\" // Domain Computers\nAND NOT g.objectid ENDS WITH \"-516\" // Domain Controllers\nAND NOT g.objectid ENDS WITH \"-521\" // Read-Only Domain Controllers\nAND r.isprimarygroup = true\nRETURN p", - "revision": 1, - "resources": [], + "query": "MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-515\" // Domain Computers\nAND NOT n.isdc = true\nAND NOT n.isreadonlydc = true\nAND r.isprimarygroup = true\nRETURN p", + "revision": 2, + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ada3/e12954a4-6865-4432-94e6-00c310ca87c0", + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5dbcf875-e802-4357-a6e2-1bdff19ff9b5", + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/73d11ea7-e634-453e-944d-559654cc91c5" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] @@ -1456,8 +1460,8 @@ ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND (n:User or n:Computer)\nWITH n\nOPTIONAL MATCH (n)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH '-519'\nWITH n, m\nWHERE m IS NULL\nRETURN n", - "revision": 1, + "query": "// Get all Tier Zero accounts that are members of Denied RODC Password Replication Group\nMATCH (n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND (n:User OR n:Computer)\nAND m.objectid ENDS WITH '-519'\nWITH COLLECT(n.objectid) AS MembersOfDeniedGroup\n\n// Get all Tier Zero accounts\nMATCH (x:Base)\nWHERE ((x:Tag_Tier_Zero) OR COALESCE(x.system_tags, '') CONTAINS 'admin_tier_0')\nAND (x:User OR x:Computer)\n\n// Filter the members of Denied RODC Password Replication Group\nAND NOT x.objectid IN MembersOfDeniedGroup\nRETURN x", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" @@ -1678,9 +1682,9 @@ "Azure" ], "category": "Shortest Paths", - "description": null, + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", "query": "MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, + "revision": 3, "resources": [], "acknowledgements": [] }, @@ -1706,9 +1710,9 @@ "Azure" ], "category": "Shortest Paths", - "description": null, + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", "query": "MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE (t:AZBase) AND t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 2, + "revision": 3, "resources": [], "acknowledgements": [] }, @@ -1782,9 +1786,9 @@ "Azure" ], "category": "Shortest Paths", - "description": null, + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription))\nWHERE s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, + "revision": 3, "resources": [], "acknowledgements": [] }, @@ -1922,22 +1926,6 @@ "resources": [], "acknowledgements": [] }, - { - "name": "Trace ACE inheritance", - "guid": "8c5454df-3ae8-412c-b271-3c4c55df7141", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Domain Information", - "description": "When BloodHound shows that an inherited ACE applies to an object it does not show the source/where it is inherited from from (OU, Container, Domain root) - the source is where it should be remediated. This query can sometimes find the source of an inherited ACE, but only works if the ACE is set to also apply to the source itself.", - "query": "// Replace INSERT_OBJECT_ID with the affected principal\n// Replace 'GenericAll' with the specific edge you're tracing\nWITH \"INSERT_OBJECT_ID\" as OID\nMATCH p=()-[:GenericAll {isacl:true,isinherited:false}]->()-[:Contains*1..]->(:Base{objectid:OID})\nWHERE NONE(ou in NODES(p) WHERE ou:OU AND ou.isaclprotected IS NOT NULL)\nRETURN p", - "revision": 1, - "resources": [], - "acknowledgements": [ - "Walter.Legowski, @SadProcessor" - ] - }, { "name": "Foreign Service Principals With any Abusable MS Graph App Role Assignment", "guid": "d7a180c8-5624-4fc1-a407-deeb2ad3054c", @@ -2648,9 +2636,9 @@ "Azure" ], "category": "Shortest Paths", - "description": null, + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole))\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, + "revision": 3, "resources": [], "acknowledgements": [] }, From 60cb0c31a1286af9d21c6cf4f7c130bce762621f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 14 Oct 2025 08:50:00 +0000 Subject: [PATCH 22/22] Update combined queries --- Queries.json | 2592 +++++++++++++++++++++++++------------------------- 1 file changed, 1296 insertions(+), 1296 deletions(-) diff --git a/Queries.json b/Queries.json index 31e0a06..e019153 100644 --- a/Queries.json +++ b/Queries.json @@ -1,56 +1,42 @@ [ { - "name": "Computers with the outgoing NTLM setting set to Deny all", - "guid": "a9ddca74-feeb-4dbf-8b0f-de08b3cfa8a6", + "name": "CA administrators and CA managers", + "guid": "fd35e3d8-0c74-4b5a-a847-c0dd1f1c9f19", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.restrictoutboundntlm = True\nRETURN c LIMIT 1000", + "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Shortest paths to systems trusted for unconstrained delegation", - "guid": "16a9e47b-45f8-4514-b409-771bb5186142", + "name": "Principals with passwords stored using reversible encryption", + "guid": "ab900835-b2b8-4674-87b4-8b5141e80439", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", - "description": null, - "query": "MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Computer))\nWHERE t.unconstraineddelegation = true AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] - }, - { - "name": "All service principals with Microsoft Graph privilege to grant arbitrary App Roles", - "guid": "e6d6b5da-89da-4514-a409-2d6e368397da", - "prebuilt": true, - "platforms": [ - "Azure" - ], - "category": "Microsoft Graph", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(:AZServicePrincipal)-[:AZMGGrantAppRoles]->(:AZTenant)\nRETURN p\nLIMIT 1000", + "query": "MATCH (n:Base)\nWHERE n.encryptedtextpwdallowed = true\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Accounts with SID History", - "guid": "8172d52c-a975-49bd-9180-5b6efc59c9ab", + "name": "Tier Zero users with email", + "guid": "9654c0d4-f1e8-4393-a2d1-53a5554a9de8", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH p=(:Base)-[:HasSIDHistory]->(:Base)\nRETURN p", + "description": "Tier Zero accounts with email access have an increased attack surface.", + "query": "MATCH (n)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.email <> \"\"\nAND n.enabled = true\nAND NOT toUpper(n.email) ENDS WITH \".ONMICROSOFT.COM\"\nAND NOT (\n (toUpper(n.email) STARTS WITH \"HEALTHMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERYMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERY\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHAPPROVAL\"\n OR toUpper(n.email) STARTS WITH \"FEDERATEDEMAIL\"\n OR toUpper(n.email) STARTS WITH \"SYSTEMMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MIGRATION.\")\n AND\n (n.name STARTS WITH \"SM_\"\n OR n.name STARTS WITH \"HEALTHMAILBOX\")\n)\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -58,57 +44,67 @@ ] }, { - "name": "Domain controllers with weak certificate binding enabled", - "guid": "a2444d99-10b5-412d-8fea-4b063cfddd2c", - "prebuilt": true, + "name": "Computers without Windows LAPS", + "guid": "7c50f724-c467-4005-8e3f-9a6ce1461db0", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.strongcertificatebindingenforcementraw = 0 OR s.strongcertificatebindingenforcementraw = 1\nRETURN p\nLIMIT 1000", + "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*WINDOWS (SERVER)? ?(10|11|2019|2022|2025).*'\nAND c.haslaps = false\nAND c.enabled = true\nRETURN c\nLIMIT 100", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Entra Users with Entra Admin Role direct eligibility", - "guid": "b87899ce-3a51-401a-ae39-ef271b566e3d", - "prebuilt": true, + "name": "Foreign Service Principals With Group Memberships", + "guid": "327ef6a5-bfa8-4c92-b35a-d3df85264a24", + "prebuilt": false, "platforms": [ "Azure" ], - "category": "General", - "description": null, - "query": "MATCH p = (:AZUser)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", + "category": "Azure Hygiene", + "description": "Review each to validate whether their presence is expected and whether the assigned group memberships are appropriate for the foreign service principal.", + "query": "MATCH p = (sp:AZServicePrincipal)-[:AZMemberOf]->(g:AZGroup)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(g.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" + ], + "acknowledgements": [ + "Stephen Hinck" + ] }, { - "name": "Servers where Domain Users can RDP", - "guid": "b9a330ae-1d89-44d4-8f74-9ca18e93eb92", - "prebuilt": true, + "name": "All incoming and local paths for a specific computer", + "guid": "1f67e538-19d4-4020-89c8-5b39b31571bd", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": null, - "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Domain Information", + "description": "All incoming and local paths for a specific computer; incoming from domain objects and paths local inside the computer.", + "query": "// Replace 'HOSTNAME' with the computer's shortname eg. 'SRV01', not FQDN\nMATCH p=(n:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base)\nWHERE m.name CONTAINS 'HOSTNAME'\nAND m.name CONTAINS '.' // Only see computer-related objects (eg. not AD Groups)\nRETURN p", + "revision": 2, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Unresolved SID with outbound control", - "guid": "4e8429f9-cba2-41e9-bac6-0c42f96b2c57", + "name": "Non-Tier Zero account with unconstrained delegation", + "guid": "e7e9a927-3f34-42c7-b921-d8bcf626011e", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Base)-[r]->(:Base)\nWHERE r.isacl\nAND n.name CONTAINS \"S-1-5-21-\" // Unresolved SID\nRETURN p\nLIMIT 1000", + "query": "MATCH (n:Base)\nWHERE n.unconstraineddelegation = true\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -116,40 +112,44 @@ ] }, { - "name": "All service principals with Microsoft Graph App Role assignments", - "guid": "74440269-eb41-476b-8dec-b4095569b029", - "prebuilt": true, + "name": "Circular AZ group memberships", + "guid": "b005669c-d8af-47ae-a0f1-4f36cd5334ab", + "prebuilt": false, "platforms": [ "Azure" ], - "category": "Microsoft Graph", - "description": null, - "query": "MATCH p=(:AZServicePrincipal)-[:AZMGAppRoleAssignment_ReadWrite_All|AZMGApplication_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGGroupMember_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory|AZMGServicePrincipalEndpoint_ReadWrite_All]->(:AZServicePrincipal)\nRETURN p\nLIMIT 1000", + "category": "Azure Hygiene", + "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", + "query": "MATCH p=(x:AZGroup)-[:AZMemberOf*2..]->(y:AZGroup)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Domains not mitigating CVE-2021-42291", - "guid": "02202726-d86d-46c2-891c-9770c635f76f", + "name": "Non-Tier Zero principals with BadSuccessor rights (no prerequisites check)", + "guid": "2b9fb71e-73ad-4061-a2df-40c7132b044d", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Checks the AttributeAuthorizationOnLDAPAdd flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \"^(.{0,27}|.{27}[^1].*)$\"\nRETURN n", + "category": "Dangerous Privileges", + "description": "Finds non-Tier Zero principals with BadSuccessor rights with no prerequisites check (DC2025 & KDC key).", + "query": "// Find OU control\nMATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p LIMIT 1000", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + "https://bsky.app/profile/specterops.io/post/3lpua65qeu22l" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Synced Entra Users with Entra Admin Roles group delegated eligibility", - "guid": "bc610e20-e5c0-41f3-9e8e-7378f87a3f71", + "name": "On-Prem Users synced to Entra Users that Own Entra Objects", + "guid": "4baf1026-e64c-4e31-afeb-2090b8090130", "prebuilt": true, "platforms": [ "Active Directory", @@ -157,63 +157,87 @@ ], "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwns]->(:AZBase)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Shortest paths from Domain Users to Tier Zero / High Value targets", - "guid": "469dc0f3-71b8-41b0-a03b-b4af7874665d", - "prebuilt": true, + "name": "Domains without Microsoft LAPS computers", + "guid": "f9b440b5-732c-4ed3-b6d2-83857db17e1a", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", + "category": "Domain Information", "description": null, - "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH (d:Domain)\nOPTIONAL MATCH (c:Computer)\nWHERE c.domainsid = d.objectid AND c.haslaps = true\nWITH d, COLLECT(c) AS computers\nWHERE SIZE(computers) = 0\nRETURN d", + "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Paths from Domain Users to Tier Zero / High Value targets", - "guid": "977bec40-565c-40b8-90c8-e3e122c291cd", - "prebuilt": true, + "name": "All GPOs applied to a specific Computer", + "guid": "1d75a21e-0d34-40c5-9360-281b60737d87", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Domain Information", + "description": "View all GPOs that are applied to any specific computer. This query identifies GPOs that are applied at both the Domain Level and the OU level, saving time in large Active Directory environments where GPO inheritance is complex. Replace \"COMPUTER_NAME\" with the target computer name or a substring. Note this does not take OU 'Block inheritance' and GPO 'No Override' into account.", + "query": "// Replace \"HOSTNAME/FQDN\" with the computer's\nMATCH p=(c:Computer)<-[:Contains*..]-(:Base)<-[:GPLink]-(:GPO)\nWHERE toLower(c.name) CONTAINS toLower(\"HOSTNAME/FQDN\")\nRETURN p", + "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/previous-versions/windows/desktop/Policy/overriding-and-blocking-group-policy" + ], + "acknowledgements": [ + "Adnan Ullah Khan, @auk0x01" + ] + }, + { + "name": "Accounts with SID History to a same-domain account", + "guid": "275d2d58-0cad-4cad-8103-e0874cece666", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE n.domainsid = m.domainsid\nRETURN p", + "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "All Global Administrators", - "guid": "94d7d765-6837-4eb8-aa33-e1c9ef262cdc", - "prebuilt": true, + "name": "Domains allowing authenticated domain enumeration", + "guid": "1e1e6fdd-6973-4547-906c-a494b5fbdcba", + "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "General", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(:AZBase)-[:AZHasRole*1..]->(t:AZRole)\nWHERE t.name =~ '(?i)Global Administrator.*'\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", + "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Large default group added to computer-local group", - "guid": "dde133d2-b4d2-4de9-a656-905f3bf066f3", + "name": "All Operators", + "guid": "3dfd0843-1ff9-4c21-aa67-feae08d109de", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Domain Information", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOfLocalGroup]->(m:ADLocalGroup)-[:LocalToComputer]->(:Computer)\nWHERE n.objectid =~ \".*-(S-1-5-11|S-1-1-0|S-1-5-32-545|S-1-5-7|-513|-515)$\" // Authenticated Users, Everyone, Users, Anonymous, Domain Users, Domain Computers\nAND NOT m.objectid =~ \".*-(545|574|554)$\" // Users, Certificate Service DCOM Access, Pre-Windows 2000 Compatible Access\nRETURN p", + "query": "MATCH p=(:Base)-[:MemberOf]->(n:Group)\nWHERE (\n n.objectid ENDS WITH 'S-1-5-32-551' OR // Backup Operators\n n.objectid ENDS WITH 'S-1-5-32-556' OR // Network Configuration Operators\n n.objectid ENDS WITH 'S-1-5-32-549' OR // Server Operators\n n.objectid ENDS WITH 'S-1-5-32-579' OR // Access Control Assistance Operators\n n.objectid ENDS WITH 'S-1-5-32-548' OR // Account Operators\n n.objectid ENDS WITH 'S-1-5-32-569' OR // Cryptographic Operators\n n.objectid ENDS WITH 'S-1-5-32-550' // Print Operators\n)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -221,329 +245,185 @@ ] }, { - "name": "Domains where any user can join a computer to the domain", - "guid": "421921fa-bc0f-4659-9680-b7481adcb132", + "name": "All coerce and NTLM relay edges", + "guid": "15c5ff3b-856c-44d1-a731-a8cb72512dd1", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (d:Domain)\nWHERE d.machineaccountquota > 0\nRETURN d", - "revision": 2, + "query": "MATCH p = (n:Base)-[:CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|CoerceAndRelayNTLMToADCS|CoerceAndRelayNTLMToSMB]->(:Base)\nRETURN p LIMIT 500", + "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/default-workstation-numbers-join-domain", - "https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/add-workstations-to-domain" + "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/" ], "acknowledgements": [] }, { - "name": "Computers with passwords older than the default maximum password age", - "guid": "185c5010-8d4f-4f9b-b24e-831707dddfca", + "name": "Entra ID SSO accounts not rolling Kerberos decryption key", + "guid": "1867abf8-08e3-4ea8-8f65-8366079d35c4", "prebuilt": false, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Active Directory Hygiene", - "description": "Machine account passwords are regularly changed for security purposes. Starting with Windows 2000-based computers, the machine account password automatically changes every 30 days.", - "query": "WITH 60 as rotation_period\nMATCH (n:Computer)\nWHERE n.pwdlastset < (datetime().epochseconds - (rotation_period * 86400)) // password not rotated\nAND n.enabled = true // enabled computers\nAND n.whencreated < (datetime().epochseconds - (rotation_period * 86400)) // exclude recently created computers\nAND n.lastlogontimestamp > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Replicated value)\nAND n.lastlogon > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Non-replicated value)\nRETURN n", + "category": "Configuration Weakness", + "description": "Microsoft highly recommends that you roll over the Entra ID SSO Kerberos decryption key at least every 30 days.", + "query": "MATCH (n:Computer)\nWHERE n.name STARTS WITH \"AZUREADSSOACC.\"\nAND n.pwdlastset < (datetime().epochseconds - (30 * 86400))\nRETURN n", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/disable-machine-account-password" + "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso-faq#how-can-i-roll-over-the-kerberos-decryption-key-of-the--azureadsso--computer-account-" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Computers not requiring inbound SMB signing", - "guid": "6b1fcfb6-b010-41a2-9d31-f9872fe994ff", - "prebuilt": true, + "name": "Domains with more than 50 Tier Zero accounts", + "guid": "f046e95a-5f84-4e83-bcda-6e83f3d8e21a", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nRETURN n", + "query": "MATCH (d:Domain)-[:Contains*1..]->(n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH d, COUNT(n) AS adminCount\nWHERE adminCount > 50\nRETURN d", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated)", - "guid": "609d648f-7fb8-42d3-ad99-626f9ce1f121", - "prebuilt": true, - "platforms": [ - "Active Directory", - "Azure" - ], - "category": "Cross Platform Attack Paths", - "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Principals with passwords stored using reversible encryption", - "guid": "ab900835-b2b8-4674-87b4-8b5141e80439", - "prebuilt": true, + "name": "Domains not mitigating CVE-2021-42291", + "guid": "02202726-d86d-46c2-891c-9770c635f76f", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (n:Base)\nWHERE n.encryptedtextpwdallowed = true\nRETURN n", + "description": "Checks the AttributeAuthorizationOnLDAPAdd flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \"^(.{0,27}|.{27}[^1].*)$\"\nRETURN n", "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Enrollment rights on published ESC2 certificate templates", - "guid": "ebc77984-1ceb-4ed2-a395-ce1067847941", - "prebuilt": true, - "platforms": [ - "Active Directory" - ], - "category": "Active Directory Certificate Services", - "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(c:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE c.requiresmanagerapproval = false\nAND (c.effectiveekus = [''] OR '2.5.29.37.0' IN c.effectiveekus OR c.effectiveekus IS NULL)\nAND (c.authorizedsignatures = 0 OR c.schemaversion = 1)\nRETURN p\nLIMIT 1000", - "revision": 2, "resources": [ - "https://posts.specterops.io/certified-pre-owned-d95910965cd2", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" ], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "PKI hierarchy", - "guid": "928acc23-ee4c-40a5-bde7-64c05cc1491d", + "name": "Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8)", + "guid": "1c1435b1-bad0-49f2-ba7d-932e047c0af4", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p=()-[:HostsCAService|IssuedSignedBy|EnterpriseCAFor|RootCAFor|TrustedForNTAuth|NTAuthStoreFor*..]->(:Domain)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.hasvulnerableendpoint = True\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled", - "guid": "96e70597-2d74-4503-a624-f1e30b642894", + "name": "Foreign principals in Tier Zero / High Value targets", + "guid": "95bec736-86ef-4017-8465-9b9b66548b17", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Certificate Services", + "category": "Azure Hygiene", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", + "query": "MATCH (n:AZServicePrincipal)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT toUpper(n.appownerorganizationid) = toUpper(n.tenantid)\nAND n.appownerorganizationid CONTAINS '-'\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Entra Users with Entra Admin Roles group delegated eligibility", - "guid": "2e36c81b-25ed-40ba-afec-5f5f6443e095", + "name": "On-Prem Users synced to Entra Users with Azure RM Roles (group delegated)", + "guid": "e4f2eada-8a89-4ba9-89eb-abbee4efbc7a", "prebuilt": true, "platforms": [ + "Active Directory", "Azure" ], - "category": "General", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers not owned by Tier Zero", - "guid": "99d29ded-223a-442b-a0e0-f8b5694c6441", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Dangerous Privileges", - "description": null, - "query": "MATCH p=(n:Base)-[:Owns]->(:Computer)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", - "revision": 2, - "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Shortest paths to Azure Subscriptions", - "guid": "4785b305-c101-461c-80fc-3fb3ff67a8ce", + "name": "Shortest paths from Owned objects", + "guid": "e370a01d-c129-4f19-b88d-9479cbe00028", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], "category": "Shortest Paths", - "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", - "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription))\nWHERE s<>t\nRETURN p\nLIMIT 1000", + "description": null, + "query": "MATCH p=shortestPath((s:Base)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE ((s:Tag_Owned) OR COALESCE(s.system_tags, '') CONTAINS 'owned')\nAND s<>t\nRETURN p\nLIMIT 1000", "revision": 3, "resources": [], "acknowledgements": [] }, { - "name": "Kerberoastable users with most admin privileges", - "guid": "9907b208-494c-4ba6-846d-485e6de14e17", + "name": "Kerberoastable members of Tier Zero / High Value groups", + "guid": "e6da7800-ae06-41cb-80a6-d5421ab2143a", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Kerberos Interaction", "description": null, - "query": "MATCH (u:User)\nWHERE u.hasspn = true\n AND u.enabled = true\n AND NOT u.objectid ENDS WITH '-502'\n AND NOT COALESCE(u.gmsa, false) = true\n AND NOT COALESCE(u.msa, false) = true\nMATCH (u)-[:MemberOf|AdminTo*1..]->(c:Computer)\nWITH DISTINCT u, COUNT(c) AS adminCount\nRETURN u\nORDER BY adminCount DESC\nLIMIT 100", - "revision": 1, + "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true \nRETURN u\nLIMIT 100", + "revision": 2, "resources": [ "https://attack.mitre.org/techniques/T1558/003/" ], "acknowledgements": [] }, { - "name": "On-Prem Users synced to Entra Users that Own Entra Objects", - "guid": "4baf1026-e64c-4e31-afeb-2090b8090130", + "name": "Enrollment rights on published enrollment agent certificate templates", + "guid": "8483bf5b-89f1-4723-abb2-c48295f6393e", "prebuilt": true, - "platforms": [ - "Active Directory", - "Azure" - ], - "category": "Cross Platform Attack Paths", - "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwns]->(:AZBase)\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Domains allowing unauthenticated NSPI RPC binds", - "guid": "a950fdab-5934-4c69-a88b-e2e0e3da9d52", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Active Directory Hygiene", - "description": "Checks the fAllowAnonNSPI flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{7}[^0].*\"\nRETURN n", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "All incoming and local paths for a specific computer", - "guid": "1f67e538-19d4-4020-89c8-5b39b31571bd", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Domain Information", - "description": "All incoming and local paths for a specific computer; incoming from domain objects and paths local inside the computer.", - "query": "// Replace 'HOSTNAME' with the computer's shortname eg. 'SRV01', not FQDN\nMATCH p=(n:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base)\nWHERE m.name CONTAINS 'HOSTNAME'\nAND m.name CONTAINS '.' // Only see computer-related objects (eg. not AD Groups)\nRETURN p", - "revision": 2, - "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Tier Zero computers with the WebClient running", - "guid": "27a6f917-8ed4-4e2e-9b38-41a4b6de1b14", - "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c LIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE '1.3.6.1.4.1.311.20.2.1' IN ct.effectiveekus\nOR '2.5.29.37.0' IN ct.effectiveekus\nOR SIZE(ct.effectiveekus) = 0\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Non-Tier Zero object with excessive control", - "guid": "944cecfe-519b-4318-b226-e8520161b454", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Dangerous Privileges", - "description": "Returns non-Tier Zero principals with >= 1000 direct rights to other principals. This does not include rights from group memberships.", - "query": "MATCH (n:Base)-[r:AD_ATTACK_PATHS]->(m:Base)\nWHERE NOT r:MemberOf\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH n, COLLECT(DISTINCT(m)) AS endNodes\nWHERE SIZE(endNodes) >= 1000\nRETURN n", - "revision": 4, - "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Devices with unsupported operating systems", - "guid": "e3f2b53a-7ce6-4e52-9c74-68b69338288b", + "name": "Entra Users with Entra Admin Role approval (group delegated)", + "guid": "b70a6512-21e1-4d6e-926a-fba44646085d", "prebuilt": true, "platforms": [ "Azure" ], - "category": "Azure Hygiene", + "category": "General", "description": null, - "query": "MATCH (n:AZDevice)\nWHERE n.operatingsystem CONTAINS 'WINDOWS'\nAND n.operatingsystemversion =~ '(10.0.19044|10.0.22000|10.0.19043|10.0.19042|10.0.19041|10.0.18363|10.0.18362|10.0.17763|10.0.17134|10.0.16299|10.0.15063|10.0.14393|10.0.10586|10.0.10240|6.3.9600|6.2.9200|6.1.7601|6.0.6200|5.1.2600|6.0.6003|5.2.3790|5.0.2195).?.*'\nRETURN n\nLIMIT 100", + "query": "MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Foreign Service Principals With an EntraID Admin Role", - "guid": "b6235820-4e0d-4dfa-af5b-729b5644feb5", - "prebuilt": false, - "platforms": [ - "Azure" - ], - "category": "Dangerous Privileges", - "description": "Entra ID admin roles grant significant control over a tenant environment, even if the role is not a default Tier Zero / High Value role", - "query": "MATCH p = (sp:AZServicePrincipal)-[:AZHasRole]->(r:AZRole)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(sp.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [ - "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" - ], - "acknowledgements": [ - "Stephen Hinck" - ] - }, - { - "name": "Circular AZ group memberships", - "guid": "b005669c-d8af-47ae-a0f1-4f36cd5334ab", - "prebuilt": false, - "platforms": [ - "Azure" - ], - "category": "Azure Hygiene", - "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", - "query": "MATCH p=(x:AZGroup)-[:AZMemberOf*2..]->(y:AZGroup)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", - "revision": 1, - "resources": [ - "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Non-default delegation on MicrosoftDNS container", - "guid": "008792c0-4458-46a1-a10d-50cdaf95af1e", + "name": "Domains affected by Exchange privilege escalation risk", + "guid": "f2d09c94-b6f2-4901-9a2d-f8bacd61edc7", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Base)-[r]->(m:Container)\nWHERE m.distinguishedname STARTS WITH \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\"\nAND NOT n.name STARTS WITH \"DNSADMINS@\"\nAND NOT n.objectid =~ \"-(512|544|519|9)$\"\nAND r.isacl\nRETURN p", + "query": "MATCH p=(n:Group)-[r:WriteDacl|ForceChangePassword|AddMember]->(m:Base)\nWHERE n.name STARTS WITH \"EXCHANGE \"\nAND ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -551,93 +431,47 @@ ] }, { - "name": "Object name conflict", - "guid": "c561c4f8-ea45-453f-85a2-3fc2e20e7f8c", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Active Directory Hygiene", - "description": "When two objects are created with the same Relative Distinguished Name (RDN) in the same parent Organizational Unit or container, the conflict is recognized by the system when one of the new objects replicates to another domain controller. When this happens, one of the objects is renamed with 'CNF'", - "query": "MATCH (n:Base)\nWHERE n.distinguishedname CONTAINS 'CNF:'\nRETURN n", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/archive/technet-wiki/15435.active-directory-duplicate-object-name-resolution" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Entra Users with Entra Admin Role approval (direct)", - "guid": "74d7993c-24af-4df7-8402-5c6fb22d088c", - "prebuilt": true, - "platforms": [ - "Azure" - ], - "category": "General", - "description": null, - "query": "MATCH p = (:AZUser)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", - "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Shortest paths from Azure Applications to Tier Zero / High Value targets", - "guid": "60ff7c58-a98e-4bc1-9e32-8378d2db0c43", - "prebuilt": true, - "platforms": [ - "Azure" - ], - "category": "Shortest Paths", - "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", - "query": "MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 3, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Domains without Protected Users group", - "guid": "8c3e0811-a31b-45b4-a29d-1dce80fa2c5f", + "name": "Circular AD group memberships", + "guid": "fcaa5ffc-3d22-481f-a2a2-18a4eec30058", "prebuilt": false, "platforms": [ "Active Directory" - ], - "category": "Domain Information", - "description": null, - "query": "MATCH (n:Domain)\nWHERE n.collected = true\nOPTIONAL MATCH (m:Group)\nWHERE m.name ENDS WITH n.name\nAND m.objectid ENDS WITH '-525'\nWITH n, m\nWHERE m IS NULL\nRETURN n", + ], + "category": "Active Directory Hygiene", + "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", + "query": "MATCH p=(x:Group)-[:MemberOf*2..]->(y:Group)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", "revision": 1, - "resources": [], + "resources": [ + "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "KRBTGT accounts with passwords not rotated in over 1 year", - "guid": "1b3ae310-ffa7-4ce5-a37f-6111aef600c8", - "prebuilt": false, + "name": "Map domain trusts", + "guid": "268d3d26-5bc2-4820-a6ed-09d20f3d5413", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "MATCH (n:User)\nWHERE (n.objectid ENDS WITH '-502'\nOR n.name STARTS WITH 'AZUREADKERBEROS.'\nOR n.name STARTS WITH 'KRBTGT_AZUREAD@')\nAND n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nRETURN n", + "query": "MATCH p = (:Domain)-[:SameForestTrust|CrossForestTrust]->(:Domain)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Users with non-expiring passwords", - "guid": "212c2a98-53d9-4dfa-b177-42c601452dd1", + "name": "Locations of Owned objects", + "guid": "350b8b8a-ea4c-44f3-874b-c9316de6c41b", "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "General", "description": null, - "query": "MATCH (u:User)\nWHERE u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", + "query": "MATCH p = (t:AZBase)<-[:AZContains*1..]-(:AZTenant)\nWHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -645,30 +479,29 @@ ] }, { - "name": "Synced Entra Users with Entra Admin Role direct eligibility", - "guid": "ea82e359-725c-4881-83e9-35007e859cf5", + "name": "Enrollment rights on published certificate templates with no security extension", + "guid": "0677b70c-4e04-4e89-a6a2-f5764604a6a7", "prebuilt": true, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.nosecurityextension = true\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Domain migration groups", - "guid": "f39c4953-ae92-4d67-bb50-eb1a161d4d3f", + "name": "All Schema Admins", + "guid": "76d8e61d-7a86-40ff-8a85-fd37f1e2563f", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Domain Information", "description": null, - "query": "MATCH (n:Group)\nWHERE n.name CONTAINS \"$$$@\"\nRETURN n", + "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE (n:User OR n:Computer)\nAND m.objectid ENDS WITH \"-518\" // Schema Admins\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -676,85 +509,87 @@ ] }, { - "name": "Tier Zero / High Value external Entra ID users", - "guid": "20e07417-d286-4dca-a962-568f2b262f65", + "name": "All service principals with Microsoft Graph App Role assignments", + "guid": "74440269-eb41-476b-8dec-b4095569b029", "prebuilt": true, "platforms": [ "Azure" ], - "category": "Azure Hygiene", + "category": "Microsoft Graph", "description": null, - "query": "MATCH (n:AZUser)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.name CONTAINS '#EXT#@'\nRETURN n\nLIMIT 100", + "query": "MATCH p=(:AZServicePrincipal)-[:AZMGAppRoleAssignment_ReadWrite_All|AZMGApplication_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGGroupMember_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory|AZMGServicePrincipalEndpoint_ReadWrite_All]->(:AZServicePrincipal)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Shortest paths to privileged roles", - "guid": "3dc73dd8-4873-4aeb-a88f-56a58c77f512", + "name": "Map OU structure", + "guid": "8f14084b-5065-43d8-865a-a6ac52da25d1", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Shortest Paths", - "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", - "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole))\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator|Privileged Role Administrator' AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 3, + "category": "Domain Information", + "description": null, + "query": "MATCH p = (:Domain)-[:Contains*1..]->(:OU)\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Public Key Services container", - "guid": "07e94492-71aa-4665-ab8c-e7aec25906cd", + "name": "Enrollment rights on CertTemplates with OIDGroupLink", + "guid": "140a68eb-d21c-4b75-971f-309225fb2d75", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (c:Container)-[:Contains*..]->(:Base)\nWHERE c.distinguishedname starts with 'CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC='\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:ExtendedByPolicy]->(:IssuancePolicy)-[:OIDGroupLink]->(:Group)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Shortest paths from Entra Users to Tier Zero / High Value targets", - "guid": "58089b28-54e0-4fd2-bf66-3db480b00e2f", - "prebuilt": true, + "name": "Unresolved SID with outbound control", + "guid": "4e8429f9-cba2-41e9-bac6-0c42f96b2c57", + "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Shortest Paths", - "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", - "query": "MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 3, + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH p=(n:Base)-[r]->(:Base)\nWHERE r.isacl\nAND n.name CONTAINS \"S-1-5-21-\" // Unresolved SID\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Computers with membership in Protected Users", - "guid": "a26372f4-2e92-49f6-8993-6657fbc1569a", + "name": "Principals with foreign domain group membership", + "guid": "8fb3214a-5a75-4ecd-b293-c121abd94b4b", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (:Base)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-525'\nRETURN p LIMIT 1000", - "revision": 2, + "query": "MATCH p=(s:Base)-[:MemberOf]->(t:Group)\nWHERE s.domainsid<>t.domainsid\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Accounts with SID History to a non-existent domain", - "guid": "2710401a-c4c2-4d2c-9edb-d7625045f2e8", + "name": "Tier Zero computers at risk of constrained delegation", + "guid": "8641e593-f2f2-48ba-bd45-fbc86e9f632a", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (d:Domain)\nWITH collect(d.objectid) AS domainSIDs\nMATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE NOT n.domainsid IN domainSIDs\nRETURN p", + "query": "MATCH p = (n:Computer)<-[:AllowedToDelegate]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -762,33 +597,15 @@ ] }, { - "name": "Foreign Service Principals With Group Memberships", - "guid": "327ef6a5-bfa8-4c92-b35a-d3df85264a24", - "prebuilt": false, - "platforms": [ - "Azure" - ], - "category": "Azure Hygiene", - "description": "Review each to validate whether their presence is expected and whether the assigned group memberships are appropriate for the foreign service principal.", - "query": "MATCH p = (sp:AZServicePrincipal)-[:AZMemberOf]->(g:AZGroup)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(g.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [ - "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" - ], - "acknowledgements": [ - "Stephen Hinck" - ] - }, - { - "name": "Tier Zero computers with unsupported operating systems", - "guid": "a87b558c-5746-4a90-9f83-c86e7b924a52", + "name": "Domains with a single-point-of-failure Domain Controller", + "guid": "3359a295-7cfd-491f-976b-c5a68647431c", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c\nLIMIT 100", + "query": "MATCH (n:Group)<-[:MemberOf]-(:Computer)\nWHERE n.objectid ENDS WITH '-516'\nWITH n, COUNT(n) AS dcCount\nWHERE dcCount = 1\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ @@ -796,325 +613,302 @@ ] }, { - "name": "Entra Users with Entra Admin Role approval (group delegated)", - "guid": "b70a6512-21e1-4d6e-926a-fba44646085d", + "name": "Shortest paths from Owned objects to Tier Zero", + "guid": "dfaa8e8f-2c79-4e92-a291-b1347f6e83b0", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "General", - "description": null, - "query": "MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", - "revision": 1, + "category": "Shortest Paths", + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "query": "// MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE\nMATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 4, "resources": [], "acknowledgements": [] }, { - "name": "Map OU structure", - "guid": "8f14084b-5065-43d8-865a-a6ac52da25d1", + "name": "Shortest paths from Domain Users to Tier Zero / High Value targets", + "guid": "469dc0f3-71b8-41b0-a03b-b4af7874665d", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Shortest Paths", "description": null, - "query": "MATCH p = (:Domain)-[:Contains*1..]->(:OU)\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "ESC8-vulnerable Enterprise CAs", - "guid": "60881923-296c-4702-adf7-a4f059dc9bb8", + "name": "Principals with DES-only Kerberos authentication", + "guid": "d03ea1ef-70f0-439b-b1ef-d7f94ceb2af3", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:EnterpriseCA)\nWHERE n.hasvulnerableendpoint=true\nRETURN n", + "query": "MATCH (n:Base)\nWHERE n.enabled = true\nAND n.usedeskeyonly = true\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "ACEs across trusts", - "guid": "c902d3b4-1a75-4335-acd7-28246dab746d", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Domain Information", - "description": "ACEs granted across a trust, the ACEs are set on trusting objects and the rights are granted to objects from trusted domains.", - "query": "MATCH p=(trustedDomainPrincipal:Base)-[r]->(trustingDomainPrincipal:Base)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nAND r.isacl\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] - }, - { - "name": "Domain Controllers allowing NTLMv1 or LM authentication", - "guid": "4b42513c-f89d-47ff-8d98-908af49d2b48", - "prebuilt": false, + "name": "Synced Entra Users with Entra Admin Role approval (group delegated)", + "guid": "ead56ecb-fb88-427c-8f39-75e774bb9a0a", + "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "NTLM Relay Attacks", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (dc:Computer)\nWHERE dc.isdc = true\nAND (dc.lmcompatibilitylevel IS NOT NULL AND NOT dc.lmcompatibilitylevel = 5)\nRETURN dc", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Computers with the WebClient running", - "guid": "51107ad1-f0bc-43d3-a561-5cee471ca196", + "name": "Domain controllers with weak certificate binding enabled", + "guid": "a2444d99-10b5-412d-8fea-4b063cfddd2c", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nRETURN c LIMIT 1000", + "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.strongcertificatebindingenforcementraw = 0 OR s.strongcertificatebindingenforcementraw = 1\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Workstations where Domain Users can RDP", - "guid": "9486e0e6-2617-4595-b969-cf57ca21fc86", - "prebuilt": true, + "name": "Computer owners who can obtain LAPS passwords", + "guid": "92aa81d6-b08e-4abb-ae39-ecbe5735a74c", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", - "description": null, - "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND NOT toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", + "description": "Creators of computer objects get abusable rights on the computer object. If the owner is not explicitly granted ReadLAPSPassword they can still compromise the computer with the abusable owner rights.", + "query": "MATCH p = (c:Computer)<-[:GenericAll|Owns|WriteDacl|WriteOwner|AllExtendedRights]-(n:User)\nWHERE c.haslaps = true AND c.ownersid = n.objectid\nRETURN p", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "AdminSDHolder protected Accounts and Groups", - "guid": "5ee2f40e-a55c-4140-ab8a-91746ba3752b", - "prebuilt": false, + "name": "Potential GPO 'Apply' misconfiguration", + "guid": "f5f2455e-afdc-4708-9a34-98f539ce52d8", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Objects whose permissions are set by SDProp to the template AdminSDHolder object as per MS-ADTS 3.1.1.6.1.2 Protected Objects. Does not exclude objects if specified in dSHeuristics dwAdminSDExMask", - "query": "MATCH (n:Base)-[:MemberOf*0..]->(m:Group)\nWHERE (\n n.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Groups\n OR m.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Members of groups\n OR n.objectid =~ \".*-(500|502|516|521)$\" // Direct objects\n)\nRETURN n", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a0d0b4fa-2895-4c64-b182-ba64ad0f84b8", - "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory" - ], + "category": "Dangerous Privileges", + "description": "In Active Directory, GPO's are applied to objects in the Group Policy Management Console by ticking \"Allow - Apply group policy\", but administrators can mistakenly tick \"Allow - Write\" or \"Allow - Full Control\" resulting in a misconfigured GPO that allows a principal to compromise other principals the GPO also applies to. Results are potential risks and must be audited for for correctness.", + "query": "MATCH p=(n:Base)-[:GenericAll|GenericWrite]->(g:GPO)\n\n// Exclude Enterprise Admins and Domain Admins\nWHERE NOT n.objectid =~ \"-(519|512)$\"\n\n// Exclude unresolved SIDs\nAND NOT (n.distinguishedname IS NULL)\n\n// Asset description may reveal if it's a delegation group (false-positive) or a filter group (true-positive)\n//AND n.description is not null\n//AND n.description =~ \"(?i)apply\"\n\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Accounts with weak password storage encryption", - "guid": "8bd6fcf2-3f3c-414c-857a-4caf28e49def", - "prebuilt": true, + "name": "Domains with List Object mode enabled", + "guid": "05e2a94b-5ee6-47ec-b715-3982f30af01b", + "prebuilt": false, "platforms": [ "Active Directory" - ], - "category": "Active Directory Hygiene", - "description": "Accounts with passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", - "query": "MATCH (n:Base)\nWHERE n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008 release\nRETURN n\nLIMIT 100", - "revision": 2, + ], + "category": "Domain Information", + "description": "Checks the fDoListObject flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{2}[^0].*\"\nRETURN n", + "revision": 1, "resources": [ - "https://techcommunity.microsoft.com/blog/coreinfrastructureandsecurityblog/decrypting-the-selection-of-supported-kerberos-encryption-types/1628797" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Tier Zero AD principals synchronized with Entra ID", - "guid": "a8b6ec67-21aa-4dd2-8906-47bb81bf5262", + "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (direct)", + "guid": "de717635-d31f-4fbd-930b-b4dac0f22118", "prebuilt": true, "platforms": [ + "Active Directory", "Azure" ], - "category": "Azure Hygiene", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (ENTRA:AZBase)\nMATCH (AD:Base)\nWHERE ((AD:Tag_Tier_Zero) OR COALESCE(AD.system_tags, '') CONTAINS 'admin_tier_0')\nAND ENTRA.onpremsyncenabled = true\nAND ENTRA.onpremid = AD.objectid\nRETURN ENTRA\n// Replace 'RETURN ENTRA' with 'RETURN AD' to see the corresponding AD principals\nLIMIT 100", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Cross-forest trusts with abusable configuration", - "guid": "5cf1f354-80d4-420e-bc4b-424fabc21a56", - "prebuilt": true, + "name": "Enabled built-in guest user accounts", + "guid": "bb0f620d-6a55-4413-ac74-4c82905e8598", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Domain)-[:CrossForestTrust|SpoofSIDHistory|AbuseTGTDelegation]-(m:Domain)\nWHERE (n)-[:SpoofSIDHistory|AbuseTGTDelegation]-(m)\nRETURN p", + "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-501\"\nAND n.enabled = true\nRETURN n", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "DCs vulnerable to NTLM relay to LDAP attacks", - "guid": "3f87e0b0-fc06-4986-a94c-e08781253dc8", - "prebuilt": true, + "name": "Large default groups with outbound control of OUs", + "guid": "310b3626-f8e6-4ab0-832c-72df6048597f", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (dc:Computer)-[:DCFor]->(:Domain)\nWHERE (dc.ldapavailable = True AND dc.ldapsigning = False)\nOR (dc.ldapsavailable = True AND dc.ldapsepa = False)\nOR (dc.ldapavailable = True AND dc.ldapsavailable = True AND dc.ldapsigning = False and dc.ldapsepa = True)\nRETURN p", + "query": "MATCH p=(n:Group)-[]->(:OU)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Tier Zero / High Value enabled users not requiring smart card authentication", - "guid": "867f9f17-c149-4c4b-ad84-9a807622ff8c", + "name": "Enrollment rights on published ESC1 certificate templates", + "guid": "2af855bc-f48f-4b22-9839-627d8231e425", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.enabled = true\nAND u.smartcardrequired = false\nAND NOT u.name STARTS WITH 'MSOL_' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'PROVAGENTGMSA' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'ADSYNCMSA_' // Removes false positive, Entra sync\nRETURN u", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = True\nAND ct.requiresmanagerapproval = False\nAND (ct.authorizedsignatures = 0 OR ct.schemaversion = 1)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Entra Users synced from On-Prem Users added to Domain Admins group", - "guid": "62722d5f-bd93-4d11-beeb-9be261827e4e", + "name": "Users which do not require password to authenticate", + "guid": "23bdc2ad-6739-4b2b-85d3-258e3f424eb2", "prebuilt": true, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:AZUser)-[:SyncedToADUser]->(:User)-[:MemberOf]->(t:Group)\nWHERE t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", + "query": "MATCH (u:User)\nWHERE u.passwordnotreqd = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Computers with unsupported operating systems", - "guid": "d06d3b14-0318-4fa9-9639-4b79ccaf3c2c", + "name": "Domain Admins logons to non-Domain Controllers", + "guid": "e2f3fd0a-1df2-4089-b0a4-272ad6e369a9", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nRETURN c\nLIMIT 100", + "query": "MATCH (s)-[:MemberOf*0..]->(g:Group)\nWHERE g.objectid ENDS WITH '-516'\nWITH COLLECT(s) AS exclude\nMATCH p = (c:Computer)-[:HasSession]->(:User)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-512' AND NOT c IN exclude\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Non-Tier Zero account with 'Admin Count' flag", - "guid": "e7f703b3-5dba-4aef-8346-4d589be2c828", + "name": "Kerberos-enabled service accounts without AES encryption support", + "guid": "cb8cf96e-21c9-422b-9439-390a13446ca6", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Accounts that were members of AD's built-in administrative groups, thus had the 'AdminCount' flag set, but are not currently in those groups and not tagged as Tier Zero. These accounts could still be highly privileged by other means.", - "query": "MATCH (n:Base)\nWHERE (n:User OR n:Computer)\nAND n.admincount = true\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT n.objectid ENDS WITH '-502' // KRBTGT user\nAND NOT n.objectid ENDS WITH '-500' // Administrator user\nOPTIONAL MATCH (n)-[:MemberOf]->(g:Group)\nWHERE g.objectid ENDS WITH '-512' // Domain Admins\nOR g.objectid ENDS WITH '-548' // Account Operators\nOR g.objectid ENDS WITH '-544' // Administrators\nOR g.objectid ENDS WITH '-551' // Backup Operators\nOR g.objectid ENDS WITH '-516' // Domain Controllers\nOR g.objectid ENDS WITH '-519' // Enterprise Admins\nOR g.objectid ENDS WITH '-527' // Enterprise Key Admins\nOR g.objectid ENDS WITH '-526' // Key Admins\nOR g.objectid ENDS WITH '-550' // Print Operators\nOR g.objectid ENDS WITH '-521' // Read-Only Domain Controllers\nOR g.objectid ENDS WITH '-552' // Replicators\nOR g.objectid ENDS WITH '-518' // Schema Admins\nOR g.objectid ENDS WITH '-549' // Server Operators\nWITH n, g\nWHERE g IS NULL\nRETURN n", + "description": "Accounts without Kerberos AES encryption support, or passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", + "query": "MATCH (n:Base)\nWHERE n.hasspn = true\nAND ((\n n.supportedencryptiontypes <> ['Not defined']\n OR n.supportedencryptiontypes <> []\n OR NONE(type IN n.supportedencryptiontypes WHERE type CONTAINS 'AES128' OR type CONTAINS 'AES256')\n)\nOR (n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008\nAND NOT n.pwdlastset IN [-1.0, 0.0]\n))\nRETURN n\nLIMIT 100", "revision": 2, - "resources": [ - "https://learn.microsoft.com/en-us/windows/win32/adschema/a-admincount", - "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#protected-groups" - ], + "resources": [], "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk", - "kaasimir, @kaasimir" + "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Tier Zero computers with passwords older than the default maximum password age", - "guid": "b6d6d0bf-130e-4719-996b-adc29bba36e9", + "name": "ACEs across trusts", + "guid": "c902d3b4-1a75-4335-acd7-28246dab746d", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (n:Computer)\nWHERE n.enabled = true\nAND n.whencreated < (datetime().epochseconds - (60 * 3 * 86400))\nAND n.pwdlastset < (datetime().epochseconds - (60 * 3 * 86400))\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", - "revision": 2, + "category": "Domain Information", + "description": "ACEs granted across a trust, the ACEs are set on trusting objects and the rights are granted to objects from trusted domains.", + "query": "MATCH p=(trustedDomainPrincipal:Base)-[r]->(trustingDomainPrincipal:Base)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nAND r.isacl\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Computers with non-default Primary Group membership", - "guid": "5862dc4e-6f6f-4321-9474-d838968495ed", + "name": "Usage of built-in domain Administrator account", + "guid": "35b1206f-871b-44aa-a601-c5258060dfcf", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-515\" // Domain Computers\nAND NOT n.isdc = true\nAND NOT n.isreadonlydc = true\nAND r.isprimarygroup = true\nRETURN p", - "revision": 2, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ada3/e12954a4-6865-4432-94e6-00c310ca87c0", - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5dbcf875-e802-4357-a6e2-1bdff19ff9b5", - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/73d11ea7-e634-453e-944d-559654cc91c5" - ], + "description": "Usage of Active Directory's built-in Administrator account is a sign that the account is not only used for break-glass purposes.", + "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-500\"\nAND (\n n.lastlogontimestamp > (datetime().epochseconds - (60 * 86400)) OR\n n.lastlogon > (datetime().epochseconds - (60 * 86400))\n)\nAND NOT n.whencreated > (datetime().epochseconds - (60 * 86400))\nRETURN n", + "revision": 1, + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Principals with weak supported Kerberos encryption types", - "guid": "ca329573-2157-41da-ab17-4d122c54b11d", + "name": "Synced Entra Users with Entra Admin Roles group delegated eligibility", + "guid": "bc610e20-e5c0-41f3-9e8e-7378f87a3f71", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Active Directory Hygiene", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (u:Base)\nWHERE 'DES-CBC-CRC' IN u.supportedencryptiontypes\nOR 'DES-CBC-MD5' IN u.supportedencryptiontypes\nOR 'RC4-HMAC-MD5' IN u.supportedencryptiontypes\nRETURN u", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Locations of Owned objects", - "guid": "350b8b8a-ea4c-44f3-874b-c9316de6c41b", - "prebuilt": false, + "name": "Computers with membership in Protected Users", + "guid": "a26372f4-2e92-49f6-8993-6657fbc1569a", + "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "General", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p = (t:AZBase)<-[:AZContains*1..]-(:AZTenant)\nWHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p = (:Base)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-525'\nRETURN p LIMIT 1000", + "revision": 2, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Tier Zero accounts that can be delegated", - "guid": "4316eaf1-6af0-4879-8f55-ac2633a711c3", + "name": "Non-default members in Pre-Windows 2000 Compatible Access", + "guid": "091995b9-7254-473a-996f-6b8368d20431", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Kerberos Interaction", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (m:Base)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nAND m.enabled = true\nAND m.sensitive = false\nOPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)\nWHERE g.objectid ENDS WITH '-525'\nWITH m, COLLECT(n) AS matchingNs\nWHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)\nRETURN m", + "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE NOT n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND NOT (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nAND NOT n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1122,33 +916,31 @@ ] }, { - "name": "Collection health of DC Registry Data", - "guid": "3f0fa2f3-fbdf-42c0-9e7d-97e689009161", + "name": "Domain migration groups", + "guid": "f39c4953-ae92-4d67-bb50-eb1a161d4d3f", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Domain Information", - "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured DC to potentially a full forest compromise by any principal. DCs returned by this query have not been collected.", - "query": "MATCH p=(:Domain)<-[:DCFor]-(c:Computer)\nWHERE c.strongcertificatebindingenforcementraw IS NULL\n// Exclude inactive DCs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", + "description": null, + "query": "MATCH (n:Group)\nWHERE n.name CONTAINS \"$$$@\"\nRETURN n", "revision": 1, - "resources": [ - "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#dc-registry" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Smart card accounts with passwords not rotated in over 1 year", - "guid": "7e56f2e7-79c3-4f0d-aa3e-14cf3de7ab73", + "name": "Non-default delegation on MicrosoftDNS container", + "guid": "008792c0-4458-46a1-a10d-50cdaf95af1e", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nAND n.enabled = true\nAND n.smartcardrequired = true\nRETURN n", + "query": "MATCH p=(n:Base)-[r]->(m:Container)\nWHERE m.distinguishedname STARTS WITH \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\"\nAND NOT n.name STARTS WITH \"DNSADMINS@\"\nAND NOT n.objectid =~ \"-(512|544|519|9)$\"\nAND r.isacl\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1156,334 +948,389 @@ ] }, { - "name": "Domain controllers with UPN certificate mapping enabled", - "guid": "799ea3ce-572b-4594-98c4-041aa2ae6176", - "prebuilt": true, + "name": "Non-Tier Zero account with 'Admin Count' flag", + "guid": "e7f703b3-5dba-4aef-8346-4d589be2c828", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", - "description": null, - "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.certificatemappingmethodsraw IN [4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31]\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Active Directory Hygiene", + "description": "Accounts that were members of AD's built-in administrative groups, thus had the 'AdminCount' flag set, but are not currently in those groups and not tagged as Tier Zero. These accounts could still be highly privileged by other means.", + "query": "MATCH (n:Base)\nWHERE (n:User OR n:Computer)\nAND n.admincount = true\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT n.objectid ENDS WITH '-502' // KRBTGT user\nAND NOT n.objectid ENDS WITH '-500' // Administrator user\nOPTIONAL MATCH (n)-[:MemberOf]->(g:Group)\nWHERE g.objectid ENDS WITH '-512' // Domain Admins\nOR g.objectid ENDS WITH '-548' // Account Operators\nOR g.objectid ENDS WITH '-544' // Administrators\nOR g.objectid ENDS WITH '-551' // Backup Operators\nOR g.objectid ENDS WITH '-516' // Domain Controllers\nOR g.objectid ENDS WITH '-519' // Enterprise Admins\nOR g.objectid ENDS WITH '-527' // Enterprise Key Admins\nOR g.objectid ENDS WITH '-526' // Key Admins\nOR g.objectid ENDS WITH '-550' // Print Operators\nOR g.objectid ENDS WITH '-521' // Read-Only Domain Controllers\nOR g.objectid ENDS WITH '-552' // Replicators\nOR g.objectid ENDS WITH '-518' // Schema Admins\nOR g.objectid ENDS WITH '-549' // Server Operators\nWITH n, g\nWHERE g IS NULL\nRETURN n", + "revision": 2, "resources": [ - "https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16", - "https://specterops.io/blog/2024/02/28/adcs-esc14-abuse-technique/" + "https://learn.microsoft.com/en-us/windows/win32/adschema/a-admincount", + "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#protected-groups" ], "acknowledgements": [ - "Jonas B\u00fclow Knudsen, @Jonas_B_K" + "Martin Sohn Christensen, @martinsohndk", + "kaasimir, @kaasimir" ] }, { - "name": "Users with logon scripts stored in a trusted domain", - "guid": "8d94d3f3-3d53-4939-a206-3c0a4dd3f646", - "prebuilt": false, + "name": "Tier Zero principals without AdminSDHolder protection", + "guid": "82ce5e2e-415b-489d-b891-304e8bb25998", + "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:User)\nWHERE n.logonscript IS NOT NULL\nMATCH (d:Domain)<-[:SameForestTrust|CrossForestTrust]-(:Domain)-[:Contains*1..]->(n)\nWITH n,last(split(d.name, '@')) AS domain\nWHERE toUpper(n.logonscript) STARTS WITH (\"\\\\\\\\\" + domain + \"\\\\\")\nRETURN n", + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.adminsdholderprotected = false\nRETURN n\nLIMIT 500", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Domains where any user can join a computer to the domain", + "guid": "421921fa-bc0f-4659-9680-b7481adcb132", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (d:Domain)\nWHERE d.machineaccountquota > 0\nRETURN d", "revision": 2, + "resources": [ + "https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/default-workstation-numbers-join-domain", + "https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/add-workstations-to-domain" + ], + "acknowledgements": [] + }, + { + "name": "Tier Zero accounts that can be delegated", + "guid": "4316eaf1-6af0-4879-8f55-ac2633a711c3", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Kerberos Interaction", + "description": null, + "query": "MATCH (m:Base)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nAND m.enabled = true\nAND m.sensitive = false\nOPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)\nWHERE g.objectid ENDS WITH '-525'\nWITH m, COLLECT(n) AS matchingNs\nWHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)\nRETURN m", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Enrollment rights on published certificate templates", - "guid": "a4ae2e54-aad3-4bfd-a12d-90cb8a9cbc86", - "prebuilt": true, + "name": "Members of Allowed RODC Password Replication Group", + "guid": "19fc5acd-e30a-4038-a5b5-2e0494f93373", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Domain Information", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", - "revision": 1, + "query": "MATCH p=(:Base)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH \"-571\"\nRETURN p", + "revision": 2, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Map Azure Management structure", + "guid": "c1bb109e-e6a4-4c91-864f-f78e1e42615e", + "prebuilt": false, + "platforms": [ + "Azure" + ], + "category": "General", + "description": "Maps the structure of Azure Management", + "query": "MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup)\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [ + "https://learn.microsoft.com/en-us/azure/governance/management-groups/overview" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Computers where Domain Users are local administrators", - "guid": "d43a7bdc-33c6-4a39-a3bb-24115749e595", + "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated)", + "guid": "609d648f-7fb8-42d3-ad99-626f9ce1f121", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Dangerous Privileges", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p=(s:Group)-[:AdminTo]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "All members of high privileged roles", - "guid": "3df24d92-dd12-4125-811b-e696b098f60e", + "name": "Tier Zero AD principals synchronized with Entra ID", + "guid": "a8b6ec67-21aa-4dd2-8906-47bb81bf5262", "prebuilt": true, "platforms": [ "Azure" ], - "category": "General", - "description": null, - "query": "MATCH p=(t:AZRole)<-[:AZHasRole|AZMemberOf*1..2]-(:AZBase)\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator|Privileged Role Administrator'\nRETURN p\nLIMIT 1000", - "revision": 2, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Tier Zero users with passwords not rotated in over 1 year", - "guid": "5e0d69b1-37d1-43ae-ac5d-f297f312fab5", - "prebuilt": false, - "platforms": [ - "Active Directory" - ], - "category": "Active Directory Hygiene", + "category": "Azure Hygiene", "description": null, - "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", + "query": "MATCH (ENTRA:AZBase)\nMATCH (AD:Base)\nWHERE ((AD:Tag_Tier_Zero) OR COALESCE(AD.system_tags, '') CONTAINS 'admin_tier_0')\nAND ENTRA.onpremsyncenabled = true\nAND ENTRA.onpremid = AD.objectid\nRETURN ENTRA\n// Replace 'RETURN ENTRA' with 'RETURN AD' to see the corresponding AD principals\nLIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Non-default members in Pre-Windows 2000 Compatible Access", - "guid": "091995b9-7254-473a-996f-6b8368d20431", - "prebuilt": false, + "name": "Paths from Domain Users to Tier Zero / High Value targets", + "guid": "977bec40-565c-40b8-90c8-e3e122c291cd", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE NOT n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND NOT (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nAND NOT n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", - "revision": 1, + "query": "MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s.objectid ENDS WITH '-513' AND s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Principals with foreign domain group membership", - "guid": "8fb3214a-5a75-4ecd-b293-c121abd94b4b", + "name": "Kerberoastable users with most admin privileges", + "guid": "9907b208-494c-4ba6-846d-485e6de14e17", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Kerberos Interaction", "description": null, - "query": "MATCH p=(s:Base)-[:MemberOf]->(t:Group)\nWHERE s.domainsid<>t.domainsid\nRETURN p\nLIMIT 1000", + "query": "MATCH (u:User)\nWHERE u.hasspn = true\n AND u.enabled = true\n AND NOT u.objectid ENDS WITH '-502'\n AND NOT COALESCE(u.gmsa, false) = true\n AND NOT COALESCE(u.msa, false) = true\nMATCH (u)-[:MemberOf|AdminTo*1..]->(c:Computer)\nWITH DISTINCT u, COUNT(c) AS adminCount\nRETURN u\nORDER BY adminCount DESC\nLIMIT 100", "revision": 1, - "resources": [], + "resources": [ + "https://attack.mitre.org/techniques/T1558/003/" + ], "acknowledgements": [] }, { - "name": "Direct Principal Rights Assignment", - "guid": "1d9c6ae3-38fc-4089-b5ad-fc3be0fa8eec", + "name": "AdminSDHolder protected Accounts and Groups", + "guid": "5ee2f40e-a55c-4140-ab8a-91746ba3752b", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "This query identifies rights assigned directly to users or computers instead of groups. Active Directory best practice requires granting rights to groups, then adding users as group members. This role-based access control (RBAC) approach ensures permissions are easily auditable and manageable. Results include inherited rights, which must be modified at the parent container level.", - "query": "MATCH p=(n:Base)-[r:GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE (n:User OR n:Computer) \nRETURN p\nLIMIT 1000", + "category": "Domain Information", + "description": "Objects whose permissions are set by SDProp to the template AdminSDHolder object as per MS-ADTS 3.1.1.6.1.2 Protected Objects. Does not exclude objects if specified in dSHeuristics dwAdminSDExMask", + "query": "MATCH (n:Base)-[:MemberOf*0..]->(m:Group)\nWHERE (\n n.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Groups\n OR m.objectid =~ \".*-(S-1-5-32-544|S-1-5-32-548|S-1-5-32-549|S-1-5-32-550|S-1-5-32-551|S-1-5-32-552|518|512|519)$\" // Members of groups\n OR n.objectid =~ \".*-(500|502|516|521)$\" // Direct objects\n)\nRETURN n", "revision": 1, "resources": [ - "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a0d0b4fa-2895-4c64-b182-ba64ad0f84b8", + "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "All Operators", - "guid": "3dfd0843-1ff9-4c21-aa67-feae08d109de", - "prebuilt": false, + "name": "Nested groups within Tier Zero / High Value", + "guid": "8e541e75-df1d-423f-b429-4bbf0403a338", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(:Base)-[:MemberOf]->(n:Group)\nWHERE (\n n.objectid ENDS WITH 'S-1-5-32-551' OR // Backup Operators\n n.objectid ENDS WITH 'S-1-5-32-556' OR // Network Configuration Operators\n n.objectid ENDS WITH 'S-1-5-32-549' OR // Server Operators\n n.objectid ENDS WITH 'S-1-5-32-579' OR // Access Control Assistance Operators\n n.objectid ENDS WITH 'S-1-5-32-548' OR // Account Operators\n n.objectid ENDS WITH 'S-1-5-32-569' OR // Cryptographic Operators\n n.objectid ENDS WITH 'S-1-5-32-550' // Print Operators\n)\nRETURN p", + "query": "MATCH p=(t:Group)<-[:MemberOf*..]-(s:Group)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT s.objectid ENDS WITH '-512' // Domain Admins\nAND NOT s.objectid ENDS WITH '-519' // Enterprise Admins\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6)", - "guid": "ab14e9dc-996c-4737-878c-583c19cdbf5a", + "name": "Entra Users with Entra Admin Roles group delegated eligibility", + "guid": "2e36c81b-25ed-40ba-afec-5f5f6443e095", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Certificate Services", + "category": "General", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Disabled Tier Zero / High Value principals", - "guid": "860d5c2d-84fe-4c85-80de-e0a9badbd0e7", + "name": "Principals with DCSync privileges", + "guid": "6e9beb8a-ad14-43de-bda1-644d174a5906", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Azure Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:AZBase)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nRETURN n\nLIMIT 100", + "query": "MATCH p=(:Base)-[:DCSync|AllExtendedRights|GenericAll]->(:Domain)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Map Azure Management structure", - "guid": "c1bb109e-e6a4-4c91-864f-f78e1e42615e", + "name": "Collection health of DC Registry Data", + "guid": "3f0fa2f3-fbdf-42c0-9e7d-97e689009161", "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "General", - "description": "Maps the structure of Azure Management", - "query": "MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup)\nRETURN p\nLIMIT 1000", - "revision": 2, + "category": "Domain Information", + "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured DC to potentially a full forest compromise by any principal. DCs returned by this query have not been collected.", + "query": "MATCH p=(:Domain)<-[:DCFor]-(c:Computer)\nWHERE c.strongcertificatebindingenforcementraw IS NULL\n// Exclude inactive DCs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", + "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/azure/governance/management-groups/overview" + "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#dc-registry" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Kerberos-enabled service account member of built-in Admins groups", - "guid": "42a856fc-257a-4142-9592-ca95fd49e579", + "name": "Microsoft Entra Connect accounts with passwords not rotated in over 90 days", + "guid": "97fb1310-d15d-4d63-82a2-8788056250f1", "prebuilt": false, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(g:Group)\nWHERE (\n g.objectid ENDS WITH '-512' // Domain Admins\n OR g.objectid ENDS WITH '-519' // Enterprise Admins\n OR g.objectid ENDS WITH '-518' // Schema Admins\n)\nAND n.hasspn = true\nRETURN p", + "description": "Micosoft recommends to change the password of MSOL accounts every 90 days to prevent attackers from allowing use of the high privileges", + "query": "WITH 90 as days_since_change\nMATCH (u:User)\nWHERE u.name STARTS WITH \"MSOL_\"\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/defender-for-identity/rotate-password-microsoft-entra-connect" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "CA Administrators and CA Managers (ESC7)", - "guid": "77a708b8-962e-4c3d-ad70-e994126aaeba", - "prebuilt": true, + "name": "Non-Tier Zero object with excessive control", + "guid": "944cecfe-519b-4318-b226-e8520161b454", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", - "description": null, - "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Dangerous Privileges", + "description": "Returns non-Tier Zero principals with >= 1000 direct rights to other principals. This does not include rights from group memberships.", + "query": "MATCH (n:Base)-[r:AD_ATTACK_PATHS]->(m:Base)\nWHERE NOT r:MemberOf\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH n, COLLECT(DISTINCT(m)) AS endNodes\nWHERE SIZE(endNodes) >= 1000\nRETURN n", + "revision": 4, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Entra ID SSO accounts not rolling Kerberos decryption key", - "guid": "1867abf8-08e3-4ea8-8f65-8366079d35c4", + "name": "Computers with non-default Primary Group membership", + "guid": "5862dc4e-6f6f-4321-9474-d838968495ed", "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Configuration Weakness", - "description": "Microsoft highly recommends that you roll over the Entra ID SSO Kerberos decryption key at least every 30 days.", - "query": "MATCH (n:Computer)\nWHERE n.name STARTS WITH \"AZUREADSSOACC.\"\nAND n.pwdlastset < (datetime().epochseconds - (30 * 86400))\nRETURN n", - "revision": 1, + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-515\" // Domain Computers\nAND NOT n.isdc = true\nAND NOT n.isreadonlydc = true\nAND r.isprimarygroup = true\nRETURN p", + "revision": 2, "resources": [ - "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/how-to-connect-sso-faq#how-can-i-roll-over-the-kerberos-decryption-key-of-the--azureadsso--computer-account-" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ada3/e12954a4-6865-4432-94e6-00c310ca87c0", + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5dbcf875-e802-4357-a6e2-1bdff19ff9b5", + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/73d11ea7-e634-453e-944d-559654cc91c5" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domain Admins logons to non-Domain Controllers", - "guid": "e2f3fd0a-1df2-4089-b0a4-272ad6e369a9", + "name": "Accounts with weak password storage encryption", + "guid": "8bd6fcf2-3f3c-414c-857a-4caf28e49def", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": null, - "query": "MATCH (s)-[:MemberOf*0..]->(g:Group)\nWHERE g.objectid ENDS WITH '-516'\nWITH COLLECT(s) AS exclude\nMATCH p = (c:Computer)-[:HasSession]->(:User)-[:MemberOf*1..]->(g:Group)\nWHERE g.objectid ENDS WITH '-512' AND NOT c IN exclude\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [], - "acknowledgements": [] + "category": "Active Directory Hygiene", + "description": "Accounts with passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", + "query": "MATCH (n:Base)\nWHERE n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008 release\nRETURN n\nLIMIT 100", + "revision": 2, + "resources": [ + "https://techcommunity.microsoft.com/blog/coreinfrastructureandsecurityblog/decrypting-the-selection-of-supported-kerberos-encryption-types/1628797" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Uncommon permission on containers", - "guid": "018c2b45-e30f-47d8-a751-22419c3d0736", + "name": "Domains allowing unauthenticated rootDSE searches and binds", + "guid": "ebc79aa4-e816-4be8-93fe-a0b30dbc771d", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "BloodHound typically identifies risk on Active Directory objects stored in OUs, however behind the scenes; Active Directory has a hieracy of containers e.g. CN=SYSTEM and CN=CONFIGURATION, on which control can lead to risk. Results are prone to false-positives but can assist auditing containers permissions.", - "query": "MATCH p=(:Domain)-[:Contains*1..]->(c:Container)<-[r]-(n:Base)\n\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\n\n// Scope edges to ACLs\nAND r.isacl\n\n// Exclude CN=Users and CN=Computers containers\nAND NOT c.distinguishedname STARTS WITH \"CN=COMPUTERS,DC=\"\nAND NOT c.distinguishedname STARTS WITH \"CN=USERS,DC=\"\n\n// Exclude same-domain unresolved SIDs\nAND NOT (n.distinguishedname IS NULL AND n.domainsid = c.domainsid)\n\n// Exclude default: Cert Publishers\nAND NOT (c.distinguishedname CONTAINS \",CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC=\" AND n.objectid ENDS WITH \"-517\")\n\n// Exclude default: RAS and IAS Servers\nAND NOT (c.distinguishedname CONTAINS \"CN=RAS AND IAS SERVERS ACCESS CHECK,CN=SYSTEM,DC=\" AND n.objectid ENDS WITH \"-553\")\n\n// Exclude default: DNS\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\" AND n.name STARTS WITH \"DNSADMINS@\")\n\n// Exclude default: ConfigMgr\nAND NOT (c.distinguishedname STARTS WITH \"CN=SYSTEM MANAGEMENT,CN=SYSTEM,DC=\" AND n.samaccountname ENDS WITH \"$\")\n\n// Exclude default: Exchange pt1\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" AND (n.name STARTS WITH \"EXCHANGE TRUSTED SUBSYSTEM@\" OR n.name STARTS WITH \"ORGANIZATION MANAGEMENT@\" OR n.name STARTS WITH \"EXCHANGE SERVICES@\"))\n\n// Exclude default: Exchange pt2\nAND NOT ((c.distinguishedname CONTAINS \"CN=MONITORING MAILBOXES,CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\") AND n.name STARTS WITH \"EXCHANGE ENTERPRISE SERVERS@\")\n\n// Exclude default: Exchange pt3\nAND NOT ((c.distinguishedname CONTAINS \"CN=ACTIVE DIRECTORY CONNECTIONS,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname =~ \"CN=RECIPIENT UPDATE SERVICES,CN=ADDRESS LISTS CONTAINER,CN=.*,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\") AND n.name STARTS WITH \"EXCHANGE DOMAIN SERVERS@\")\n\nRETURN p\nLIMIT 2000", + "description": "Checks the fLDAPBlockAnonOps flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{6}[^2].*\"\nRETURN n", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Map domain trusts", - "guid": "268d3d26-5bc2-4820-a6ed-09d20f3d5413", + "name": "DCs vulnerable to NTLM relay to LDAP attacks", + "guid": "3f87e0b0-fc06-4986-a94c-e08781253dc8", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p = (:Domain)-[:SameForestTrust|CrossForestTrust]->(:Domain)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (dc:Computer)-[:DCFor]->(:Domain)\nWHERE (dc.ldapavailable = True AND dc.ldapsigning = False)\nOR (dc.ldapsavailable = True AND dc.ldapsepa = False)\nOR (dc.ldapavailable = True AND dc.ldapsavailable = True AND dc.ldapsigning = False and dc.ldapsepa = True)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero users with email", - "guid": "9654c0d4-f1e8-4393-a2d1-53a5554a9de8", + "name": "All ADCS ESC privilege escalation edges", + "guid": "49db8edc-8421-438f-b97b-23c042959bef", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Tier Zero accounts with email access have an increased attack surface.", - "query": "MATCH (n)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.email <> \"\"\nAND n.enabled = true\nAND NOT toUpper(n.email) ENDS WITH \".ONMICROSOFT.COM\"\nAND NOT (\n (toUpper(n.email) STARTS WITH \"HEALTHMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERYMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHDISCOVERY\"\n OR toUpper(n.email) STARTS WITH \"MSEXCHAPPROVAL\"\n OR toUpper(n.email) STARTS WITH \"FEDERATEDEMAIL\"\n OR toUpper(n.email) STARTS WITH \"SYSTEMMAILBOX\"\n OR toUpper(n.email) STARTS WITH \"MIGRATION.\")\n AND\n (n.name STARTS WITH \"SM_\"\n OR n.name STARTS WITH \"HEALTHMAILBOX\")\n)\nRETURN n", + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p=(:Base)-[:ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|GoldenCert|CoerceAndRelayNTLMToADCS]->(:Base)\nRETURN p", "revision": 1, - "resources": [], + "resources": [ + "https://posts.specterops.io/certified-pre-owned-d95910965cd2", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-1-799f3d3b03cf", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac", + "https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53", + "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/#:~:text=Introducing%20the%20CoerceAndRelayNTLMToADCS%20Edge" + ], "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" + "Jonas B\u00fclow Knudsen, @Jonas_B_K" ] }, { - "name": "Domains with smart card accounts where smart account passwords do not expire", - "guid": "97e05e67-5961-4aba-a8e7-fe5f92334035", + "name": "Principals with weak supported Kerberos encryption types", + "guid": "ca329573-2157-41da-ab17-4d122c54b11d", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN s", + "query": "MATCH (u:Base)\nWHERE 'DES-CBC-CRC' IN u.supportedencryptiontypes\nOR 'DES-CBC-MD5' IN u.supportedencryptiontypes\nOR 'RC4-HMAC-MD5' IN u.supportedencryptiontypes\nRETURN u", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Synced Entra Users with Entra Admin Role approval (group delegated)", - "guid": "ead56ecb-fb88-427c-8f39-75e774bb9a0a", + "name": "Synced Entra Users with Entra Admin Role approval (direct)", + "guid": "1bfe2d75-0a51-4dbe-abc6-178cc0e4476f", "prebuilt": true, "platforms": [ "Active Directory", @@ -1491,194 +1338,179 @@ ], "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Domains with more than 50 Tier Zero accounts", - "guid": "f046e95a-5f84-4e83-bcda-6e83f3d8e21a", + "name": "Object name conflict", + "guid": "c561c4f8-ea45-453f-85a2-3fc2e20e7f8c", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (d:Domain)-[:Contains*1..]->(n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nWITH d, COUNT(n) AS adminCount\nWHERE adminCount > 50\nRETURN d", + "description": "When two objects are created with the same Relative Distinguished Name (RDN) in the same parent Organizational Unit or container, the conflict is recognized by the system when one of the new objects replicates to another domain controller. When this happens, one of the objects is renamed with 'CNF'", + "query": "MATCH (n:Base)\nWHERE n.distinguishedname CONTAINS 'CNF:'\nRETURN n", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/archive/technet-wiki/15435.active-directory-duplicate-object-name-resolution" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Accounts with smart card required in domains where smart account passwords do not expire", - "guid": "bba7985e-f32a-4c62-b1b0-0365bf1455e6", + "name": "Domain controllers with UPN certificate mapping enabled", + "guid": "799ea3ce-572b-4594-98c4-041aa2ae6176", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p=(s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN p", + "query": "MATCH p = (s:Computer)-[:DCFor]->(:Domain)\nWHERE s.certificatemappingmethodsraw IN [4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31]\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16", + "https://specterops.io/blog/2024/02/28/adcs-esc14-abuse-technique/" + ], + "acknowledgements": [ + "Jonas B\u00fclow Knudsen, @Jonas_B_K" + ] }, { - "name": "Principals with DCSync privileges", - "guid": "6e9beb8a-ad14-43de-bda1-644d174a5906", + "name": "Entra Users synced from On-Prem Users added to Domain Admins group", + "guid": "62722d5f-bd93-4d11-beeb-9be261827e4e", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Dangerous Privileges", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH p=(:Base)-[:DCSync|AllExtendedRights|GenericAll]->(:Domain)\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:AZUser)-[:SyncedToADUser]->(:User)-[:MemberOf]->(t:Group)\nWHERE t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enabled computers inactive for 180 days - MSSQL Failover Cluster", - "guid": "d263e621-7f1b-4efb-ad25-098fc7d4fb72", + "name": "Tier Zero computers with passwords older than the default maximum password age", + "guid": "b6d6d0bf-130e-4719-996b-adc29bba36e9", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND ANY(type IN n.serviceprincipalnames WHERE \n toLower(type) CONTAINS 'mssqlservercluster' OR \n toLower(type) CONTAINS 'mssqlserverclustermgmtapi' OR \n toLower(type) CONTAINS 'msclustervirtualserver')\nRETURN n\nLIMIT 1000", - "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/troubleshoot/windows-server/high-availability/troubleshoot-issues-accounts-used-failover-clusters#troubleshoot-password-issues-with-the-cluster-name-account" - ], + "query": "MATCH (n:Computer)\nWHERE n.enabled = true\nAND n.whencreated < (datetime().epochseconds - (60 * 3 * 86400))\nAND n.pwdlastset < (datetime().epochseconds - (60 * 3 * 86400))\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "revision": 2, + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Enrollment rights on published certificate templates with no security extension", - "guid": "0677b70c-4e04-4e89-a6a2-f5764604a6a7", + "name": "PKI hierarchy", + "guid": "928acc23-ee4c-40a5-bde7-64c05cc1491d", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.nosecurityextension = true\nRETURN p\nLIMIT 1000", + "query": "MATCH p=()-[:HostsCAService|IssuedSignedBy|EnterpriseCAFor|RootCAFor|TrustedForNTAuth|NTAuthStoreFor*..]->(:Domain)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Computers where Domain Users can read LAPS passwords", - "guid": "aa4bfa95-e7b9-4d56-8f35-f34f04d7b6f4", + "name": "Cross-forest trusts with abusable configuration", + "guid": "5cf1f354-80d4-420e-bc4b-424fabc21a56", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(s:Group)-[:AllExtendedRights|ReadLAPSPassword]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(n:Domain)-[:CrossForestTrust|SpoofSIDHistory|AbuseTGTDelegation]-(m:Domain)\nWHERE (n)-[:SpoofSIDHistory|AbuseTGTDelegation]-(m)\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enrollment rights on published ESC15 certificate templates", - "guid": "78d59fe1-e1a0-4813-adc9-c3c96ac08b66", - "prebuilt": false, + "name": "CA Administrators and CA Managers (ESC7)", + "guid": "77a708b8-962e-4c3d-ad70-e994126aaeba", + "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Certificate Services", - "description": "Enrollment rights on certificate templates that meet the requirements for the ADCS ESC15 (EKUwu) attack.", - "query": "MATCH p=(:Base)-[:Enroll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)-[:TrustedForNTAuth]->(:NTAuthStore)-[:NTAuthStoreFor]->(:Domain)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = False\nAND ct.requiresmanagerapproval = False\nAND ct.schemaversion = 1\nRETURN p", + "description": null, + "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://x.com/SpecterOps/status/1844800558151901639", - "https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2024-49019" - ], - "acknowledgements": [ - "Jonas B\u00fclow Knudsen, @Jonas_B_K" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "All GPOs applied to a specific Computer", - "guid": "1d75a21e-0d34-40c5-9360-281b60737d87", + "name": "Domains exempting privileged groups from AdminSDHolder protections", + "guid": "79f8d8f9-8291-4bf7-a13a-15989018075f", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "View all GPOs that are applied to any specific computer. This query identifies GPOs that are applied at both the Domain Level and the OU level, saving time in large Active Directory environments where GPO inheritance is complex. Replace \"COMPUTER_NAME\" with the target computer name or a substring. Note this does not take OU 'Block inheritance' and GPO 'No Override' into account.", - "query": "// Replace \"HOSTNAME/FQDN\" with the computer's\nMATCH p=(c:Computer)<-[:Contains*..]-(:Base)<-[:GPLink]-(:GPO)\nWHERE toLower(c.name) CONTAINS toLower(\"HOSTNAME/FQDN\")\nRETURN p", + "category": "Active Directory Hygiene", + "description": "Checks the dwAdminSDExMask flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{15}[^0].*\"\nRETURN n", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/previous-versions/windows/desktop/Policy/overriding-and-blocking-group-policy" + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" ], "acknowledgements": [ - "Adnan Ullah Khan, @auk0x01" + "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "All Domain Admins", - "guid": "0596dba7-9180-49a0-aa54-00243240037c", - "prebuilt": true, - "platforms": [ - "Active Directory" - ], - "category": "Domain Information", - "description": null, - "query": "MATCH p = (t:Group)<-[:MemberOf*1..]-(a)\nWHERE (a:User or a:Computer) and t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", - "revision": 1, - "resources": [], - "acknowledgements": [] - }, - { - "name": "Domains allowing unauthenticated domain enumeration", - "guid": "41a08d76-f8a5-4296-ad19-464c4c5c69fe", + "name": "Tier Zero accounts not members of Denied RODC Password Replication Group", + "guid": "e9613406-e346-410b-a033-690a6cf0c708", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nOR n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", - "revision": 1, + "query": "// Get all Tier Zero accounts that are members of Denied RODC Password Replication Group\nMATCH (n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND (n:User OR n:Computer)\nAND m.objectid ENDS WITH '-519'\nWITH COLLECT(n.objectid) AS MembersOfDeniedGroup\n\n// Get all Tier Zero accounts\nMATCH (x:Base)\nWHERE ((x:Tag_Tier_Zero) OR COALESCE(x.system_tags, '') CONTAINS 'admin_tier_0')\nAND (x:User OR x:Computer)\n\n// Filter the members of Denied RODC Password Replication Group\nAND NOT x.objectid IN MembersOfDeniedGroup\nRETURN x", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "All coerce and NTLM relay edges", - "guid": "15c5ff3b-856c-44d1-a731-a8cb72512dd1", + "name": "Shortest paths to Domain Admins from Kerberoastable users", + "guid": "bd163361-1e05-47c7-908b-962aef251535", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Shortest Paths", "description": null, - "query": "MATCH p = (n:Base)-[:CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|CoerceAndRelayNTLMToADCS|CoerceAndRelayNTLMToSMB]->(:Base)\nRETURN p LIMIT 500", - "revision": 1, - "resources": [ - "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/" - ], + "query": "MATCH p=shortestPath((s:User)-[:AD_ATTACK_PATHS*1..]->(t:Group))\nWHERE s.hasspn=true\nAND s.enabled = true\nAND NOT s.objectid ENDS WITH '-502'\nAND NOT COALESCE(s.gmsa, false) = true\nAND NOT COALESCE(s.msa, false) = true\nAND t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], "acknowledgements": [] }, { - "name": "Accounts with clear-text password attributes", - "guid": "e303498f-e3d4-489d-8a34-b68e187bc4e7", + "name": "Kerberos-enabled service account member of built-in Admins groups", + "guid": "42a856fc-257a-4142-9592-ca95fd49e579", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE n.userpassword IS NOT NULL\nOR n.unixpassword IS NOT NULL\nOR n.unicodepwd IS NOT NULL\nOR n.msSFU30Password IS NOT NULL\nRETURN n", + "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(g:Group)\nWHERE (\n g.objectid ENDS WITH '-512' // Domain Admins\n OR g.objectid ENDS WITH '-519' // Enterprise Admins\n OR g.objectid ENDS WITH '-518' // Schema Admins\n)\nAND n.hasspn = true\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1686,45 +1518,49 @@ ] }, { - "name": "CA administrators and CA managers", - "guid": "fd35e3d8-0c74-4b5a-a847-c0dd1f1c9f19", - "prebuilt": true, + "name": "All paths crossing a specific trust", + "guid": "251fc893-7a6b-4a0a-8650-9d5408d38c3c", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", - "description": null, - "query": "MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Domain Information", + "description": "All paths crossing a specific trust from a trusted to a trusting domain.", + "query": "// Replace the TRUSTED domain SID\n// Replace the TRUSTING domain SID\nMATCH p=(Trusted:Base)-[:AD_ATTACK_PATHS]->(Trusting:Base)\nWHERE Trusted.domainsid = 'S-1-5-21-1111111111-1111111111-1111111111'\nAND Trusting.domainsid = 'S-1-5-21-2222222222-2222222222-2222222222'\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Sessions across trusts", - "guid": "aea7ac64-1f51-407b-b0ee-19fd30075794", + "name": "Enabled computers inactive for 180 days - MSSQL Failover Cluster", + "guid": "d263e621-7f1b-4efb-ad25-098fc7d4fb72", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Users logging on across a trust, the users originate from trusted domains.", - "query": "MATCH p=(trustedDomainPrincipal:Computer)-[r:HasSession]->(trustingDomainPrincipal:User)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nRETURN p\nLIMIT 1000", + "category": "Active Directory Hygiene", + "description": null, + "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND ANY(type IN n.serviceprincipalnames WHERE \n toLower(type) CONTAINS 'mssqlservercluster' OR \n toLower(type) CONTAINS 'mssqlserverclustermgmtapi' OR \n toLower(type) CONTAINS 'msclustervirtualserver')\nRETURN n\nLIMIT 1000", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/troubleshoot/windows-server/high-availability/troubleshoot-issues-accounts-used-failover-clusters#troubleshoot-password-issues-with-the-cluster-name-account" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Locations of Owned objects", - "guid": "c88bfab4-3da0-4b36-b71d-7b324ebd2243", + "name": "Large default groups with outbound control", + "guid": "a334f21a-3d7f-448e-b7ea-1465a3127bce", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(n:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC5|ADCSESC6a|ADCSESC6b|ADCSESC7|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1732,74 +1568,94 @@ ] }, { - "name": "Enrollment rights on published ESC1 certificate templates", - "guid": "2af855bc-f48f-4b22-9839-627d8231e425", + "name": "All Global Administrators", + "guid": "94d7d765-6837-4eb8-aa33-e1c9ef262cdc", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "General", + "description": null, + "query": "MATCH p=(:AZBase)-[:AZHasRole*1..]->(t:AZRole)\nWHERE t.name =~ '(?i)Global Administrator.*'\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Computers with unsupported operating systems", + "guid": "d06d3b14-0318-4fa9-9639-4b79ccaf3c2c", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = True\nAND ct.requiresmanagerapproval = False\nAND (ct.authorizedsignatures = 0 OR ct.schemaversion = 1)\nRETURN p\nLIMIT 1000", + "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nRETURN c\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Foreign principals in Tier Zero / High Value targets", - "guid": "95bec736-86ef-4017-8465-9b9b66548b17", + "name": "ESC8-vulnerable Enterprise CAs", + "guid": "60881923-296c-4702-adf7-a4f059dc9bb8", "prebuilt": true, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Azure Hygiene", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (n:AZServicePrincipal)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT toUpper(n.appownerorganizationid) = toUpper(n.tenantid)\nAND n.appownerorganizationid CONTAINS '-'\nRETURN n\nLIMIT 100", + "query": "MATCH (n:EnterpriseCA)\nWHERE n.hasvulnerableendpoint=true\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Non-Tier Zero accounts with SID History of Tier Zero accounts", - "guid": "59744dfe-9411-4daf-b342-1203dc62acd4", + "name": "Domains not verifying UPN and SPN uniqueness", + "guid": "cb0b1591-5c3e-45f1-afb7-984e5ad865d0", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": null, - "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "category": "Active Directory Hygiene", + "description": "Checks the DoNotVerifyUPNAndOrSPNUniqueness flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{20}[^0].*\"\nRETURN n", "revision": 1, - "resources": [], + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Synced Entra Users with Entra Admin Role approval (direct)", - "guid": "1bfe2d75-0a51-4dbe-abc6-178cc0e4476f", - "prebuilt": true, + "name": "Enrollment rights on published ESC15 certificate templates", + "guid": "78d59fe1-e1a0-4813-adc9-c3c96ac08b66", + "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", - "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", + "category": "Active Directory Certificate Services", + "description": "Enrollment rights on certificate templates that meet the requirements for the ADCS ESC15 (EKUwu) attack.", + "query": "MATCH p=(:Base)-[:Enroll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)-[:TrustedForNTAuth]->(:NTAuthStore)-[:NTAuthStoreFor]->(:Domain)\nWHERE ct.enrolleesuppliessubject = True\nAND ct.authenticationenabled = False\nAND ct.requiresmanagerapproval = False\nAND ct.schemaversion = 1\nRETURN p", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://x.com/SpecterOps/status/1844800558151901639", + "https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2024-49019" + ], + "acknowledgements": [ + "Jonas B\u00fclow Knudsen, @Jonas_B_K" + ] }, { - "name": "Tier Zero computers at risk of resource-based constrained delegation", - "guid": "4dc97cf4-3c03-4fe6-8a8b-4f665c67e1e5", + "name": "Users with non-expiring passwords", + "guid": "212c2a98-53d9-4dfa-b177-42c601452dd1", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (n:Computer)<-[:AllowedToAct]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH (u:User)\nWHERE u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [ @@ -1807,33 +1663,31 @@ ] }, { - "name": "Domains with a minimum default password policy length less than 15 characters", - "guid": "7d258d2d-a43d-4a90-85d7-71c946ae5fd7", + "name": "Tier Zero computers not requiring inbound SMB signing", + "guid": "13485477-f026-4b1f-906d-4f2e37364ba4", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH (n:Domain)\nWHERE n.minpwdlength < 15\nRETURN n", + "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", "revision": 1, - "resources": [ - "https://pages.nist.gov/800-63-3/sp800-63b.html" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains affected by AdPrep privilege escalation risk", - "guid": "815ff190-f6f3-4757-a516-2f4bf589b705", + "name": "Users with non-default Primary Group membership", + "guid": "93890f88-df2c-4167-a945-a53961d08d00", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[r:GenericAll]->(m:Domain)\nWHERE n.objectid ENDS WITH \"-527\" // Enterprise Key Admins\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH p=(n:User)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-513\" // Domain Users\nAND r.isprimarygroup = true\nAND NOT n.objectid ENDS WITH \"-501\" // Guests account, as it has primaryGroup to Guests\nAND (n.gmsa IS NULL OR n.gmsa = false) // Not gMSA, as it has primaryGroup to Domain Computers\nAND (n.msa IS NULL OR n.msa = false) // Not MSA, as it has primaryGroup to Domain Computers\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -1841,120 +1695,133 @@ ] }, { - "name": "Tier Zero principals without AdminSDHolder protection", - "guid": "82ce5e2e-415b-489d-b891-304e8bb25998", + "name": "Shortest paths from Azure Applications to Tier Zero / High Value targets", + "guid": "60ff7c58-a98e-4bc1-9e32-8378d2db0c43", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "Shortest Paths", + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "query": "MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 3, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Compromising permissions on ADCS nodes (ESC5)", + "guid": "396c7b67-fb5d-4c04-bb13-8007f0dfc9b1", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.adminsdholderprotected = false\nRETURN n\nLIMIT 500", + "query": "MATCH p = (n:Base)-[:Owns|WriteOwner|WriteDacl|GenericAll|GenericWrite]->(m:Base)\nWHERE m.distinguishedname CONTAINS \"PUBLIC KEY SERVICES\"\nAND NOT n.objectid ENDS WITH \"-512\" // Domain Admins\nAND NOT n.objectid ENDS WITH \"-519\" // Enterprise Admins\nAND NOT n.objectid ENDS WITH \"-544\" // Administrators\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "On-Prem Users synced to Entra Users with Azure RM Roles (group delegated)", - "guid": "e4f2eada-8a89-4ba9-89eb-abbee4efbc7a", + "name": "Shortest paths from Entra Users to Tier Zero / High Value targets", + "guid": "58089b28-54e0-4fd2-bf66-3db480b00e2f", "prebuilt": true, "platforms": [ - "Active Directory", "Azure" ], - "category": "Cross Platform Attack Paths", - "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)\nRETURN p\nLIMIT 1000", - "revision": 1, + "category": "Shortest Paths", + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "query": "MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 3, "resources": [], "acknowledgements": [] }, { - "name": "Enabled computers inactive for 180 days", - "guid": "0768e810-1e1e-4319-a216-76d9c2058644", - "prebuilt": false, + "name": "Enrollment rights on published certificate templates", + "guid": "a4ae2e54-aad3-4bfd-a12d-90cb8a9cbc86", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Active Directory Certificate Services", "description": null, - "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Disabled Tier Zero / High Value principals", - "guid": "d65a801f-d3ef-4b7e-8030-99ebfd6dad12", - "prebuilt": true, + "name": "Non-Tier Zero principals with control of AdminSDHolder", + "guid": "4c1e0137-5b7f-48d8-bd09-9db7674bca61", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nAND NOT n.objectid ENDS WITH '-502' // Removes false positive, KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 100", + "query": "MATCH p=(n:Group)-[r:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteOwnerLimitedRights|OwnsLimitedRights]->(m:Container)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND m.name STARTS WITH \"ADMINSDHOLDER@\"\nRETURN p", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#adminsdholder" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Kerberos-enabled service accounts without AES encryption support", - "guid": "cb8cf96e-21c9-422b-9439-390a13446ca6", + "name": "Accounts with clear-text password attributes", + "guid": "e303498f-e3d4-489d-8a34-b68e187bc4e7", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Accounts without Kerberos AES encryption support, or passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.", - "query": "MATCH (n:Base)\nWHERE n.hasspn = true\nAND ((\n n.supportedencryptiontypes <> ['Not defined']\n OR n.supportedencryptiontypes <> []\n OR NONE(type IN n.supportedencryptiontypes WHERE type CONTAINS 'AES128' OR type CONTAINS 'AES256')\n)\nOR (n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008\nAND NOT n.pwdlastset IN [-1.0, 0.0]\n))\nRETURN n\nLIMIT 100", - "revision": 2, + "description": null, + "query": "MATCH (n:Base)\nWHERE n.userpassword IS NOT NULL\nOR n.unixpassword IS NOT NULL\nOR n.unicodepwd IS NOT NULL\nOR n.msSFU30Password IS NOT NULL\nRETURN n", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Shortest paths from Owned objects", - "guid": "e370a01d-c129-4f19-b88d-9479cbe00028", + "name": "Shortest paths to Domain Admins", + "guid": "f40cb34b-5ec7-44bc-9aa8-a200a4a41f22", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Shortest Paths", "description": null, - "query": "MATCH p=shortestPath((s:Base)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE ((s:Tag_Owned) OR COALESCE(s.system_tags, '') CONTAINS 'owned')\nAND s<>t\nRETURN p\nLIMIT 1000", - "revision": 3, + "query": "MATCH p=shortestPath((t:Group)<-[:AD_ATTACK_PATHS*1..]-(s:Base))\nWHERE t.objectid ENDS WITH '-512' AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], "acknowledgements": [] }, { - "name": "Kerberoastable members of Tier Zero / High Value groups", - "guid": "e6da7800-ae06-41cb-80a6-d5421ab2143a", + "name": "Shortest paths to Azure Subscriptions", + "guid": "4785b305-c101-461c-80fc-3fb3ff67a8ce", "prebuilt": true, "platforms": [ - "Active Directory" - ], - "category": "Kerberos Interaction", - "description": null, - "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true \nRETURN u\nLIMIT 100", - "revision": 2, - "resources": [ - "https://attack.mitre.org/techniques/T1558/003/" + "Azure" ], + "category": "Shortest Paths", + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription))\nWHERE s<>t\nRETURN p\nLIMIT 1000", + "revision": 3, + "resources": [], "acknowledgements": [] }, { - "name": "Users with non-default Primary Group membership", - "guid": "93890f88-df2c-4167-a945-a53961d08d00", + "name": "Enabled users inactive for 180 days", + "guid": "71972f3c-b32d-4023-a841-5cc8cc1c1867", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:User)-[r:MemberOf]->(g:Group)\nWHERE NOT g.objectid ENDS WITH \"-513\" // Domain Users\nAND r.isprimarygroup = true\nAND NOT n.objectid ENDS WITH \"-501\" // Guests account, as it has primaryGroup to Guests\nAND (n.gmsa IS NULL OR n.gmsa = false) // Not gMSA, as it has primaryGroup to Domain Computers\nAND (n.msa IS NULL OR n.msa = false) // Not MSA, as it has primaryGroup to Domain Computers\nRETURN p", + "query": "WITH 180 as inactive_days\nMATCH (n:User)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -1962,71 +1829,73 @@ ] }, { - "name": "Enabled Tier Zero / High Value principals inactive for 60 days", - "guid": "72550bcb-3c4f-463d-8973-91a49163dc5a", - "prebuilt": true, + "name": "Tier Zero users not member of Protected Users", + "guid": "543eb01d-9fa3-4b8f-a936-b46bbfdaa2ae", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "WITH 60 as inactive_days\nMATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n", + "query": "MATCH (m:User)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nOPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)\nWHERE g.objectid ENDS WITH '-525'\nWITH m, COLLECT(n) AS matchingNs\nWHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)\nRETURN m", "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Shortest paths to Domain Admins", - "guid": "f40cb34b-5ec7-44bc-9aa8-a200a4a41f22", + "name": "Location of AdminSDHolder Protected objects", + "guid": "3408ccaf-1f42-4c10-b09a-e986661f84d7", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", + "category": "Domain Information", "description": null, - "query": "MATCH p=shortestPath((t:Group)<-[:AD_ATTACK_PATHS*1..]-(s:Base))\nWHERE t.objectid ENDS WITH '-512' AND s<>t\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH p = (n:Base)<-[:Contains*1..]-(:Domain)\nWHERE n.adminsdholderprotected = True\nRETURN p\nLIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Enrollment rights on published enrollment agent certificate templates", - "guid": "8483bf5b-89f1-4723-abb2-c48295f6393e", + "name": "Computers with the outgoing NTLM setting set to Deny all", + "guid": "a9ddca74-feeb-4dbf-8b0f-de08b3cfa8a6", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE '1.3.6.1.4.1.311.20.2.1' IN ct.effectiveekus\nOR '2.5.29.37.0' IN ct.effectiveekus\nOR SIZE(ct.effectiveekus) = 0\nRETURN p\nLIMIT 1000", + "query": "MATCH (c:Computer)\nWHERE c.restrictoutboundntlm = True\nRETURN c LIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Locations of Tier Zero / High Value objects", - "guid": "18a83a17-b451-4343-acfe-7620516e2968", + "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6)", + "guid": "ab14e9dc-996c-4737-878c-583c19cdbf5a", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Domains with a single-point-of-failure Domain Controller", - "guid": "3359a295-7cfd-491f-976b-c5a68647431c", + "name": "Locations of Owned objects", + "guid": "c88bfab4-3da0-4b36-b71d-7b324ebd2243", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "MATCH (n:Group)<-[:MemberOf]-(:Computer)\nWHERE n.objectid ENDS WITH '-516'\nWITH n, COUNT(n) AS dcCount\nWHERE dcCount = 1\nRETURN n", + "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -2034,146 +1903,173 @@ ] }, { - "name": "Compromising permissions on ADCS nodes (ESC5)", - "guid": "396c7b67-fb5d-4c04-bb13-8007f0dfc9b1", + "name": "Users with passwords not rotated in over 1 year", + "guid": "be70d1bd-b7eb-40b0-971c-eefc50eca032", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (n:Base)-[:Owns|WriteOwner|WriteDacl|GenericAll|GenericWrite]->(m:Base)\nWHERE m.distinguishedname CONTAINS \"PUBLIC KEY SERVICES\"\nAND NOT n.objectid ENDS WITH \"-512\" // Domain Admins\nAND NOT n.objectid ENDS WITH \"-519\" // Enterprise Admins\nAND NOT n.objectid ENDS WITH \"-544\" // Administrators\nRETURN p\nLIMIT 1000", + "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "AS-REP Roastable Tier Zero users (DontReqPreAuth)", - "guid": "6d51e4dc-e1ad-477a-b6c6-324f18f03120", + "name": "Tier Zero users with passwords not rotated in over 1 year", + "guid": "5e0d69b1-37d1-43ae-ac5d-f297f312fab5", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.dontreqpreauth = true\nRETURN n", + "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/004/" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Large default groups with outbound control", - "guid": "a334f21a-3d7f-448e-b7ea-1465a3127bce", - "prebuilt": false, + "name": "Entra Users with Entra Admin Role direct eligibility", + "guid": "b87899ce-3a51-401a-ae39-ef271b566e3d", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Dangerous Privileges", + "category": "General", "description": null, - "query": "MATCH p=(n:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC5|ADCSESC6a|ADCSESC6b|ADCSESC7|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", + "query": "MATCH p = (:AZUser)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Collection health of CA Registry Data", - "guid": "c8dd3479-8063-450a-9456-557bc5f39e10", + "name": "Foreign Service Principals With any Abusable MS Graph App Role Assignment", + "guid": "d7a180c8-5624-4fc1-a407-deeb2ad3054c", "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Domain Information", - "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured CA to potentially a full forest compromise by any principal. CAs returned by this query have not been collected.", - "query": "MATCH p=(eca:EnterpriseCA)<-[:HostsCAService]-(c:Computer)\nWHERE (\n eca.isuserspecifiessanenabledcollected = false\n OR eca.casecuritycollected = false\n OR eca.enrollmentagentrestrictionscollected = false\n OR eca.roleseparationenabledcollected = false\n)\n// Exclude inactive CAs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", + "category": "Dangerous Privileges", + "description": "MS Graph app role assignments provide significant power within an Entra ID tenant, similar to an Admin role.", + "query": "MATCH p = (sp1:AZServicePrincipal)-[r:AZMGGroupMember_ReadWrite_All|AZMGServicePrincipalEndpoint_ReadWrite_All|AZMGAppRoleAssignment_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory]->(sp2:AZServicePrincipal)\nWHERE toUpper(sp1.appownerorganizationid) <> toUpper(sp1.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp1.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [ - "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#ca-registry" + "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" ], "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" + "Stephen Hinck" ] }, { - "name": "Foreign Service Principals With any Abusable MS Graph App Role Assignment", - "guid": "d7a180c8-5624-4fc1-a407-deeb2ad3054c", + "name": "Domains with functional level not the latest version", + "guid": "3da9d14a-f1cb-4df7-b3da-8d73ff5c401b", "prebuilt": false, "platforms": [ - "Azure" + "Active Directory" ], - "category": "Dangerous Privileges", - "description": "MS Graph app role assignments provide significant power within an Entra ID tenant, similar to an Admin role.", - "query": "MATCH p = (sp1:AZServicePrincipal)-[r:AZMGGroupMember_ReadWrite_All|AZMGServicePrincipalEndpoint_ReadWrite_All|AZMGAppRoleAssignment_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory]->(sp2:AZServicePrincipal)\nWHERE toUpper(sp1.appownerorganizationid) <> toUpper(sp1.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp1.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:Domain)\nWHERE toString(n.functionallevel) IN ['2008','2003','2003 Interim','2000 Mixed/Native']\nRETURN n", "revision": 1, - "resources": [ - "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" + "resources": [], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "KRBTGT accounts with passwords not rotated in over 1 year", + "guid": "1b3ae310-ffa7-4ce5-a37f-6111aef600c8", + "prebuilt": false, + "platforms": [ + "Active Directory" ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:User)\nWHERE (n.objectid ENDS WITH '-502'\nOR n.name STARTS WITH 'AZUREADKERBEROS.'\nOR n.name STARTS WITH 'KRBTGT_AZUREAD@')\nAND n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nRETURN n", + "revision": 1, + "resources": [], "acknowledgements": [ - "Stephen Hinck" + "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Potential GPO 'Apply' misconfiguration", - "guid": "f5f2455e-afdc-4708-9a34-98f539ce52d8", - "prebuilt": true, + "name": "Tier Zero computers at risk of resource-based constrained delegation", + "guid": "4dc97cf4-3c03-4fe6-8a8b-4f665c67e1e5", + "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Dangerous Privileges", - "description": "In Active Directory, GPO's are applied to objects in the Group Policy Management Console by ticking \"Allow - Apply group policy\", but administrators can mistakenly tick \"Allow - Write\" or \"Allow - Full Control\" resulting in a misconfigured GPO that allows a principal to compromise other principals the GPO also applies to. Results are potential risks and must be audited for for correctness.", - "query": "MATCH p=(n:Base)-[:GenericAll|GenericWrite]->(g:GPO)\n\n// Exclude Enterprise Admins and Domain Admins\nWHERE NOT n.objectid =~ \"-(519|512)$\"\n\n// Exclude unresolved SIDs\nAND NOT (n.distinguishedname IS NULL)\n\n// Asset description may reveal if it's a delegation group (false-positive) or a filter group (true-positive)\n//AND n.description is not null\n//AND n.description =~ \"(?i)apply\"\n\nRETURN p\nLIMIT 1000", - "revision": 2, + "description": null, + "query": "MATCH p = (n:Computer)<-[:AllowedToAct]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "On-Prem Users synced to Entra Users with Entra Group Membership", - "guid": "edb575df-2048-4ef0-a0e4-168544a496e9", + "name": "Domains with smart card accounts where smart account passwords do not expire", + "guid": "97e05e67-5961-4aba-a8e7-fe5f92334035", "prebuilt": true, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Cross Platform Attack Paths", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)\nRETURN p\nLIMIT 1000", + "query": "MATCH (s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN s", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero accounts not members of Denied RODC Password Replication Group", - "guid": "e9613406-e346-410b-a033-690a6cf0c708", + "name": "Domains allowing unauthenticated domain enumeration", + "guid": "41a08d76-f8a5-4296-ad19-464c4c5c69fe", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "// Get all Tier Zero accounts that are members of Denied RODC Password Replication Group\nMATCH (n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND (n:User OR n:Computer)\nAND m.objectid ENDS WITH '-519'\nWITH COLLECT(n.objectid) AS MembersOfDeniedGroup\n\n// Get all Tier Zero accounts\nMATCH (x:Base)\nWHERE ((x:Tag_Tier_Zero) OR COALESCE(x.system_tags, '') CONTAINS 'admin_tier_0')\nAND (x:User OR x:Computer)\n\n// Filter the members of Denied RODC Password Replication Group\nAND NOT x.objectid IN MembersOfDeniedGroup\nRETURN x", - "revision": 2, + "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE (n.objectid ENDS WITH \"S-1-5-7\" // Anonymous\nOR n.objectid ENDS WITH \"S-1-1-0\") // Everyone\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains without Microsoft LAPS computers", - "guid": "f9b440b5-732c-4ed3-b6d2-83857db17e1a", + "name": "Computers with passwords older than the default maximum password age", + "guid": "185c5010-8d4f-4f9b-b24e-831707dddfca", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": "Machine account passwords are regularly changed for security purposes. Starting with Windows 2000-based computers, the machine account password automatically changes every 30 days.", + "query": "WITH 60 as rotation_period\nMATCH (n:Computer)\nWHERE n.pwdlastset < (datetime().epochseconds - (rotation_period * 86400)) // password not rotated\nAND n.enabled = true // enabled computers\nAND n.whencreated < (datetime().epochseconds - (rotation_period * 86400)) // exclude recently created computers\nAND n.lastlogontimestamp > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Replicated value)\nAND n.lastlogon > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Non-replicated value)\nRETURN n", + "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/disable-machine-account-password" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Sessions across trusts", + "guid": "aea7ac64-1f51-407b-b0ee-19fd30075794", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Domain Information", - "description": null, - "query": "MATCH (d:Domain)\nOPTIONAL MATCH (c:Computer)\nWHERE c.domainsid = d.objectid AND c.haslaps = true\nWITH d, COLLECT(c) AS computers\nWHERE SIZE(computers) = 0\nRETURN d", + "description": "Users logging on across a trust, the users originate from trusted domains.", + "query": "MATCH p=(trustedDomainPrincipal:Computer)-[r:HasSession]->(trustingDomainPrincipal:User)\nWHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [ @@ -2181,109 +2077,148 @@ ] }, { - "name": "Nested groups within Tier Zero / High Value", - "guid": "8e541e75-df1d-423f-b429-4bbf0403a338", + "name": "AdminSDHolder to protected objects relationship", + "guid": "c751f95c-8bb0-4be4-b027-84f5709c91d2", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(t:Group)<-[:MemberOf*..]-(s:Group)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT s.objectid ENDS WITH '-512' // Domain Admins\nAND NOT s.objectid ENDS WITH '-519' // Enterprise Admins\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(n)-[:ProtectAdminGroups]->(m)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Users which do not require password to authenticate", - "guid": "23bdc2ad-6739-4b2b-85d3-258e3f424eb2", + "name": "Disabled Tier Zero / High Value principals", + "guid": "d65a801f-d3ef-4b7e-8030-99ebfd6dad12", "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (u:User)\nWHERE u.passwordnotreqd = true\nRETURN u\nLIMIT 100", + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nAND NOT n.objectid ENDS WITH '-502' // Removes false positive, KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Computer owners who can obtain LAPS passwords", - "guid": "92aa81d6-b08e-4abb-ae39-ecbe5735a74c", + "name": "Domains with a minimum default password policy length less than 15 characters", + "guid": "7d258d2d-a43d-4a90-85d7-71c946ae5fd7", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", - "description": "Creators of computer objects get abusable rights on the computer object. If the owner is not explicitly granted ReadLAPSPassword they can still compromise the computer with the abusable owner rights.", - "query": "MATCH p = (c:Computer)<-[:GenericAll|Owns|WriteDacl|WriteOwner|AllExtendedRights]-(n:User)\nWHERE c.haslaps = true AND c.ownersid = n.objectid\nRETURN p", + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:Domain)\nWHERE n.minpwdlength < 15\nRETURN n", "revision": 1, - "resources": [], + "resources": [ + "https://pages.nist.gov/800-63-3/sp800-63b.html" + ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Enrollment rights on CertTemplates with OIDGroupLink", - "guid": "140a68eb-d21c-4b75-971f-309225fb2d75", + "name": "Domains allowing unauthenticated NSPI RPC binds", + "guid": "a950fdab-5934-4c69-a88b-e2e0e3da9d52", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": "Checks the fAllowAnonNSPI flag of dSHeuristics.", + "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{7}[^0].*\"\nRETURN n", + "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Accounts with smart card required in domains where smart account passwords do not expire", + "guid": "bba7985e-f32a-4c62-b1b0-0365bf1455e6", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:ExtendedByPolicy]->(:IssuancePolicy)-[:OIDGroupLink]->(:Group)\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(s:Domain)-[:Contains*1..]->(t:Base)\nWHERE s.expirepasswordsonsmartcardonlyaccounts = false\nAND t.enabled = true\nAND t.smartcardrequired = true\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "All DNSAdmins", - "guid": "183fb320-f3ae-4ab3-a090-3f9a7db692e1", + "name": "Overprivileged Microsoft Entra Connect accounts", + "guid": "9e6e75b4-9ecc-45d4-a39b-b6427b813f0a", + "prebuilt": false, + "platforms": [ + "Active Directory", + "Azure" + ], + "category": "Active Directory Hygiene", + "description": "Legacy MSOL accounts were by default deployed with Domain Admins or Enterprise Admins membership.", + "query": "MATCH p=(n:User)-[:MemberOf*1..]->(g:Group)\nWHERE n.name STARTS WITH \"MSOL_\"\nAND (g.objectid ENDS WITH \"-512\" // Domain Admins\nOR g.objectid ENDS WITH \"-519\") // Entterprise Admins\nRETURN p", + "revision": 1, + "resources": [ + "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/reference-connect-accounts-permissions" + ], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Users with logon scripts stored in a trusted domain", + "guid": "8d94d3f3-3d53-4939-a206-3c0a4dd3f646", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Base)-[:MemberOf]->(g:Group) \nWHERE n.name STARTS WITH \"DNSADMINS@\"\nRETURN p", - "revision": 1, + "query": "MATCH (n:User)\nWHERE n.logonscript IS NOT NULL\nMATCH (d:Domain)<-[:SameForestTrust|CrossForestTrust]-(:Domain)-[:Contains*1..]->(n)\nWITH n,last(split(d.name, '@')) AS domain\nWHERE toUpper(n.logonscript) STARTS WITH (\"\\\\\\\\\" + domain + \"\\\\\")\nRETURN n", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains allowing unauthenticated rootDSE searches and binds", - "guid": "ebc79aa4-e816-4be8-93fe-a0b30dbc771d", + "name": "Domains without Protected Users group", + "guid": "8c3e0811-a31b-45b4-a29d-1dce80fa2c5f", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Checks the fLDAPBlockAnonOps flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{6}[^2].*\"\nRETURN n", + "category": "Domain Information", + "description": null, + "query": "MATCH (n:Domain)\nWHERE n.collected = true\nOPTIONAL MATCH (m:Group)\nWHERE m.name ENDS WITH n.name\nAND m.objectid ENDS WITH '-525'\nWITH n, m\nWHERE m IS NULL\nRETURN n", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Users with passwords not rotated in over 1 year", - "guid": "be70d1bd-b7eb-40b0-971c-eefc50eca032", + "name": "AS-REP Roastable users (DontReqPreAuth)", + "guid": "2570e359-dec1-419d-b0dc-a204bd64ee42", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Kerberos Interaction", "description": null, - "query": "WITH 365 as days_since_change\nMATCH (u:User)\nWHERE u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u\nLIMIT 100", + "query": "MATCH (u:User)\nWHERE u.dontreqpreauth = true\nAND u.enabled = true\nRETURN u\nLIMIT 100", "revision": 1, - "resources": [], + "resources": [ + "https://attack.mitre.org/techniques/T1558/004/" + ], "acknowledgements": [] }, { @@ -2302,130 +2237,152 @@ "acknowledgements": [] }, { - "name": "Tier Zero / High Value users with non-expiring passwords", - "guid": "4eca1b69-00a2-48a0-abb3-b94ea647cf6b", - "prebuilt": true, + "name": "Foreign Service Principals With an EntraID Admin Role", + "guid": "b6235820-4e0d-4dfa-af5b-729b5644feb5", + "prebuilt": false, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", - "description": null, - "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", + "category": "Dangerous Privileges", + "description": "Entra ID admin roles grant significant control over a tenant environment, even if the role is not a default Tier Zero / High Value role", + "query": "MATCH p = (sp:AZServicePrincipal)-[:AZHasRole]->(r:AZRole)\nWHERE toUpper(sp.appownerorganizationid) <> toUpper(sp.tenantid)\n// Ensure AZServicePrincipal has a valid appownerorganizationid\nAND sp.appownerorganizationid CONTAINS \"-\"\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [], - "acknowledgements": [] + "resources": [ + "https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65" + ], + "acknowledgements": [ + "Stephen Hinck" + ] }, { - "name": "Domains exempting privileged groups from AdminSDHolder protections", - "guid": "79f8d8f9-8291-4bf7-a13a-15989018075f", + "name": "Direct Principal Rights Assignment", + "guid": "1d9c6ae3-38fc-4089-b5ad-fc3be0fa8eec", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Checks the dwAdminSDExMask flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{15}[^0].*\"\nRETURN n", + "description": "This query identifies rights assigned directly to users or computers instead of groups. Active Directory best practice requires granting rights to groups, then adding users as group members. This role-based access control (RBAC) approach ensures permissions are easily auditable and manageable. Results include inherited rights, which must be modified at the parent container level.", + "query": "MATCH p=(n:Base)-[r:GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)\nWHERE (n:User OR n:Computer) \nRETURN p\nLIMIT 1000", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains allowing authenticated domain enumeration", - "guid": "1e1e6fdd-6973-4547-906c-a494b5fbdcba", - "prebuilt": false, + "name": "Public Key Services container", + "guid": "07e94492-71aa-4665-ab8c-e7aec25906cd", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p = (c:Container)-[:Contains*..]->(:Base)\nWHERE c.distinguishedname starts with 'CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC='\nRETURN p\nLIMIT 1000", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Enabled Tier Zero / High Value principals inactive for 60 days", + "guid": "72550bcb-3c4f-463d-8973-91a49163dc5a", + "prebuilt": true, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[:MemberOf]->(m:Group)\nWHERE n.objectid ENDS WITH \"S-1-5-11\" // Authenticated Users\nAND m.objectid ENDS WITH \"S-1-5-32-554\" // Pre-Windows 2000 Compatible Access\nRETURN p", + "query": "WITH 60 as inactive_days\nMATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Domains affected by Exchange privilege escalation risk", - "guid": "f2d09c94-b6f2-4901-9a2d-f8bacd61edc7", - "prebuilt": false, + "name": "Computers not requiring inbound SMB signing", + "guid": "6b1fcfb6-b010-41a2-9d31-f9872fe994ff", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "NTLM Relay Attacks", "description": null, - "query": "MATCH p=(n:Group)-[r:WriteDacl|ForceChangePassword|AddMember]->(m:Base)\nWHERE n.name STARTS WITH \"EXCHANGE \"\nAND ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nRETURN n", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] + }, + { + "name": "Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled", + "guid": "96e70597-2d74-4503-a624-f1e30b642894", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.isuserspecifiessanenabled = True\nRETURN p\nLIMIT 1000", + "revision": 1, + "resources": [], + "acknowledgements": [] }, { - "name": "Principals with DES-only Kerberos authentication", - "guid": "d03ea1ef-70f0-439b-b1ef-d7f94ceb2af3", + "name": "Servers where Domain Users can RDP", + "guid": "b9a330ae-1d89-44d4-8f74-9ca18e93eb92", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:Base)\nWHERE n.enabled = true\nAND n.usedeskeyonly = true\nRETURN n", + "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Non-Tier Zero principals with BadSuccessor rights (no prerequisites check)", - "guid": "2b9fb71e-73ad-4061-a2df-40c7132b044d", - "prebuilt": false, + "name": "Entra Users with Entra Admin Role approval (direct)", + "guid": "74d7993c-24af-4df7-8402-5c6fb22d088c", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Dangerous Privileges", - "description": "Finds non-Tier Zero principals with BadSuccessor rights with no prerequisites check (DC2025 & KDC key).", - "query": "// Find OU control\nMATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p LIMIT 1000", + "category": "General", + "description": null, + "query": "MATCH p = (:AZUser)-[:AZRoleApprover]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, - "resources": [ - "https://bsky.app/profile/specterops.io/post/3lpua65qeu22l" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Non-Tier Zero principals with control of AdminSDHolder", - "guid": "4c1e0137-5b7f-48d8-bd09-9db7674bca61", + "name": "Accounts with SID History", + "guid": "8172d52c-a975-49bd-9180-5b6efc59c9ab", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[r:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteOwnerLimitedRights|OwnsLimitedRights]->(m:Container)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND m.name STARTS WITH \"ADMINSDHOLDER@\"\nRETURN p", + "query": "MATCH p=(:Base)-[:HasSIDHistory]->(:Base)\nRETURN p", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#adminsdholder" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Dangerous privileges for Domain Users groups", - "guid": "9b8b9c18-f8c6-4c54-a20f-de0f7a7edbe0", + "name": "Disabled Tier Zero / High Value principals", + "guid": "860d5c2d-84fe-4c85-80de-e0a9badbd0e7", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Dangerous Privileges", + "category": "Azure Hygiene", "description": null, - "query": "MATCH p=(s:Group)-[r:AD_ATTACK_PATHS]->(:Base)\nWHERE s.objectid ENDS WITH '-513'\nAND NOT r:MemberOf\nRETURN p\nLIMIT 1000", - "revision": 3, + "query": "MATCH (n:AZBase)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.enabled = false\nRETURN n\nLIMIT 100", + "revision": 1, "resources": [], "acknowledgements": [] }, @@ -2444,235 +2401,232 @@ "acknowledgements": [] }, { - "name": "Members of Allowed RODC Password Replication Group", - "guid": "19fc5acd-e30a-4038-a5b5-2e0494f93373", + "name": "Tier Zero computers with the WebClient running", + "guid": "27a6f917-8ed4-4e2e-9b38-41a4b6de1b14", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(:Base)-[:MemberOf*1..]->(m:Group)\nWHERE m.objectid ENDS WITH \"-571\"\nRETURN p", - "revision": 2, + "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c LIMIT 1000", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Shortest paths from Owned objects to Tier Zero", - "guid": "dfaa8e8f-2c79-4e92-a291-b1347f6e83b0", - "prebuilt": true, + "name": "Domain Controllers allowing NTLMv1 or LM authentication", + "guid": "4b42513c-f89d-47ff-8d98-908af49d2b48", + "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Shortest Paths", - "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", - "query": "// MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE\nMATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base))\nWHERE s<>t\nAND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", - "revision": 4, + "category": "NTLM Relay Attacks", + "description": null, + "query": "MATCH (dc:Computer)\nWHERE dc.isdc = true\nAND (dc.lmcompatibilitylevel IS NOT NULL AND NOT dc.lmcompatibilitylevel = 5)\nRETURN dc", + "revision": 1, "resources": [], - "acknowledgements": [] + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] }, { - "name": "Domains not verifying UPN and SPN uniqueness", - "guid": "cb0b1591-5c3e-45f1-afb7-984e5ad865d0", - "prebuilt": false, + "name": "Computers where Domain Users are local administrators", + "guid": "d43a7bdc-33c6-4a39-a3bb-24115749e595", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Checks the DoNotVerifyUPNAndOrSPNUniqueness flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{20}[^0].*\"\nRETURN n", + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(s:Group)-[:AdminTo]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" - ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Circular AD group memberships", - "guid": "fcaa5ffc-3d22-481f-a2a2-18a4eec30058", + "name": "AS-REP Roastable Tier Zero users (DontReqPreAuth)", + "guid": "6d51e4dc-e1ad-477a-b6c6-324f18f03120", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.", - "query": "MATCH p=(x:Group)-[:MemberOf*2..]->(y:Group)\nWHERE x.objectid=y.objectid\nRETURN p\nLIMIT 100", + "description": null, + "query": "MATCH (n:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.dontreqpreauth = true\nRETURN n", "revision": 1, "resources": [ - "https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references" + "https://attack.mitre.org/techniques/T1558/004/" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Domains with functional level not the latest version", - "guid": "3da9d14a-f1cb-4df7-b3da-8d73ff5c401b", - "prebuilt": false, + "name": "All Domain Admins", + "guid": "0596dba7-9180-49a0-aa54-00243240037c", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Domain Information", "description": null, - "query": "MATCH (n:Domain)\nWHERE toString(n.functionallevel) IN ['2008','2003','2003 Interim','2000 Mixed/Native']\nRETURN n", + "query": "MATCH p = (t:Group)<-[:MemberOf*1..]-(a)\nWHERE (a:User or a:Computer) and t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Enabled users inactive for 180 days", - "guid": "71972f3c-b32d-4023-a841-5cc8cc1c1867", - "prebuilt": false, + "name": "All service principals with Microsoft Graph privilege to grant arbitrary App Roles", + "guid": "e6d6b5da-89da-4514-a409-2d6e368397da", + "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Active Directory Hygiene", + "category": "Microsoft Graph", "description": null, - "query": "WITH 180 as inactive_days\nMATCH (n:User)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator\nRETURN n\nLIMIT 1000", + "query": "MATCH p=(:AZServicePrincipal)-[:AZMGGrantAppRoles]->(:AZTenant)\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "AS-REP Roastable users (DontReqPreAuth)", - "guid": "2570e359-dec1-419d-b0dc-a204bd64ee42", + "name": "On-Prem Users synced to Entra Users with Entra Group Membership", + "guid": "edb575df-2048-4ef0-a0e4-168544a496e9", "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Kerberos Interaction", + "category": "Cross Platform Attack Paths", "description": null, - "query": "MATCH (u:User)\nWHERE u.dontreqpreauth = true\nAND u.enabled = true\nRETURN u\nLIMIT 100", + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)\nRETURN p\nLIMIT 1000", "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/004/" - ], + "resources": [], "acknowledgements": [] }, { - "name": "Computers without Windows LAPS", - "guid": "7c50f724-c467-4005-8e3f-9a6ce1461db0", + "name": "Enabled computers inactive for 180 days", + "guid": "0768e810-1e1e-4319-a216-76d9c2058644", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*WINDOWS (SERVER)? ?(10|11|2019|2022|2025).*'\nAND c.haslaps = false\nAND c.enabled = true\nRETURN c\nLIMIT 100", + "query": "WITH 180 as inactive_days\nMATCH (n:Computer)\nWHERE n.enabled = true\nAND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value\nAND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value\nAND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals\nAND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT\nAND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO\nRETURN n\nLIMIT 1000", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "All ADCS ESC privilege escalation edges", - "guid": "49db8edc-8421-438f-b97b-23c042959bef", + "name": "Principal with SPN keyword", + "guid": "38a9c4c9-3d70-453f-a017-cbfd35ed9917", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", - "description": null, - "query": "MATCH p=(:Base)-[:ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|GoldenCert|CoerceAndRelayNTLMToADCS]->(:Base)\nRETURN p", + "category": "Kerberos Interaction", + "description": "Finds service accounts used with a specific Kerberos-enabled service or all service accounts running on a Kerberos-enabled service on a specific server.", + "query": "// Replace keyword with a service type or server name (not FQDN)\nWITH \"KEYWORD\" as SPNKeyword\nMATCH (n:User)\nWHERE ANY(keyword IN n.serviceprincipalnames WHERE toUpper(keyword) CONTAINS toUpper(SPNKeyword))\nRETURN n", "revision": 1, "resources": [ - "https://posts.specterops.io/certified-pre-owned-d95910965cd2", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-1-799f3d3b03cf", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547", - "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac", - "https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53", - "https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/#:~:text=Introducing%20the%20CoerceAndRelayNTLMToADCS%20Edge" + "https://adsecurity.org/?page_id=183" ], "acknowledgements": [ - "Jonas B\u00fclow Knudsen, @Jonas_B_K" + "Ryan, @haus3c" ] }, { - "name": "Location of AdminSDHolder Protected objects", - "guid": "3408ccaf-1f42-4c10-b09a-e986661f84d7", + "name": "Non-default permissions on IssuancePolicy nodes", + "guid": "b2280665-c91b-448c-8c0f-97d1f38b6f59", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Active Directory Certificate Services", "description": null, - "query": "MATCH p = (n:Base)<-[:Contains*1..]-(:Domain)\nWHERE n.adminsdholderprotected = True\nRETURN p\nLIMIT 1000", + "query": "MATCH p = (s:Base)-[:GenericAll|GenericWrite|Owns|WriteOwner|WriteDacl]->(:IssuancePolicy)\nWHERE NOT s.objectid ENDS WITH '-512' AND NOT s.objectid ENDS WITH '-519'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "All Schema Admins", - "guid": "76d8e61d-7a86-40ff-8a85-fd37f1e2563f", - "prebuilt": false, + "name": "Shortest paths to systems trusted for unconstrained delegation", + "guid": "16a9e47b-45f8-4514-b409-771bb5186142", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", + "category": "Shortest Paths", "description": null, - "query": "MATCH p=(n:Base)-[:MemberOf*1..]->(m:Group)\nWHERE (n:User OR n:Computer)\nAND m.objectid ENDS WITH \"-518\" // Schema Admins\nRETURN p", - "revision": 1, + "query": "MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Computer))\nWHERE t.unconstraineddelegation = true AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Domains with List Object mode enabled", - "guid": "05e2a94b-5ee6-47ec-b715-3982f30af01b", - "prebuilt": false, + "name": "Enrollment rights on published ESC2 certificate templates", + "guid": "ebc77984-1ceb-4ed2-a395-ce1067847941", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "Checks the fDoListObject flag of dSHeuristics.", - "query": "MATCH (n:Domain)\nWHERE n.dsheuristics =~ \".{2}[^0].*\"\nRETURN n", - "revision": 1, + "category": "Active Directory Certificate Services", + "description": null, + "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(c:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)\nWHERE c.requiresmanagerapproval = false\nAND (c.effectiveekus = [''] OR '2.5.29.37.0' IN c.effectiveekus OR c.effectiveekus IS NULL)\nAND (c.authorizedsignatures = 0 OR c.schemaversion = 1)\nRETURN p\nLIMIT 1000", + "revision": 2, "resources": [ - "https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5" + "https://posts.specterops.io/certified-pre-owned-d95910965cd2", + "https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547" ], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "All paths crossing a specific trust", - "guid": "251fc893-7a6b-4a0a-8650-9d5408d38c3c", + "name": "Large default group added to computer-local group", + "guid": "dde133d2-b4d2-4de9-a656-905f3bf066f3", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Domain Information", - "description": "All paths crossing a specific trust from a trusted to a trusting domain.", - "query": "// Replace the TRUSTED domain SID\n// Replace the TRUSTING domain SID\nMATCH p=(Trusted:Base)-[:AD_ATTACK_PATHS]->(Trusting:Base)\nWHERE Trusted.domainsid = 'S-1-5-21-1111111111-1111111111-1111111111'\nAND Trusting.domainsid = 'S-1-5-21-2222222222-2222222222-2222222222'\nRETURN p\nLIMIT 1000", - "revision": 2, + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(n:Group)-[:MemberOfLocalGroup]->(m:ADLocalGroup)-[:LocalToComputer]->(:Computer)\nWHERE n.objectid =~ \".*-(S-1-5-11|S-1-1-0|S-1-5-32-545|S-1-5-7|-513|-515)$\" // Authenticated Users, Everyone, Users, Anonymous, Domain Users, Domain Computers\nAND NOT m.objectid =~ \".*-(545|574|554)$\" // Users, Certificate Service DCOM Access, Pre-Windows 2000 Compatible Access\nRETURN p", + "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Shortest paths to Domain Admins from Kerberoastable users", - "guid": "bd163361-1e05-47c7-908b-962aef251535", + "name": "Locations of Tier Zero / High Value objects", + "guid": "18a83a17-b451-4343-acfe-7620516e2968", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Domain Information", + "description": null, + "query": "MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)\nWHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p\nLIMIT 1000", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Tier Zero / High Value external Entra ID users", + "guid": "20e07417-d286-4dca-a962-568f2b262f65", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Shortest Paths", + "category": "Azure Hygiene", "description": null, - "query": "MATCH p=shortestPath((s:User)-[:AD_ATTACK_PATHS*1..]->(t:Group))\nWHERE s.hasspn=true\nAND s.enabled = true\nAND NOT s.objectid ENDS WITH '-502'\nAND NOT COALESCE(s.gmsa, false) = true\nAND NOT COALESCE(s.msa, false) = true\nAND t.objectid ENDS WITH '-512'\nRETURN p\nLIMIT 1000", - "revision": 2, + "query": "MATCH (n:AZUser)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nAND n.name CONTAINS '#EXT#@'\nRETURN n\nLIMIT 100", + "revision": 1, "resources": [], "acknowledgements": [] }, @@ -2695,29 +2649,45 @@ ] }, { - "name": "Non-default permissions on IssuancePolicy nodes", - "guid": "b2280665-c91b-448c-8c0f-97d1f38b6f59", + "name": "Shortest paths to privileged roles", + "guid": "3dc73dd8-4873-4aeb-a88f-56a58c77f512", + "prebuilt": true, + "platforms": [ + "Azure" + ], + "category": "Shortest Paths", + "description": "WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE", + "query": "MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole))\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator|Privileged Role Administrator' AND s<>t\nRETURN p\nLIMIT 1000", + "revision": 3, + "resources": [], + "acknowledgements": [] + }, + { + "name": "All Kerberoastable users", + "guid": "14ab4eaa-b73b-49c4-b2d1-1e020757c995", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Kerberos Interaction", "description": null, - "query": "MATCH p = (s:Base)-[:GenericAll|GenericWrite|Owns|WriteOwner|WriteDacl]->(:IssuancePolicy)\nWHERE NOT s.objectid ENDS WITH '-512' AND NOT s.objectid ENDS WITH '-519'\nRETURN p\nLIMIT 1000", + "query": "MATCH (u:User)\nWHERE u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true\nRETURN u\nLIMIT 100", "revision": 1, - "resources": [], + "resources": [ + "https://attack.mitre.org/techniques/T1558/003/" + ], "acknowledgements": [] }, { - "name": "Accounts with SID History to a same-domain account", - "guid": "275d2d58-0cad-4cad-8103-e0874cece666", + "name": "All DNSAdmins", + "guid": "183fb320-f3ae-4ab3-a090-3f9a7db692e1", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Domain Information", "description": null, - "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE n.domainsid = m.domainsid\nRETURN p", + "query": "MATCH p=(n:Base)-[:MemberOf]->(g:Group) \nWHERE n.name STARTS WITH \"DNSADMINS@\"\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2725,60 +2695,59 @@ ] }, { - "name": "On-Prem Users synced to Entra Users with Entra Admin Roles (direct)", - "guid": "de717635-d31f-4fbd-930b-b4dac0f22118", + "name": "Devices with unsupported operating systems", + "guid": "e3f2b53a-7ce6-4e52-9c74-68b69338288b", "prebuilt": true, "platforms": [ - "Active Directory", "Azure" ], - "category": "Cross Platform Attack Paths", + "category": "Azure Hygiene", "description": null, - "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZHasRole]->(:AZRole)\nRETURN p\nLIMIT 1000", + "query": "MATCH (n:AZDevice)\nWHERE n.operatingsystem CONTAINS 'WINDOWS'\nAND n.operatingsystemversion =~ '(10.0.19044|10.0.22000|10.0.19043|10.0.19042|10.0.19041|10.0.18363|10.0.18362|10.0.17763|10.0.17134|10.0.16299|10.0.15063|10.0.14393|10.0.10586|10.0.10240|6.3.9600|6.2.9200|6.1.7601|6.0.6200|5.1.2600|6.0.6003|5.2.3790|5.0.2195).?.*'\nRETURN n\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "AdminSDHolder to protected objects relationship", - "guid": "c751f95c-8bb0-4be4-b027-84f5709c91d2", + "name": "Workstations where Domain Users can RDP", + "guid": "9486e0e6-2617-4595-b969-cf57ca21fc86", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p=(n)-[:ProtectAdminGroups]->(m)\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(s:Group)-[:CanRDP]->(t:Computer)\nWHERE s.objectid ENDS WITH '-513' AND NOT toUpper(t.operatingsystem) CONTAINS 'SERVER'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero users not member of Protected Users", - "guid": "543eb01d-9fa3-4b8f-a936-b46bbfdaa2ae", + "name": "Tier Zero computers not owned by Tier Zero", + "guid": "99d29ded-223a-442b-a0e0-f8b5694c6441", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (m:User)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nOPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)\nWHERE g.objectid ENDS WITH '-525'\nWITH m, COLLECT(n) AS matchingNs\nWHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)\nRETURN m", - "revision": 1, + "query": "MATCH p=(n:Base)-[:Owns]->(:Computer)\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "revision": 2, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Usage of built-in domain Administrator account", - "guid": "35b1206f-871b-44aa-a601-c5258060dfcf", + "name": "Uncommon permission on containers", + "guid": "018c2b45-e30f-47d8-a751-22419c3d0736", "prebuilt": false, "platforms": [ "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Usage of Active Directory's built-in Administrator account is a sign that the account is not only used for break-glass purposes.", - "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-500\"\nAND (\n n.lastlogontimestamp > (datetime().epochseconds - (60 * 86400)) OR\n n.lastlogon > (datetime().epochseconds - (60 * 86400))\n)\nAND NOT n.whencreated > (datetime().epochseconds - (60 * 86400))\nRETURN n", + "description": "BloodHound typically identifies risk on Active Directory objects stored in OUs, however behind the scenes; Active Directory has a hieracy of containers e.g. CN=SYSTEM and CN=CONFIGURATION, on which control can lead to risk. Results are prone to false-positives but can assist auditing containers permissions.", + "query": "MATCH p=(:Domain)-[:Contains*1..]->(c:Container)<-[r]-(n:Base)\n\n// Exclude Tier Zero\nWHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\n\n// Scope edges to ACLs\nAND r.isacl\n\n// Exclude CN=Users and CN=Computers containers\nAND NOT c.distinguishedname STARTS WITH \"CN=COMPUTERS,DC=\"\nAND NOT c.distinguishedname STARTS WITH \"CN=USERS,DC=\"\n\n// Exclude same-domain unresolved SIDs\nAND NOT (n.distinguishedname IS NULL AND n.domainsid = c.domainsid)\n\n// Exclude default: Cert Publishers\nAND NOT (c.distinguishedname CONTAINS \",CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC=\" AND n.objectid ENDS WITH \"-517\")\n\n// Exclude default: RAS and IAS Servers\nAND NOT (c.distinguishedname CONTAINS \"CN=RAS AND IAS SERVERS ACCESS CHECK,CN=SYSTEM,DC=\" AND n.objectid ENDS WITH \"-553\")\n\n// Exclude default: DNS\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFTDNS,CN=SYSTEM,DC=\" AND n.name STARTS WITH \"DNSADMINS@\")\n\n// Exclude default: ConfigMgr\nAND NOT (c.distinguishedname STARTS WITH \"CN=SYSTEM MANAGEMENT,CN=SYSTEM,DC=\" AND n.samaccountname ENDS WITH \"$\")\n\n// Exclude default: Exchange pt1\nAND NOT (c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" AND (n.name STARTS WITH \"EXCHANGE TRUSTED SUBSYSTEM@\" OR n.name STARTS WITH \"ORGANIZATION MANAGEMENT@\" OR n.name STARTS WITH \"EXCHANGE SERVICES@\"))\n\n// Exclude default: Exchange pt2\nAND NOT ((c.distinguishedname CONTAINS \"CN=MONITORING MAILBOXES,CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\") AND n.name STARTS WITH \"EXCHANGE ENTERPRISE SERVERS@\")\n\n// Exclude default: Exchange pt3\nAND NOT ((c.distinguishedname CONTAINS \"CN=ACTIVE DIRECTORY CONNECTIONS,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\" OR c.distinguishedname CONTAINS \"CN=MICROSOFT EXCHANGE SYSTEM OBJECTS,DC=\" OR c.distinguishedname =~ \"CN=RECIPIENT UPDATE SERVICES,CN=ADDRESS LISTS CONTAINER,CN=.*,CN=MICROSOFT EXCHANGE,CN=SERVICES,CN=CONFIGURATION,DC=\") AND n.name STARTS WITH \"EXCHANGE DOMAIN SERVERS@\")\n\nRETURN p\nLIMIT 2000", "revision": 1, "resources": [], "acknowledgements": [ @@ -2786,34 +2755,47 @@ ] }, { - "name": "Microsoft Entra Connect accounts with passwords not rotated in over 90 days", - "guid": "97fb1310-d15d-4d63-82a2-8788056250f1", + "name": "Computers with the WebClient running", + "guid": "51107ad1-f0bc-43d3-a561-5cee471ca196", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "NTLM Relay Attacks", + "description": null, + "query": "MATCH (c:Computer)\nWHERE c.webclientrunning = True\nRETURN c LIMIT 1000", + "revision": 1, + "resources": [], + "acknowledgements": [] + }, + { + "name": "Collection health of CA Registry Data", + "guid": "c8dd3479-8063-450a-9456-557bc5f39e10", "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], - "category": "Active Directory Hygiene", - "description": "Micosoft recommends to change the password of MSOL accounts every 90 days to prevent attackers from allowing use of the high privileges", - "query": "WITH 90 as days_since_change\nMATCH (u:User)\nWHERE u.name STARTS WITH \"MSOL_\"\nAND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))\nAND NOT u.pwdlastset IN [-1.0, 0.0]\nRETURN u", + "category": "Domain Information", + "description": "BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured CA to potentially a full forest compromise by any principal. CAs returned by this query have not been collected.", + "query": "MATCH p=(eca:EnterpriseCA)<-[:HostsCAService]-(c:Computer)\nWHERE (\n eca.isuserspecifiessanenabledcollected = false\n OR eca.casecuritycollected = false\n OR eca.enrollmentagentrestrictionscollected = false\n OR eca.roleseparationenabledcollected = false\n)\n// Exclude inactive CAs\nAND c.enabled = true\nAND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))\nRETURN p", "revision": 1, "resources": [ - "https://learn.microsoft.com/en-us/defender-for-identity/rotate-password-microsoft-entra-connect" + "https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#ca-registry" ], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Enabled built-in guest user accounts", - "guid": "bb0f620d-6a55-4413-ac74-4c82905e8598", + "name": "Non-Tier Zero accounts with SID History of Tier Zero accounts", + "guid": "59744dfe-9411-4daf-b342-1203dc62acd4", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Active Directory Hygiene", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:User)\nWHERE n.objectid ENDS WITH \"-501\"\nAND n.enabled = true\nRETURN n", + "query": "MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", "revision": 1, "resources": [], "acknowledgements": [ @@ -2821,68 +2803,60 @@ ] }, { - "name": "Overprivileged Microsoft Entra Connect accounts", - "guid": "9e6e75b4-9ecc-45d4-a39b-b6427b813f0a", + "name": "Accounts with SID History to a non-existent domain", + "guid": "2710401a-c4c2-4d2c-9edb-d7625045f2e8", "prebuilt": false, "platforms": [ - "Active Directory", - "Azure" + "Active Directory" ], "category": "Active Directory Hygiene", - "description": "Legacy MSOL accounts were by default deployed with Domain Admins or Enterprise Admins membership.", - "query": "MATCH p=(n:User)-[:MemberOf*1..]->(g:Group)\nWHERE n.name STARTS WITH \"MSOL_\"\nAND (g.objectid ENDS WITH \"-512\" // Domain Admins\nOR g.objectid ENDS WITH \"-519\") // Entterprise Admins\nRETURN p", + "description": null, + "query": "MATCH (d:Domain)\nWITH collect(d.objectid) AS domainSIDs\nMATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)\nWHERE NOT n.domainsid IN domainSIDs\nRETURN p", "revision": 1, - "resources": [ - "https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/reference-connect-accounts-permissions" - ], + "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] }, { - "name": "Principal with SPN keyword", - "guid": "38a9c4c9-3d70-453f-a017-cbfd35ed9917", - "prebuilt": false, + "name": "Synced Entra Users with Entra Admin Role direct eligibility", + "guid": "ea82e359-725c-4881-83e9-35007e859cf5", + "prebuilt": true, "platforms": [ - "Active Directory" + "Active Directory", + "Azure" ], - "category": "Kerberos Interaction", - "description": "Finds service accounts used with a specific Kerberos-enabled service or all service accounts running on a Kerberos-enabled service on a specific server.", - "query": "// Replace keyword with a service type or server name (not FQDN)\nWITH \"KEYWORD\" as SPNKeyword\nMATCH (n:User)\nWHERE ANY(keyword IN n.serviceprincipalnames WHERE toUpper(keyword) CONTAINS toUpper(SPNKeyword))\nRETURN n", + "category": "Cross Platform Attack Paths", + "description": null, + "query": "MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleEligible]->(:AZRole)\nRETURN p LIMIT 100", "revision": 1, - "resources": [ - "https://adsecurity.org/?page_id=183" - ], - "acknowledgements": [ - "Ryan, @haus3c" - ] + "resources": [], + "acknowledgements": [] }, { - "name": "Tier Zero computers at risk of constrained delegation", - "guid": "8641e593-f2f2-48ba-bd45-fbc86e9f632a", - "prebuilt": false, + "name": "Tier Zero / High Value enabled users not requiring smart card authentication", + "guid": "867f9f17-c149-4c4b-ad84-9a807622ff8c", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p = (n:Computer)<-[:AllowedToDelegate]-(:Base)\nWHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')\nAND u.enabled = true\nAND u.smartcardrequired = false\nAND NOT u.name STARTS WITH 'MSOL_' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'PROVAGENTGMSA' // Removes false positive, Entra sync\nAND NOT u.name STARTS WITH 'ADSYNCMSA_' // Removes false positive, Entra sync\nRETURN u", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "Large default groups with outbound control of OUs", - "guid": "310b3626-f8e6-4ab0-832c-72df6048597f", + "name": "Tier Zero computers with unsupported operating systems", + "guid": "a87b558c-5746-4a90-9f83-c86e7b924a52", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH p=(n:Group)-[]->(:OU)\nWHERE n.objectid ENDS WITH \"-513\" // DOMAIN USERS\nOR n.objectid ENDS WITH \"-515\" // DOMAIN COMPUTERS\nOR n.objectid ENDS WITH \"-S-1-5-11\" // AUTHENTICATED USERS\nOR n.objectid ENDS WITH \"-S-1-1-0\" // EVERYONE\nOR n.objectid ENDS WITH \"S-1-5-32-545\" // USERS\nOR n.objectid ENDS WITH \"S-1-5-32-546\" // GUESTS\nOR n.objectid ENDS WITH \"S-1-5-7\" // ANONYMOUS\nRETURN p", + "query": "MATCH (c:Computer)\nWHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'\nAND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN c\nLIMIT 100", "revision": 1, "resources": [], "acknowledgements": [ @@ -2890,65 +2864,91 @@ ] }, { - "name": "Non-Tier Zero account with unconstrained delegation", - "guid": "e7e9a927-3f34-42c7-b921-d8bcf626011e", - "prebuilt": false, + "name": "Tier Zero / High Value users with non-expiring passwords", + "guid": "4eca1b69-00a2-48a0-abb3-b94ea647cf6b", + "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Dangerous Privileges", + "category": "Active Directory Hygiene", "description": null, - "query": "MATCH (n:Base)\nWHERE n.unconstraineddelegation = true\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "query": "MATCH (u:User)\nWHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.enabled = true\nAND u.pwdneverexpires = true\nRETURN u\nLIMIT 100", "revision": 1, "resources": [], - "acknowledgements": [ - "Martin Sohn Christensen, @martinsohndk" - ] + "acknowledgements": [] }, { - "name": "All Kerberoastable users", - "guid": "14ab4eaa-b73b-49c4-b2d1-1e020757c995", + "name": "All members of high privileged roles", + "guid": "3df24d92-dd12-4125-811b-e696b098f60e", "prebuilt": true, "platforms": [ - "Active Directory" + "Azure" ], - "category": "Kerberos Interaction", + "category": "General", "description": null, - "query": "MATCH (u:User)\nWHERE u.hasspn=true\nAND u.enabled = true\nAND NOT u.objectid ENDS WITH '-502'\nAND NOT COALESCE(u.gmsa, false) = true\nAND NOT COALESCE(u.msa, false) = true\nRETURN u\nLIMIT 100", - "revision": 1, - "resources": [ - "https://attack.mitre.org/techniques/T1558/003/" - ], + "query": "MATCH p=(t:AZRole)<-[:AZHasRole|AZMemberOf*1..2]-(:AZBase)\nWHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator|Privileged Role Administrator'\nRETURN p\nLIMIT 1000", + "revision": 2, + "resources": [], "acknowledgements": [] }, { - "name": "Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8)", - "guid": "1c1435b1-bad0-49f2-ba7d-932e047c0af4", + "name": "Computers where Domain Users can read LAPS passwords", + "guid": "aa4bfa95-e7b9-4d56-8f35-f34f04d7b6f4", "prebuilt": true, "platforms": [ "Active Directory" ], - "category": "Active Directory Certificate Services", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)\nWHERE eca.hasvulnerableendpoint = True\nRETURN p\nLIMIT 1000", + "query": "MATCH p=(s:Group)-[:AllExtendedRights|ReadLAPSPassword]->(:Computer)\nWHERE s.objectid ENDS WITH '-513'\nRETURN p\nLIMIT 1000", "revision": 1, "resources": [], "acknowledgements": [] }, { - "name": "Tier Zero computers not requiring inbound SMB signing", - "guid": "13485477-f026-4b1f-906d-4f2e37364ba4", + "name": "Domains affected by AdPrep privilege escalation risk", + "guid": "815ff190-f6f3-4757-a516-2f4bf589b705", "prebuilt": false, "platforms": [ "Active Directory" ], - "category": "NTLM Relay Attacks", + "category": "Dangerous Privileges", "description": null, - "query": "MATCH (n:Computer)\nWHERE n.smbsigning = False\nAND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN n", + "query": "MATCH p=(n:Group)-[r:GenericAll]->(m:Domain)\nWHERE n.objectid ENDS WITH \"-527\" // Enterprise Key Admins\nAND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')\nRETURN p", + "revision": 1, + "resources": [], + "acknowledgements": [ + "Martin Sohn Christensen, @martinsohndk" + ] + }, + { + "name": "Smart card accounts with passwords not rotated in over 1 year", + "guid": "7e56f2e7-79c3-4f0d-aa3e-14cf3de7ab73", + "prebuilt": false, + "platforms": [ + "Active Directory" + ], + "category": "Active Directory Hygiene", + "description": null, + "query": "MATCH (n:Base)\nWHERE n.pwdlastset < (datetime().epochseconds - (365 * 86400))\nAND n.enabled = true\nAND n.smartcardrequired = true\nRETURN n", "revision": 1, "resources": [], "acknowledgements": [ "Martin Sohn Christensen, @martinsohndk" ] + }, + { + "name": "Dangerous privileges for Domain Users groups", + "guid": "9b8b9c18-f8c6-4c54-a20f-de0f7a7edbe0", + "prebuilt": true, + "platforms": [ + "Active Directory" + ], + "category": "Dangerous Privileges", + "description": null, + "query": "MATCH p=(s:Group)-[r:AD_ATTACK_PATHS]->(:Base)\nWHERE s.objectid ENDS WITH '-513'\nAND NOT r:MemberOf\nRETURN p\nLIMIT 1000", + "revision": 3, + "resources": [], + "acknowledgements": [] } ] \ No newline at end of file