diff --git a/README.md b/README.md index aab59b2..9ea7620 100644 --- a/README.md +++ b/README.md @@ -40,10 +40,10 @@ One of BloodHound’s key features is its flexibility through Cypher queries – Queries can answer anything from simple questions (e.g., “*Which users haven’t reset their passwords in 180 days?*”), to complex identity attack path problems (e.g., “*Which low-privileged users can compromise computers hosting a gMSA with unconstrained delegation?*”). -The library gives you practical examples for learning Cypher and can be combined with the following resources: +The library gives you practical examples for learning Cypher and can be combined with these resources: - [BloodHound documentation: Searching with Cypher](https://support.bloodhoundenterprise.io/hc/en-us/articles/16721164740251) - [openCypher resources](https://opencypher.org/resources/) -- [Neo4j Cypher Cheat Sheet](https://opencypher.org/resources/) +- [Neo4j Cypher Cheat Sheet](https://neo4j.com/docs/cypher-cheat-sheet/current/lists/) You can also learn with the communty by joining the #cypher_queries channel in the [BloodHound community Slack](https://support.bloodhoundenterprise.io/hc/en-us/articles/16730536907547). diff --git a/queries/ACEs across trusts.yml b/queries/ACEs across trusts.yml new file mode 100644 index 0000000..a170a8e --- /dev/null +++ b/queries/ACEs across trusts.yml @@ -0,0 +1,18 @@ +name: ACEs across trusts +guid: c902d3b4-1a75-4335-acd7-28246dab746d +prebuilt: false +platform: 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) + WHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid + AND r.isacl + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgement: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/AS-REP Roastable Tier Zero users (DontReqPreAuth).yml b/queries/AS-REP Roastable Tier Zero users (DontReqPreAuth).yml new file mode 100644 index 0000000..a363c4d --- /dev/null +++ b/queries/AS-REP Roastable Tier Zero users (DontReqPreAuth).yml @@ -0,0 +1,16 @@ +name: AS-REP Roastable Tier Zero users (DontReqPreAuth) +guid: 6d51e4dc-e1ad-477a-b6c6-324f18f03120 +prebuilt: false +platform: 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.dontreqpreauth = true + RETURN n +note: +revision: 1 +resources: https://attack.mitre.org/techniques/T1558/004/ +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/AS-REP Roastable users (DontReqPreAuth).yml b/queries/AS-REP Roastable users (DontReqPreAuth).yml new file mode 100644 index 0000000..91285ec --- /dev/null +++ b/queries/AS-REP Roastable users (DontReqPreAuth).yml @@ -0,0 +1,17 @@ +name: AS-REP Roastable users (DontReqPreAuth) +guid: 2570e359-dec1-419d-b0dc-a204bd64ee42 +prebuilt: true +platform: Active Directory +category: Kerberos Interaction +description: +query: |- + MATCH (u:User) + WHERE u.dontreqpreauth = true + AND u.enabled = true + RETURN u + LIMIT 100 +note: +revision: 1 +resources: https://attack.mitre.org/techniques/T1558/004/ +acknowledgements: + diff --git a/queries/Accounts with SID History to a non-existent domain.yml b/queries/Accounts with SID History to a non-existent domain.yml new file mode 100644 index 0000000..c7e1a49 --- /dev/null +++ b/queries/Accounts with SID History to a non-existent domain.yml @@ -0,0 +1,17 @@ +name: Accounts with SID History to a non-existent domain +guid: 2710401a-c4c2-4d2c-9edb-d7625045f2e8 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (d:Domain) + WITH collect(d.objectid) AS domainSIDs + MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base) + WHERE NOT n.domainsid IN domainSIDs + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Accounts with SID History to a same-domain account.yml b/queries/Accounts with SID History to a same-domain account.yml new file mode 100644 index 0000000..7605550 --- /dev/null +++ b/queries/Accounts with SID History to a same-domain account.yml @@ -0,0 +1,15 @@ +name: Accounts with SID History to a same-domain account +guid: 275d2d58-0cad-4cad-8103-e0874cece666 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base) + WHERE n.domainsid = m.domainsid + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Accounts with SID History.yml b/queries/Accounts with SID History.yml new file mode 100644 index 0000000..a3cd2b8 --- /dev/null +++ b/queries/Accounts with SID History.yml @@ -0,0 +1,14 @@ +name: Accounts with SID History +guid: 8172d52c-a975-49bd-9180-5b6efc59c9ab +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(:Base)-[:HasSIDHistory]->(:Base) + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Accounts with clear-text password attributes.yml b/queries/Accounts with clear-text password attributes.yml new file mode 100644 index 0000000..b187bd8 --- /dev/null +++ b/queries/Accounts with clear-text password attributes.yml @@ -0,0 +1,18 @@ +name: Accounts with clear-text password attributes +guid: e303498f-e3d4-489d-8a34-b68e187bc4e7 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Base) + WHERE n.userpassword IS NOT NULL + OR n.unixpassword IS NOT NULL + OR n.unicodepwd IS NOT NULL + OR n.msSFU30Password IS NOT NULL + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/Queries/Active Directory/Domain Information/AdminSDHolder protected Accounts and Groups.yml b/queries/AdminSDHolder protected Accounts and Groups.yml similarity index 76% rename from Queries/Active Directory/Domain Information/AdminSDHolder protected Accounts and Groups.yml rename to queries/AdminSDHolder protected Accounts and Groups.yml index 3cd19a1..0c0e9b6 100644 --- a/Queries/Active Directory/Domain Information/AdminSDHolder protected Accounts and Groups.yml +++ b/queries/AdminSDHolder protected Accounts and Groups.yml @@ -1,14 +1,15 @@ name: AdminSDHolder protected Accounts and Groups guid: 5ee2f40e-a55c-4140-ab8a-91746ba3752b +prebuilt: false platform: 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) WHERE ( - 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 - 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 - OR n.objectid =~ ".*-(500|502|516|521)" // Direct objects + 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 + 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 + OR n.objectid =~ ".*-(500|502|516|521)$" // Direct objects ) RETURN n note: @@ -17,4 +18,5 @@ 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 acknowledgement: +acknowledgements: Martin Sohn Christensen, @martinsohndk diff --git a/queries/All ADCS ESC privilege escalation edges.yml b/queries/All ADCS ESC privilege escalation edges.yml new file mode 100644 index 0000000..5ebf2cc --- /dev/null +++ b/queries/All ADCS ESC privilege escalation edges.yml @@ -0,0 +1,20 @@ +name: All ADCS ESC privilege escalation edges +guid: 49db8edc-8421-438f-b97b-23c042959bef +prebuilt: false +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p=(:Base)-[:ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|GoldenCert|CoerceAndRelayNTLMToADCS]->(:Base) + RETURN p +note: +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ülow Knudsen, @Jonas_B_K + diff --git a/queries/All DNSAdmins.yml b/queries/All DNSAdmins.yml new file mode 100644 index 0000000..016983c --- /dev/null +++ b/queries/All DNSAdmins.yml @@ -0,0 +1,15 @@ +name: All DNSAdmins +guid: 183fb320-f3ae-4ab3-a090-3f9a7db692e1 +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p=(n:Base)-[:MemberOf]->(g:Group) + WHERE n.name STARTS WITH "DNSADMINS@" + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/All Domain Admins.yml b/queries/All Domain Admins.yml new file mode 100644 index 0000000..7aaa9c9 --- /dev/null +++ b/queries/All Domain Admins.yml @@ -0,0 +1,16 @@ +name: All Domain Admins +guid: 0596dba7-9180-49a0-aa54-00243240037c +prebuilt: true +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p = (t:Group)<-[:MemberOf*1..]-(a) + WHERE (a:User or a:Computer) and t.objectid ENDS WITH '-512' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/All Global Administrators.yml b/queries/All Global Administrators.yml new file mode 100644 index 0000000..b74e56e --- /dev/null +++ b/queries/All Global Administrators.yml @@ -0,0 +1,15 @@ +name: All Global Administrators +guid: 94d7d765-6837-4eb8-aa33-e1c9ef262cdc +prebuilt: true +platform: Azure +category: General +description: +query: |- + MATCH p = (:AZBase)-[:AZGlobalAdmin*1..]->(:AZTenant) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/All Kerberoastable users.yml b/queries/All Kerberoastable users.yml new file mode 100644 index 0000000..a5385bb --- /dev/null +++ b/queries/All Kerberoastable users.yml @@ -0,0 +1,20 @@ +name: All Kerberoastable users +guid: 14ab4eaa-b73b-49c4-b2d1-1e020757c995 +prebuilt: true +platform: Active Directory +category: Kerberos Interaction +description: +query: |- + MATCH (u:User) + WHERE 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 +note: +revision: 1 +resources: https://attack.mitre.org/techniques/T1558/003/ +acknowledgements: + diff --git a/queries/All Operator groups.yml b/queries/All Operator groups.yml new file mode 100644 index 0000000..3fac95d --- /dev/null +++ b/queries/All Operator groups.yml @@ -0,0 +1,23 @@ +name: All Operators +guid: 3dfd0843-1ff9-4c21-aa67-feae08d109de +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p=(:Base)-[:MemberOf]->(n:Group) + WHERE ( + n.objectid ENDS WITH 'S-1-5-32-551' OR // Backup Operators + n.objectid ENDS WITH 'S-1-5-32-556' OR // Network Configuration Operators + n.objectid ENDS WITH 'S-1-5-32-549' OR // Server Operators + n.objectid ENDS WITH 'S-1-5-32-579' OR // Access Control Assistance Operators + n.objectid ENDS WITH 'S-1-5-32-548' OR // Account Operators + n.objectid ENDS WITH 'S-1-5-32-569' OR // Cryptographic Operators + n.objectid ENDS WITH 'S-1-5-32-550' // Print Operators + ) + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/All Schema Admins.yml b/queries/All Schema Admins.yml new file mode 100644 index 0000000..1887192 --- /dev/null +++ b/queries/All Schema Admins.yml @@ -0,0 +1,16 @@ +name: All Schema Admins +guid: 76d8e61d-7a86-40ff-8a85-fd37f1e2563f +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p=(n:Base)-[:MemberOf*1..]->(m:Group) + WHERE (n:User OR n:Computer) + AND m.objectid ENDS WITH "-518" // Schema Admins + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/All coerce and NTLM relay edges.yml b/queries/All coerce and NTLM relay edges.yml new file mode 100644 index 0000000..51b91a0 --- /dev/null +++ b/queries/All coerce and NTLM relay edges.yml @@ -0,0 +1,14 @@ +name: All coerce and NTLM relay edges +guid: 15c5ff3b-856c-44d1-a731-a8cb72512dd1 +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH p = (n:Base)-[:CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|CoerceAndRelayNTLMToADCS|CoerceAndRelayNTLMToSMB]->(:Base) + RETURN p LIMIT 500 +note: +revision: 1 +resources: https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/ +acknowledgements: + 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 new file mode 100644 index 0000000..c6027a4 --- /dev/null +++ b/queries/All incoming and local paths for a specific computer.yml @@ -0,0 +1,18 @@ +name: All incoming and local paths for a specific computer +guid: 1f67e538-19d4-4020-89c8-5b39b31571bd +prebuilt: false +platform: 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 + MATCH p=(n:Base)-[:RemoteInteractiveLogonPrivilege|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 +note: +revision: 1 +resources: +acknowledgement: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/All members of high privileged roles.yml b/queries/All members of high privileged roles.yml new file mode 100644 index 0000000..96c312e --- /dev/null +++ b/queries/All members of high privileged roles.yml @@ -0,0 +1,16 @@ +name: All members of high privileged roles +guid: 3df24d92-dd12-4125-811b-e696b098f60e +prebuilt: true +platform: Azure +category: General +description: +query: |- + MATCH p=(t:AZRole)<-[:AZHasRole|AZMemberOf*1..2]-(:AZBase) + WHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/All paths crossing a specific trust.yml b/queries/All paths crossing a specific trust.yml new file mode 100644 index 0000000..f8fed6f --- /dev/null +++ b/queries/All paths crossing a specific trust.yml @@ -0,0 +1,20 @@ +name: All paths crossing a specific trust +guid: 251fc893-7a6b-4a0a-8650-9d5408d38c3c +prebuilt: false +platform: 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 + // Replace the TRUSTING domain SID + MATCH p=(Trusted:Base)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation]->(Trusting:Base) + WHERE Trusted.domainsid = 'S-1-5-21-1111111111-1111111111-1111111111' + AND Trusting.domainsid = 'S-1-5-21-2222222222-2222222222-2222222222' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgement: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/All service principals with Microsoft Graph App Role assignments.yml b/queries/All service principals with Microsoft Graph App Role assignments.yml new file mode 100644 index 0000000..59a4ad9 --- /dev/null +++ b/queries/All service principals with Microsoft Graph App Role assignments.yml @@ -0,0 +1,15 @@ +name: All service principals with Microsoft Graph App Role assignments +guid: 74440269-eb41-476b-8dec-b4095569b029 +prebuilt: true +platform: Azure +category: Microsoft Graph +description: +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) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/All service principals with Microsoft Graph privilege to grant arbitrary App Roles.yml b/queries/All service principals with Microsoft Graph privilege to grant arbitrary App Roles.yml new file mode 100644 index 0000000..a76a982 --- /dev/null +++ b/queries/All service principals with Microsoft Graph privilege to grant arbitrary App Roles.yml @@ -0,0 +1,15 @@ +name: All service principals with Microsoft Graph privilege to grant arbitrary App Roles +guid: e6d6b5da-89da-4514-a409-2d6e368397da +prebuilt: true +platform: Azure +category: Microsoft Graph +description: +query: |- + MATCH p=(:AZServicePrincipal)-[:AZMGGrantAppRoles]->(:AZTenant) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/CA administrators and CA managers.yml b/queries/CA administrators and CA managers.yml new file mode 100644 index 0000000..04cd20a --- /dev/null +++ b/queries/CA administrators and CA managers.yml @@ -0,0 +1,15 @@ +name: CA administrators and CA managers +guid: fd35e3d8-0c74-4b5a-a847-c0dd1f1c9f19 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computer owners who can obtain LAPS passwords.yml b/queries/Computer owners who can obtain LAPS passwords.yml new file mode 100644 index 0000000..b22bc4c --- /dev/null +++ b/queries/Computer owners who can obtain LAPS passwords.yml @@ -0,0 +1,15 @@ +name: Computer owners who can obtain LAPS passwords +guid: 92aa81d6-b08e-4abb-ae39-ecbe5735a74c +prebuilt: false +platform: 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) + WHERE c.haslaps = true AND c.ownersid = n.objectid + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Computers not requiring inbound SMB signing.yml b/queries/Computers not requiring inbound SMB signing.yml new file mode 100644 index 0000000..997b6fd --- /dev/null +++ b/queries/Computers not requiring inbound SMB signing.yml @@ -0,0 +1,15 @@ +name: Computers not requiring inbound SMB signing +guid: 6b1fcfb6-b010-41a2-9d31-f9872fe994ff +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH (n:Computer) + WHERE n.smbsigning = False + RETURN n +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computers where Domain Users are local administrators.yml b/queries/Computers where Domain Users are local administrators.yml new file mode 100644 index 0000000..5f6bb7a --- /dev/null +++ b/queries/Computers where Domain Users are local administrators.yml @@ -0,0 +1,16 @@ +name: Computers where Domain Users are local administrators +guid: d43a7bdc-33c6-4a39-a3bb-24115749e595 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(s:Group)-[:AdminTo]->(:Computer) + WHERE s.objectid ENDS WITH '-513' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computers where Domain Users can read LAPS passwords.yml b/queries/Computers where Domain Users can read LAPS passwords.yml new file mode 100644 index 0000000..187271e --- /dev/null +++ b/queries/Computers where Domain Users can read LAPS passwords.yml @@ -0,0 +1,16 @@ +name: Computers where Domain Users can read LAPS passwords +guid: aa4bfa95-e7b9-4d56-8f35-f34f04d7b6f4 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(s:Group)-[:AllExtendedRights|ReadLAPSPassword]->(:Computer) + WHERE s.objectid ENDS WITH '-513' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computers with membership in Protected Users.yml b/queries/Computers with membership in Protected Users.yml new file mode 100644 index 0000000..ff115f8 --- /dev/null +++ b/queries/Computers with membership in Protected Users.yml @@ -0,0 +1,15 @@ +name: Computers with membership in Protected Users +guid: a26372f4-2e92-49f6-8993-6657fbc1569a +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH p = (:Base)-[:MemberOf*1..]->(g:Group) + WHERE g.objectid ENDS WITH "-525" + RETURN p LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computers with non-default Primary Group membership.yml b/queries/Computers with non-default Primary Group membership.yml new file mode 100644 index 0000000..922a645 --- /dev/null +++ b/queries/Computers with non-default Primary Group membership.yml @@ -0,0 +1,18 @@ +name: Computers with non-default Primary Group membership +guid: 5862dc4e-6f6f-4321-9474-d838968495ed +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +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 r.isprimarygroup = true + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Computers with passwords older than the default maximum password age.yml b/queries/Computers with passwords older than the default maximum password age.yml new file mode 100644 index 0000000..e0b3f2a --- /dev/null +++ b/queries/Computers with passwords older than the default maximum password age.yml @@ -0,0 +1,20 @@ +name: Computers with passwords older than the default maximum password age +guid: 185c5010-8d4f-4f9b-b24e-831707dddfca +prebuilt: false +platform: 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 + MATCH (n:Computer) + WHERE n.pwdlastset < (datetime().epochseconds - (rotation_period * 86400)) // password not rotated + AND n.enabled = true // enabled computers + AND n.whencreated < (datetime().epochseconds - (rotation_period * 86400)) // exclude recently created computers + AND n.lastlogontimestamp > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Replicated value) + AND n.lastlogon > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Non-replicated value) + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/disable-machine-account-password +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Computers with the WebClient running.yml b/queries/Computers with the WebClient running.yml new file mode 100644 index 0000000..df6327d --- /dev/null +++ b/queries/Computers with the WebClient running.yml @@ -0,0 +1,15 @@ +name: Computers with the WebClient running +guid: 51107ad1-f0bc-43d3-a561-5cee471ca196 +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH (c:Computer) + WHERE c.webclientrunning = True + RETURN c LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computers with the outgoing NTLM setting set to Deny all.yml b/queries/Computers with the outgoing NTLM setting set to Deny all.yml new file mode 100644 index 0000000..4d2ee63 --- /dev/null +++ b/queries/Computers with the outgoing NTLM setting set to Deny all.yml @@ -0,0 +1,15 @@ +name: Computers with the outgoing NTLM setting set to Deny all +guid: a9ddca74-feeb-4dbf-8b0f-de08b3cfa8a6 +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH (c:Computer) + WHERE c.restrictoutboundntlm = True + RETURN c LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Computers with unsupported operating systems.yml b/queries/Computers with unsupported operating systems.yml new file mode 100644 index 0000000..5a7db47 --- /dev/null +++ b/queries/Computers with unsupported operating systems.yml @@ -0,0 +1,16 @@ +name: Computers with unsupported operating systems +guid: d06d3b14-0318-4fa9-9639-4b79ccaf3c2c +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (c:Computer) + WHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*' + RETURN c + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Cross-forest trusts with abusable configuration.yml b/queries/Cross-forest trusts with abusable configuration.yml new file mode 100644 index 0000000..e8c88fe --- /dev/null +++ b/queries/Cross-forest trusts with abusable configuration.yml @@ -0,0 +1,15 @@ +name: Cross-forest trusts with abusable configuration +guid: 5cf1f354-80d4-420e-bc4b-424fabc21a56 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Domain)-[:CrossForestTrust|SpoofSIDHistory|AbuseTGTDelegation]-(m:Domain) + WHERE (n)-[:SpoofSIDHistory|AbuseTGTDelegation]-(m) + RETURN p +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/DCs vulnerable to NTLM relay to LDAP attacks.yml b/queries/DCs vulnerable to NTLM relay to LDAP attacks.yml new file mode 100644 index 0000000..a07adb0 --- /dev/null +++ b/queries/DCs vulnerable to NTLM relay to LDAP attacks.yml @@ -0,0 +1,17 @@ +name: DCs vulnerable to NTLM relay to LDAP attacks +guid: 3f87e0b0-fc06-4986-a94c-e08781253dc8 +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH p = (dc:Computer)-[:DCFor]->(:Domain) + WHERE (dc.ldapavailable = True AND dc.ldapsigning = False) + OR (dc.ldapsavailable = True AND dc.ldapsepa = False) + OR (dc.ldapavailable = True AND dc.ldapsavailable = True AND dc.ldapsigning = False and dc.ldapsepa = True) + RETURN p +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Dangerous privileges for Domain Users groups.yml b/queries/Dangerous privileges for Domain Users groups.yml new file mode 100644 index 0000000..dd1fb93 --- /dev/null +++ b/queries/Dangerous privileges for Domain Users groups.yml @@ -0,0 +1,16 @@ +name: Dangerous privileges for Domain Users groups +guid: 9b8b9c18-f8c6-4c54-a20f-de0f7a7edbe0 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(s:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation]->(:Base) + WHERE s.objectid ENDS WITH '-513' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Devices with unsupported operating systems.yml b/queries/Devices with unsupported operating systems.yml new file mode 100644 index 0000000..42abc49 --- /dev/null +++ b/queries/Devices with unsupported operating systems.yml @@ -0,0 +1,17 @@ +name: Devices with unsupported operating systems +guid: e3f2b53a-7ce6-4e52-9c74-68b69338288b +prebuilt: true +platform: Azure +category: Azure Hygiene +description: +query: |- + MATCH (n:AZDevice) + WHERE n.operatingsystem CONTAINS 'WINDOWS' + AND 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).?.*' + RETURN n + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Disabled Tier Zero High Value principals - AD.yml b/queries/Disabled Tier Zero High Value principals - AD.yml new file mode 100644 index 0000000..693bc2b --- /dev/null +++ b/queries/Disabled Tier Zero High Value principals - AD.yml @@ -0,0 +1,19 @@ +name: Disabled Tier Zero / High Value principals +guid: d65a801f-d3ef-4b7e-8030-99ebfd6dad12 +prebuilt: true +platform: 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.enabled = false + AND NOT n.objectid ENDS WITH '-502' // Removes false positive, KRBTGT + AND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator + RETURN n + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Disabled Tier Zero High Value principals - AZ.yml b/queries/Disabled Tier Zero High Value principals - AZ.yml new file mode 100644 index 0000000..a0582ab --- /dev/null +++ b/queries/Disabled Tier Zero High Value principals - AZ.yml @@ -0,0 +1,17 @@ +name: Disabled Tier Zero / High Value principals +guid: 860d5c2d-84fe-4c85-80de-e0a9badbd0e7 +prebuilt: true +platform: Azure +category: Azure Hygiene +description: +query: |- + MATCH (n:AZBase) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND n.enabled = false + RETURN n + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Domain Admins logons to non-Domain Controllers.yml b/queries/Domain Admins logons to non-Domain Controllers.yml new file mode 100644 index 0000000..a590c9f --- /dev/null +++ b/queries/Domain Admins logons to non-Domain Controllers.yml @@ -0,0 +1,19 @@ +name: Domain Admins logons to non-Domain Controllers +guid: e2f3fd0a-1df2-4089-b0a4-272ad6e369a9 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH (s)-[:MemberOf*0..]->(g:Group) + WHERE g.objectid ENDS WITH '-516' + WITH COLLECT(s) AS exclude + MATCH p = (c:Computer)-[:HasSession]->(:User)-[:MemberOf*1..]->(g:Group) + WHERE g.objectid ENDS WITH '-512' AND NOT c IN exclude + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Domain Controllers allowing NTLMv1 or LM authentication.yml b/queries/Domain Controllers allowing NTLMv1 or LM authentication.yml new file mode 100644 index 0000000..b007ef2 --- /dev/null +++ b/queries/Domain Controllers allowing NTLMv1 or LM authentication.yml @@ -0,0 +1,16 @@ +name: Domain Controllers allowing NTLMv1 or LM authentication +guid: 4b42513c-f89d-47ff-8d98-908af49d2b48 +prebuilt: false +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH (dc:Computer) + WHERE dc.isdc = true + AND (dc.lmcompatibilitylevel IS NOT NULL AND NOT dc.lmcompatibilitylevel = 5) + RETURN dc +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domain controllers with UPN certificate mapping enabled.yml b/queries/Domain controllers with UPN certificate mapping enabled.yml new file mode 100644 index 0000000..9afefc9 --- /dev/null +++ b/queries/Domain controllers with UPN certificate mapping enabled.yml @@ -0,0 +1,18 @@ +name: Domain controllers with UPN certificate mapping enabled +guid: 799ea3ce-572b-4594-98c4-041aa2ae6176 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (s:Computer)-[:DCFor]->(:Domain) + WHERE s.certificatemappingmethodsraw IN [4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31] + RETURN p + LIMIT 1000 +note: +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ülow Knudsen, @Jonas_B_K + diff --git a/queries/Domain controllers with weak certificate binding enabled.yml b/queries/Domain controllers with weak certificate binding enabled.yml new file mode 100644 index 0000000..8991072 --- /dev/null +++ b/queries/Domain controllers with weak certificate binding enabled.yml @@ -0,0 +1,16 @@ +name: Domain controllers with weak certificate binding enabled +guid: a2444d99-10b5-412d-8fea-4b063cfddd2c +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (s:Computer)-[:DCFor]->(:Domain) + WHERE s.strongcertificatebindingenforcementraw = 0 OR s.strongcertificatebindingenforcementraw = 1 + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Domain migration groups.yml b/queries/Domain migration groups.yml new file mode 100644 index 0000000..16829ab --- /dev/null +++ b/queries/Domain migration groups.yml @@ -0,0 +1,15 @@ +name: Domain migration groups +guid: f39c4953-ae92-4d67-bb50-eb1a161d4d3f +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH (n:Group) + WHERE n.name CONTAINS "$$$@" + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains affected by AdPrep privilege escalation risk.yml b/queries/Domains affected by AdPrep privilege escalation risk.yml new file mode 100644 index 0000000..72d50b6 --- /dev/null +++ b/queries/Domains affected by AdPrep privilege escalation risk.yml @@ -0,0 +1,16 @@ +name: Domains affected by AdPrep privilege escalation risk +guid: 815ff190-f6f3-4757-a516-2f4bf589b705 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Group)-[r:GenericAll]->(m:Domain) + WHERE n.objectid ENDS WITH "-527" // Enterprise Key Admins + AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains affected by Exchange privilege escalation risk.yml b/queries/Domains affected by Exchange privilege escalation risk.yml new file mode 100644 index 0000000..bc39172 --- /dev/null +++ b/queries/Domains affected by Exchange privilege escalation risk.yml @@ -0,0 +1,16 @@ +name: Domains affected by Exchange privilege escalation risk +guid: f2d09c94-b6f2-4901-9a2d-f8bacd61edc7 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Group)-[r:WriteDacl|ForceChangePassword|AddMember]->(m:Base) + WHERE n.name STARTS WITH "EXCHANGE " + AND ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains allowing authenticated domain enumeration.yml b/queries/Domains allowing authenticated domain enumeration.yml new file mode 100644 index 0000000..e3eda79 --- /dev/null +++ b/queries/Domains allowing authenticated domain enumeration.yml @@ -0,0 +1,16 @@ +name: Domains allowing authenticated domain enumeration +guid: 1e1e6fdd-6973-4547-906c-a494b5fbdcba +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Group)-[:MemberOf]->(m:Group) + WHERE n.objectid ENDS WITH "S-1-5-11" // Authenticated Users + AND m.objectid ENDS WITH "S-1-5-32-554" // Pre-Windows 2000 Compatible Access + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains allowing unauthenticated NSPI RPC binds.yml b/queries/Domains allowing unauthenticated NSPI RPC binds.yml new file mode 100644 index 0000000..a52da71 --- /dev/null +++ b/queries/Domains allowing unauthenticated NSPI RPC binds.yml @@ -0,0 +1,15 @@ +name: Domains allowing unauthenticated NSPI RPC binds +guid: a950fdab-5934-4c69-a88b-e2e0e3da9d52 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: Checks the fAllowAnonNSPI flag of dSHeuristics. +query: |- + MATCH (n:Domain) + WHERE n.dsheuristics =~ ".{7}[^0].*" + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5 +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains allowing unauthenticated domain enumeration.yml b/queries/Domains allowing unauthenticated domain enumeration.yml new file mode 100644 index 0000000..7c971e7 --- /dev/null +++ b/queries/Domains allowing unauthenticated domain enumeration.yml @@ -0,0 +1,17 @@ +name: Domains allowing unauthenticated domain enumeration +guid: 41a08d76-f8a5-4296-ad19-464c4c5c69fe +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Group)-[:MemberOf]->(m:Group) + WHERE (n.objectid ENDS WITH "S-1-5-7" // Anonymous + OR n.objectid ENDS WITH "S-1-1-0") // Everyone + AND m.objectid ENDS WITH "S-1-5-32-554" // Pre-Windows 2000 Compatible Access + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains allowing unauthenticated rootDSE searches and binds.yml b/queries/Domains allowing unauthenticated rootDSE searches and binds.yml new file mode 100644 index 0000000..97210c0 --- /dev/null +++ b/queries/Domains allowing unauthenticated rootDSE searches and binds.yml @@ -0,0 +1,15 @@ +name: Domains allowing unauthenticated rootDSE searches and binds +guid: ebc79aa4-e816-4be8-93fe-a0b30dbc771d +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: Checks the fLDAPBlockAnonOps flag of dSHeuristics. +query: |- + MATCH (n:Domain) + WHERE n.dsheuristics =~ ".{6}[^2].*" + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5 +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains exempting privileged groups from AdminSDHolder protections.yml b/queries/Domains exempting privileged groups from AdminSDHolder protections.yml new file mode 100644 index 0000000..a99ef25 --- /dev/null +++ b/queries/Domains exempting privileged groups from AdminSDHolder protections.yml @@ -0,0 +1,15 @@ +name: Domains exempting privileged groups from AdminSDHolder protections +guid: 79f8d8f9-8291-4bf7-a13a-15989018075f +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: Checks the dwAdminSDExMask flag of dSHeuristics. +query: |- + MATCH (n:Domain) + WHERE n.dsheuristics =~ ".{15}[^0].*" + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5 +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains not mitigating CVE-2021-42291.yml b/queries/Domains not mitigating CVE-2021-42291.yml new file mode 100644 index 0000000..bfab6c3 --- /dev/null +++ b/queries/Domains not mitigating CVE-2021-42291.yml @@ -0,0 +1,15 @@ +name: Domains not mitigating CVE-2021-42291 +guid: 02202726-d86d-46c2-891c-9770c635f76f +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: Checks the AttributeAuthorizationOnLDAPAdd flag of dSHeuristics. +query: |- + MATCH (n:Domain) + WHERE n.dsheuristics =~ ".{27}[^1].*" + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5 +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains not verifying UPN and SPN uniqueness.yml b/queries/Domains not verifying UPN and SPN uniqueness.yml new file mode 100644 index 0000000..bd76063 --- /dev/null +++ b/queries/Domains not verifying UPN and SPN uniqueness.yml @@ -0,0 +1,15 @@ +name: Domains not verifying UPN and SPN uniqueness +guid: cb0b1591-5c3e-45f1-afb7-984e5ad865d0 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: Checks the DoNotVerifyUPNAndOrSPNUniqueness flag of dSHeuristics. +query: |- + MATCH (n:Domain) + WHERE n.dsheuristics =~ ".{20}[^0].*" + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5 +acknowledgements: Martin Sohn Christensen, @martinsohndk + 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 new file mode 100644 index 0000000..5b5feec --- /dev/null +++ b/queries/Domains where any user can join a computer to the domain.yml @@ -0,0 +1,17 @@ +name: Domains where any user can join a computer to the domain +guid: 421921fa-bc0f-4659-9680-b7481adcb132 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Domain) + WHERE n.machineaccountquota > 0 + RETURN n +note: Does not check the 'Add workstations to domain' URA Security Policy on DCs. +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 +acknowledgements: + diff --git a/queries/Domains with List Object mode enabled.yml b/queries/Domains with List Object mode enabled.yml new file mode 100644 index 0000000..f1435a2 --- /dev/null +++ b/queries/Domains with List Object mode enabled.yml @@ -0,0 +1,15 @@ +name: Domains with List Object mode enabled +guid: 05e2a94b-5ee6-47ec-b715-3982f30af01b +prebuilt: false +platform: Active Directory +category: Domain Information +description: Checks the fDoListObject flag of dSHeuristics. +query: |- + MATCH (n:Domain) + WHERE n.dsheuristics =~ ".{2}[^0].*" + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5 +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains with a minimum default password policy length less than 15 characters.yml b/queries/Domains with a minimum default password policy length less than 15 characters.yml new file mode 100644 index 0000000..3256332 --- /dev/null +++ b/queries/Domains with a minimum default password policy length less than 15 characters.yml @@ -0,0 +1,15 @@ +name: Domains with a minimum default password policy length less than 15 characters +guid: 7d258d2d-a43d-4a90-85d7-71c946ae5fd7 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Domain) + WHERE n.minpwdlength < 15 + RETURN n +note: NIST recommends 15 characters. +revision: 1 +resources: https://pages.nist.gov/800-63-3/sp800-63b.html +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains with a single-point-of-failure Domain Controller.yml b/queries/Domains with a single-point-of-failure Domain Controller.yml new file mode 100644 index 0000000..e40697e --- /dev/null +++ b/queries/Domains with a single-point-of-failure Domain Controller.yml @@ -0,0 +1,17 @@ +name: Domains with a single-point-of-failure Domain Controller +guid: 3359a295-7cfd-491f-976b-c5a68647431c +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Group)<-[:MemberOf]-(:Computer) + WHERE n.objectid ENDS WITH '-516' + WITH n, COUNT(n) AS dcCount + WHERE dcCount = 1 + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains with functional level not the latest version.yml b/queries/Domains with functional level not the latest version.yml new file mode 100644 index 0000000..0829167 --- /dev/null +++ b/queries/Domains with functional level not the latest version.yml @@ -0,0 +1,15 @@ +name: Domains with functional level not the latest version +guid: 3da9d14a-f1cb-4df7-b3da-8d73ff5c401b +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Domain) + WHERE toString(n.functionallevel) IN ['2008','2003','2003 Interim','2000 Mixed/Native'] + RETURN n +note: Functional level <4 +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains with more than 50 Tier Zero accounts.yml b/queries/Domains with more than 50 Tier Zero accounts.yml new file mode 100644 index 0000000..47caf20 --- /dev/null +++ b/queries/Domains with more than 50 Tier Zero accounts.yml @@ -0,0 +1,17 @@ +name: Domains with more than 50 Tier Zero accounts +guid: f046e95a-5f84-4e83-bcda-6e83f3d8e21a +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (d:Domain)-[:Contains*1..]->(n:Base) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + WITH d, COUNT(n) AS adminCount + WHERE adminCount > 50 + RETURN d +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains with smart card accounts where smart account passwords do not expire.yml b/queries/Domains with smart card accounts where smart account passwords do not expire.yml new file mode 100644 index 0000000..26fe8fc --- /dev/null +++ b/queries/Domains with smart card accounts where smart account passwords do not expire.yml @@ -0,0 +1,17 @@ +name: Domains with smart card accounts where smart account passwords do not expire +guid: 97e05e67-5961-4aba-a8e7-fe5f92334035 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (s:Domain)-[:Contains*1..]->(t:Base) + WHERE s.expirepasswordsonsmartcardonlyaccounts = false + AND t.enabled = true + AND t.smartcardrequired = true + RETURN s +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Domains without Microsoft LAPS computers.yml b/queries/Domains without Microsoft LAPS computers.yml new file mode 100644 index 0000000..2f15ddb --- /dev/null +++ b/queries/Domains without Microsoft LAPS computers.yml @@ -0,0 +1,18 @@ +name: Domains without Microsoft LAPS computers +guid: f9b440b5-732c-4ed3-b6d2-83857db17e1a +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH (d:Domain) + OPTIONAL MATCH (c:Computer) + WHERE c.domainsid = d.objectid AND c.haslaps = true + WITH d, COLLECT(c) AS computers + WHERE SIZE(computers) = 0 + RETURN d +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains without Protected Users group.yml b/queries/Domains without Protected Users group.yml new file mode 100644 index 0000000..0d3ba54 --- /dev/null +++ b/queries/Domains without Protected Users group.yml @@ -0,0 +1,20 @@ +name: Domains without Protected Users group +guid: 8c3e0811-a31b-45b4-a29d-1dce80fa2c5f +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH (n:Domain) + WHERE n.collected = true + OPTIONAL MATCH (m:Group) + WHERE m.name ENDS WITH n.name + AND m.objectid ENDS WITH '-525' + WITH n, m + WHERE m IS NULL + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Domains without automatic password rotation on smart card accounts.yml b/queries/Domains without automatic password rotation on smart card accounts.yml new file mode 100644 index 0000000..e8f6863 --- /dev/null +++ b/queries/Domains without automatic password rotation on smart card accounts.yml @@ -0,0 +1,17 @@ +name: Domains with smart card accounts where smart account passwords do not expire +guid: 97e05e67-5961-4aba-a8e7-fe5f92334035 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (s:Domain)-[:Contains*1..]->(t:Base) + WHERE s.expirepasswordsonsmartcardonlyaccounts = false + AND t.enabled = true + AND t.smartcardrequired = true + RETURN s +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/ESC8-vulnerable Enterprise CAs.yml b/queries/ESC8-vulnerable Enterprise CAs.yml new file mode 100644 index 0000000..6f28d01 --- /dev/null +++ b/queries/ESC8-vulnerable Enterprise CAs.yml @@ -0,0 +1,15 @@ +name: ESC8-vulnerable Enterprise CAs +guid: 60881923-296c-4702-adf7-a4f059dc9bb8 +prebuilt: true +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH (n:EnterpriseCA) + WHERE n.hasvulnerableendpoint=true + RETURN n +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enabled Tier Zero High Value principals inactive for 60 days.yml b/queries/Enabled Tier Zero High Value principals inactive for 60 days.yml new file mode 100644 index 0000000..6cc410d --- /dev/null +++ b/queries/Enabled Tier Zero High Value principals inactive for 60 days.yml @@ -0,0 +1,23 @@ +name: Enabled Tier Zero / High Value principals inactive for 60 days +guid: 72550bcb-3c4f-463d-8973-91a49163dc5a +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + WITH 60 as inactive_days + MATCH (n:Base) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND n.enabled = true + AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value + AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value + AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals + AND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT + AND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator + AND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO + RETURN n +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enabled built-in guest user accounts.yml b/queries/Enabled built-in guest user accounts.yml new file mode 100644 index 0000000..795a0ed --- /dev/null +++ b/queries/Enabled built-in guest user accounts.yml @@ -0,0 +1,16 @@ +name: Enabled built-in guest user accounts +guid: bb0f620d-6a55-4413-ac74-4c82905e8598 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:User) + WHERE n.objectid ENDS WITH "-501" + AND n.enabled = true + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Enabled computers inactive for 180 days - MSSQL Failover Cluster.yml b/queries/Enabled computers inactive for 180 days - MSSQL Failover Cluster.yml new file mode 100644 index 0000000..1001a07 --- /dev/null +++ b/queries/Enabled computers inactive for 180 days - MSSQL Failover Cluster.yml @@ -0,0 +1,24 @@ +name: Enabled computers inactive for 180 days - MSSQL Failover Cluster +guid: d263e621-7f1b-4efb-ad25-098fc7d4fb72 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + WITH 180 as inactive_days + MATCH (n:Computer) + WHERE n.enabled = true + AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value + AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value + AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals + AND ANY(type IN n.serviceprincipalnames WHERE + toLower(type) CONTAINS 'mssqlservercluster' OR + toLower(type) CONTAINS 'mssqlserverclustermgmtapi' OR + toLower(type) CONTAINS 'msclustervirtualserver') + RETURN n + LIMIT 1000 +note: +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 + diff --git a/queries/Enabled computers inactive for 180 days.yml b/queries/Enabled computers inactive for 180 days.yml new file mode 100644 index 0000000..fd6bc42 --- /dev/null +++ b/queries/Enabled computers inactive for 180 days.yml @@ -0,0 +1,22 @@ +name: Enabled computers inactive for 180 days +guid: 0768e810-1e1e-4319-a216-76d9c2058644 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + WITH 180 as inactive_days + MATCH (n:Computer) + WHERE n.enabled = true + AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value + AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value + AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals + AND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT + AND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO + RETURN n + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Enabled users inactive for 180 days.yml b/queries/Enabled users inactive for 180 days.yml new file mode 100644 index 0000000..dca249d --- /dev/null +++ b/queries/Enabled users inactive for 180 days.yml @@ -0,0 +1,21 @@ +name: Enabled users inactive for 180 days +guid: 71972f3c-b32d-4023-a841-5cc8cc1c1867 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + WITH 180 as inactive_days + MATCH (n:User) + WHERE n.enabled = true + AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value + AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value + AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals + AND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator + RETURN n + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Enrollment rights on CertTemplates with OIDGroupLink.yml b/queries/Enrollment rights on CertTemplates with OIDGroupLink.yml new file mode 100644 index 0000000..408e774 --- /dev/null +++ b/queries/Enrollment rights on CertTemplates with OIDGroupLink.yml @@ -0,0 +1,15 @@ +name: Enrollment rights on CertTemplates with OIDGroupLink +guid: 140a68eb-d21c-4b75-971f-309225fb2d75 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:ExtendedByPolicy]->(:IssuancePolicy)-[:OIDGroupLink]->(:Group) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled.yml b/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled.yml new file mode 100644 index 0000000..c214ae8 --- /dev/null +++ b/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled.yml @@ -0,0 +1,16 @@ +name: Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled +guid: 96e70597-2d74-4503-a624-f1e30b642894 +prebuilt: true +platform: 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 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enrollment rights on published ESC1 certificate templates.yml b/queries/Enrollment rights on published ESC1 certificate templates.yml new file mode 100644 index 0000000..62839fe --- /dev/null +++ b/queries/Enrollment rights on published ESC1 certificate templates.yml @@ -0,0 +1,19 @@ +name: Enrollment rights on published ESC1 certificate templates +guid: 2af855bc-f48f-4b22-9839-627d8231e425 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA) + WHERE ct.enrolleesuppliessubject = True + AND ct.authenticationenabled = True + AND ct.requiresmanagerapproval = False + AND (ct.authorizedsignatures = 0 OR ct.schemaversion = 1) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enrollment rights on published ESC2 certificate templates.yml b/queries/Enrollment rights on published ESC2 certificate templates.yml new file mode 100644 index 0000000..a6ea12b --- /dev/null +++ b/queries/Enrollment rights on published ESC2 certificate templates.yml @@ -0,0 +1,18 @@ +name: Enrollment rights on published ESC2 certificate templates +guid: ebc77984-1ceb-4ed2-a395-ce1067847941 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(c:CertTemplate)-[:PublishedTo]->(:EnterpriseCA) + WHERE c.requiresmanagerapproval = false + AND (c.effectiveekus = [''] OR '2.5.29.37.0' IN c.effectiveekus) + AND (c.authorizedsignatures = 0 OR c.schemaversion = 1) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enrollment rights on published certificate templates with no security extension.yml b/queries/Enrollment rights on published certificate templates with no security extension.yml new file mode 100644 index 0000000..f781a6c --- /dev/null +++ b/queries/Enrollment rights on published certificate templates with no security extension.yml @@ -0,0 +1,16 @@ +name: Enrollment rights on published certificate templates with no security extension +guid: 0677b70c-4e04-4e89-a6a2-f5764604a6a7 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA) + WHERE ct.nosecurityextension = true + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enrollment rights on published certificate templates.yml b/queries/Enrollment rights on published certificate templates.yml new file mode 100644 index 0000000..e95e17c --- /dev/null +++ b/queries/Enrollment rights on published certificate templates.yml @@ -0,0 +1,15 @@ +name: Enrollment rights on published certificate templates +guid: a4ae2e54-aad3-4bfd-a12d-90cb8a9cbc86 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:PublishedTo]->(:EnterpriseCA) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Enrollment rights on published enrollment agent certificate templates.yml b/queries/Enrollment rights on published enrollment agent certificate templates.yml new file mode 100644 index 0000000..e872839 --- /dev/null +++ b/queries/Enrollment rights on published enrollment agent certificate templates.yml @@ -0,0 +1,18 @@ +name: Enrollment rights on published enrollment agent certificate templates +guid: 8483bf5b-89f1-4723-abb2-c48295f6393e +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA) + WHERE '1.3.6.1.4.1.311.20.2.1' IN ct.effectiveekus + OR '2.5.29.37.0' IN ct.effectiveekus + OR SIZE(ct.effectiveekus) = 0 + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Entra ID SSO accounts not rolling Kerberos decryption key.yml b/queries/Entra ID SSO accounts not rolling Kerberos decryption key.yml new file mode 100644 index 0000000..dfd6158 --- /dev/null +++ b/queries/Entra ID SSO accounts not rolling Kerberos decryption key.yml @@ -0,0 +1,18 @@ +name: Entra ID SSO accounts not rolling Kerberos decryption key +guid: 1867abf8-08e3-4ea8-8f65-8366079d35c4 +prebuilt: false +platform: +- 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) + WHERE n.name STARTS WITH "AZUREADSSOACC." + AND n.pwdlastset < (datetime().epochseconds - (30 * 86400)) + RETURN n +note: +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 + diff --git a/queries/Entra Users synced from On-Prem Users added to Domain Admins group.yml b/queries/Entra Users synced from On-Prem Users added to Domain Admins group.yml new file mode 100644 index 0000000..0257d15 --- /dev/null +++ b/queries/Entra Users synced from On-Prem Users added to Domain Admins group.yml @@ -0,0 +1,18 @@ +name: Entra Users synced from On-Prem Users added to Domain Admins group +guid: 62722d5f-bd93-4d11-beeb-9be261827e4e +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:AZUser)-[:SyncedToADUser]->(:User)-[:MemberOf]->(t:Group) + WHERE t.objectid ENDS WITH '-512' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Foreign principals in Tier Zero High Value targets.yml b/queries/Foreign principals in Tier Zero High Value targets.yml new file mode 100644 index 0000000..8bddf70 --- /dev/null +++ b/queries/Foreign principals in Tier Zero High Value targets.yml @@ -0,0 +1,18 @@ +name: Foreign principals in Tier Zero / High Value targets +guid: 95bec736-86ef-4017-8465-9b9b66548b17 +prebuilt: true +platform: Azure +category: Azure Hygiene +description: +query: |- + MATCH (n:AZServicePrincipal) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND NOT toUpper(n.appownerorganizationid) = toUpper(n.tenantid) + AND n.appownerorganizationid CONTAINS '-' + RETURN n + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/KRBTGT accounts with passwords not rotated in over 1 year.yml b/queries/KRBTGT accounts with passwords not rotated in over 1 year.yml new file mode 100644 index 0000000..3e1b19e --- /dev/null +++ b/queries/KRBTGT accounts with passwords not rotated in over 1 year.yml @@ -0,0 +1,18 @@ +name: KRBTGT accounts with passwords not rotated in over 1 year +guid: 1b3ae310-ffa7-4ce5-a37f-6111aef600c8 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:User) + WHERE (n.objectid ENDS WITH '-502' + OR n.name STARTS WITH 'AZUREADKERBEROS.' + OR n.name STARTS WITH 'KRBTGT_AZUREAD@') + AND n.pwdlastset < (datetime().epochseconds - (365 * 86400)) + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Kerberoastable members of Tier Zero High Value groups.yml b/queries/Kerberoastable members of Tier Zero High Value groups.yml new file mode 100644 index 0000000..cee48d6 --- /dev/null +++ b/queries/Kerberoastable members of Tier Zero High Value groups.yml @@ -0,0 +1,20 @@ +name: Kerberoastable members of Tier Zero / High Value groups +guid: e6da7800-ae06-41cb-80a6-d5421ab2143a +prebuilt: true +platform: Active Directory +category: Kerberos Interaction +description: +query: |- + MATCH (u:User) + WHERE (u:Tag_Tier_Zero) 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 +note: +revision: 1 +resources: https://attack.mitre.org/techniques/T1558/003/ +acknowledgements: + diff --git a/queries/Kerberoastable users with most admin privileges.yml b/queries/Kerberoastable users with most admin privileges.yml new file mode 100644 index 0000000..a9bc680 --- /dev/null +++ b/queries/Kerberoastable users with most admin privileges.yml @@ -0,0 +1,23 @@ +name: Kerberoastable users with most admin privileges +guid: 9907b208-494c-4ba6-846d-485e6de14e17 +prebuilt: true +platform: Active Directory +category: Kerberos Interaction +description: +query: |- + MATCH (u:User) + WHERE 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 + MATCH (u)-[:MemberOf|AdminTo*1..]->(c:Computer) + WITH DISTINCT u, COUNT(c) AS adminCount + RETURN u + ORDER BY adminCount DESC + LIMIT 100 +note: +revision: 1 +resources: https://attack.mitre.org/techniques/T1558/003/ +acknowledgements: + diff --git a/queries/Kerberos-enabled service account member of built-in Admins groups.yml b/queries/Kerberos-enabled service account member of built-in Admins groups.yml new file mode 100644 index 0000000..35f2e6d --- /dev/null +++ b/queries/Kerberos-enabled service account member of built-in Admins groups.yml @@ -0,0 +1,20 @@ +name: Kerberos-enabled service account member of built-in Admins groups +guid: 42a856fc-257a-4142-9592-ca95fd49e579 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Base)-[:MemberOf*1..]->(g:Group) + WHERE ( + g.objectid ENDS WITH '-512' // Domain Admins + OR g.objectid ENDS WITH '-519' // Enterprise Admins + OR g.objectid ENDS WITH '-518' // Schema Admins + ) + AND n.hasspn = true + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Kerberos-enabled service accounts without AES encryption support.yml b/queries/Kerberos-enabled service accounts without AES encryption support.yml new file mode 100644 index 0000000..fdbbe2d --- /dev/null +++ b/queries/Kerberos-enabled service accounts without AES encryption support.yml @@ -0,0 +1,24 @@ +name: Kerberos-enabled service accounts without AES encryption support +guid: cb8cf96e-21c9-422b-9439-390a13446ca6 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Base) + WHERE n.hasspn = true + AND (( + n.supportedencryptiontypes <> ['Not defined'] + AND n.supportedencryptiontypes <> [] + AND NONE(type IN n.supportedencryptiontypes WHERE type CONTAINS 'AES128' OR type CONTAINS 'AES256') + ) + OR (n.pwdlastset < datetime('2008-02-27T00:00:00').epochseconds // Password Last Set before Windows Server 2008 + AND NOT n.pwdlastset IN [-1.0, 0.0] + )) + RETURN n + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Large default group added to computer-local group.yml b/queries/Large default group added to computer-local group.yml new file mode 100644 index 0000000..ad8efec --- /dev/null +++ b/queries/Large default group added to computer-local group.yml @@ -0,0 +1,16 @@ +name: Large default group added to computer-local group +guid: dde133d2-b4d2-4de9-a656-905f3bf066f3 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Group)-[:MemberOfLocalGroup]->(m:ADLocalGroup)-[:LocalToComputer]->(:Computer) + WHERE 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 + AND NOT m.objectid =~ ".*-(545|574|554)$" // Users, Certificate Service DCOM Access, Pre-Windows 2000 Compatible Access + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Large default groups with outbound control of OUs.yml b/queries/Large default groups with outbound control of OUs.yml new file mode 100644 index 0000000..4dfe3f1 --- /dev/null +++ b/queries/Large default groups with outbound control of OUs.yml @@ -0,0 +1,21 @@ +name: Large default groups with outbound control of OUs +guid: 310b3626-f8e6-4ab0-832c-72df6048597f +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Group)-[]->(:OU) + WHERE n.objectid ENDS WITH "-513" // DOMAIN USERS + OR n.objectid ENDS WITH "-515" // DOMAIN COMPUTERS + OR n.objectid ENDS WITH "-S-1-5-11" // AUTHENTICATED USERS + OR n.objectid ENDS WITH "-S-1-1-0" // EVERYONE + OR n.objectid ENDS WITH "S-1-5-32-545" // USERS + OR n.objectid ENDS WITH "S-1-5-32-546" // GUESTS + OR n.objectid ENDS WITH "S-1-5-7" // ANONYMOUS + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Large default groups with outbound control.yml b/queries/Large default groups with outbound control.yml new file mode 100644 index 0000000..93812ed --- /dev/null +++ b/queries/Large default groups with outbound control.yml @@ -0,0 +1,21 @@ +name: Large default groups with outbound control +guid: a334f21a-3d7f-448e-b7ea-1465a3127bce +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +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) + WHERE n.objectid ENDS WITH "-513" // DOMAIN USERS + OR n.objectid ENDS WITH "-515" // DOMAIN COMPUTERS + OR n.objectid ENDS WITH "-S-1-5-11" // AUTHENTICATED USERS + OR n.objectid ENDS WITH "-S-1-1-0" // EVERYONE + OR n.objectid ENDS WITH "S-1-5-32-545" // USERS + OR n.objectid ENDS WITH "S-1-5-32-546" // GUESTS + OR n.objectid ENDS WITH "S-1-5-7" // ANONYMOUS + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Locations of Tier Zero High Value objects.yml b/queries/Locations of Tier Zero High Value objects.yml new file mode 100644 index 0000000..81bf199 --- /dev/null +++ b/queries/Locations of Tier Zero High Value objects.yml @@ -0,0 +1,16 @@ +name: Locations of Tier Zero / High Value objects +guid: 18a83a17-b451-4343-acfe-7620516e2968 +prebuilt: true +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p = (t:Base)<-[:Contains*1..]-(:Domain) + WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/Queries/Azure/General/Map Azure Management structure.yml b/queries/Map Azure Management structure.yml similarity index 68% rename from Queries/Azure/General/Map Azure Management structure.yml rename to queries/Map Azure Management structure.yml index ab403ea..818ac0d 100644 --- a/Queries/Azure/General/Map Azure Management structure.yml +++ b/queries/Map Azure Management structure.yml @@ -1,7 +1,8 @@ name: Map Azure Management structure guid: c1bb109e-e6a4-4c91-864f-f78e1e42615e +prebuilt: false platform: Azure -category: General +category: Kerberos Interaction description: Maps the structure of Azure Management query: |- MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup) @@ -10,4 +11,6 @@ query: |- note: revision: 1 resources: https://learn.microsoft.com/en-us/azure/governance/management-groups/overview -acknowledgement: Martin Sohn Christensen, @martinsohndk \ No newline at end of file +acknowledgement: Martin Sohn Christensen, @martinsohndk +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Map OU structure.yml b/queries/Map OU structure.yml new file mode 100644 index 0000000..2b1b5ea --- /dev/null +++ b/queries/Map OU structure.yml @@ -0,0 +1,15 @@ +name: Map OU structure +guid: 8f14084b-5065-43d8-865a-a6ac52da25d1 +prebuilt: true +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p = (:Domain)-[:Contains*1..]->(:OU) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Map domain trusts.yml b/queries/Map domain trusts.yml new file mode 100644 index 0000000..2046ed0 --- /dev/null +++ b/queries/Map domain trusts.yml @@ -0,0 +1,15 @@ +name: Map domain trusts +guid: 268d3d26-5bc2-4820-a6ed-09d20f3d5413 +prebuilt: true +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p = (:Domain)-[:SameForestTrust|CrossForestTrust]->(:Domain) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Members of Allowed RODC Password Replication Group.yml b/queries/Members of Allowed RODC Password Replication Group.yml new file mode 100644 index 0000000..71e7aad --- /dev/null +++ b/queries/Members of Allowed RODC Password Replication Group.yml @@ -0,0 +1,16 @@ +name: Members of Allowed RODC Password Replication Group +guid: 19fc5acd-e30a-4038-a5b5-2e0494f93373 +prebuilt: false +platform: Active Directory +category: Domain Information +description: +query: |- + MATCH p=(n:Base)-[r:MemberOf]->(m:Group) + WHERE m.objectid ENDS WITH "-571" + AND (n:User or n:Computer) + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Nested groups within Tier Zero High Value.yml b/queries/Nested groups within Tier Zero High Value.yml new file mode 100644 index 0000000..155baa4 --- /dev/null +++ b/queries/Nested groups within Tier Zero High Value.yml @@ -0,0 +1,18 @@ +name: Nested groups within Tier Zero / High Value +guid: 8e541e75-df1d-423f-b429-4bbf0403a338 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(t:Group)<-[:MemberOf*..]-(s:Group) + WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') + AND NOT s.objectid ENDS WITH '-512' // Domain Admins + AND NOT s.objectid ENDS WITH '-519' // Enterprise Admins + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Non-Tier Zero account with 'Admin Count' flag.yml b/queries/Non-Tier Zero account with 'Admin Count' flag.yml new file mode 100644 index 0000000..b7fcdf4 --- /dev/null +++ b/queries/Non-Tier Zero account with 'Admin Count' flag.yml @@ -0,0 +1,16 @@ +name: Non-Tier Zero account with 'Admin Count' flag +guid: e7f703b3-5dba-4aef-8346-4d589be2c828 +prebuilt: false +platform: 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) + WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND n.admincount = true + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/windows/win32/adschema/a-admincount +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-Tier Zero account with excessive control.yml b/queries/Non-Tier Zero account with excessive control.yml new file mode 100644 index 0000000..fcc2725 --- /dev/null +++ b/queries/Non-Tier Zero account with excessive control.yml @@ -0,0 +1,20 @@ +name: Non-Tier Zero account with excessive control +guid: 944cecfe-519b-4318-b226-e8520161b454 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH (d:Domain)-[:Contains*1..]->(u:User) + WHERE u.enabled = true + WITH d, COUNT(u) AS enabledUserCount + MATCH (d)-[:Contains*1..]->(n:Base)-[r:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions]->(m:Base) + WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + WITH n, enabledUserCount, COLLECT(DISTINCT(m)) AS endNodes + WHERE SIZE(endNodes) >= 1000 + RETURN n +note: Finds Non-Tier Zero principals with control of >1000 Non-Tier Zero principals +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-Tier Zero account with unconstrained delegation.yml b/queries/Non-Tier Zero account with unconstrained delegation.yml new file mode 100644 index 0000000..b543012 --- /dev/null +++ b/queries/Non-Tier Zero account with unconstrained delegation.yml @@ -0,0 +1,16 @@ +name: Non-Tier Zero account with unconstrained delegation +guid: e7e9a927-3f34-42c7-b921-d8bcf626011e +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH (n:Base) + WHERE n.unconstraineddelegation = true + AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-Tier Zero accounts with SID History of Tier Zero accounts.yml b/queries/Non-Tier Zero accounts with SID History of Tier Zero accounts.yml new file mode 100644 index 0000000..53e8ea9 --- /dev/null +++ b/queries/Non-Tier Zero accounts with SID History of Tier Zero accounts.yml @@ -0,0 +1,16 @@ +name: Non-Tier Zero accounts with SID History of Tier Zero accounts +guid: 59744dfe-9411-4daf-b342-1203dc62acd4 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base) + WHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0') + AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-Tier Zero principals with BadSuccessor rights (no prerequisites check).yml b/queries/Non-Tier Zero principals with BadSuccessor rights (no prerequisites check).yml new file mode 100644 index 0000000..bb9ab79 --- /dev/null +++ b/queries/Non-Tier Zero principals with BadSuccessor rights (no prerequisites check).yml @@ -0,0 +1,18 @@ +name: Non-Tier Zero principals with BadSuccessor rights (no prerequisites check) +guid: 2b9fb71e-73ad-4061-a2df-40c7132b044d +prebuilt: false +platform: 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 + MATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base) + // Exclude Tier Zero + WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p LIMIT 1000 +note: +revision: 1 +resources: https://bsky.app/profile/specterops.io/post/3lpua65qeu22l +acknowledgement: Martin Sohn Christensen, @martinsohndk +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-Tier Zero principals with BadSuccessor rights (with prerequisites check).yml b/queries/Non-Tier Zero principals with BadSuccessor rights (with prerequisites check).yml new file mode 100644 index 0000000..c37df48 --- /dev/null +++ b/queries/Non-Tier Zero principals with BadSuccessor rights (with prerequisites check).yml @@ -0,0 +1,28 @@ +name: Non-Tier Zero principals with BadSuccessor rights (with prerequisites check) +guid: 74daaebe-6040-4f7a-9c9a-416faf73dcc3 +prebuilt: false +platform: 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 + MATCH (dc:Computer) + WHERE dc.isdc = true AND dc.operatingsystem CONTAINS '2025' + // Find gMSAs + MATCH (m:User) + WHERE m.gmsa = true + // Find OU control + MATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base) + // Confirm domain has a 2025 DC + WHERE ou.domain = dc.domain + // Confirm domain KDC key + AND ou.domain = m.domain + // Exclude Tier Zero + AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p LIMIT 1000 +note: +revision: 1 +resources: https://bsky.app/profile/specterops.io/post/3lpua65qeu22l +acknowledgement: Martin Sohn Christensen, @martinsohndk +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-Tier Zero principals with control of AdminSDHolder.yml b/queries/Non-Tier Zero principals with control of AdminSDHolder.yml new file mode 100644 index 0000000..a47b7e5 --- /dev/null +++ b/queries/Non-Tier Zero principals with control of AdminSDHolder.yml @@ -0,0 +1,16 @@ +name: Non-Tier Zero principals with control of AdminSDHolder +guid: 4c1e0137-5b7f-48d8-bd09-9db7674bca61 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +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) + WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND m.name STARTS WITH "ADMINSDHOLDER@" + RETURN p +note: +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 + diff --git a/queries/Non-default delegation on MicrosoftDNS container.yml b/queries/Non-default delegation on MicrosoftDNS container.yml new file mode 100644 index 0000000..f21e4d3 --- /dev/null +++ b/queries/Non-default delegation on MicrosoftDNS container.yml @@ -0,0 +1,18 @@ +name: Non-default delegation on MicrosoftDNS container +guid: 008792c0-4458-46a1-a10d-50cdaf95af1e +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Base)-[r]->(m:Container) + WHERE m.distinguishedname STARTS WITH "CN=MICROSOFTDNS,CN=SYSTEM,DC=" + AND NOT n.name STARTS WITH "DNSADMINS@" + AND NOT n.objectid =~ "-(512|544|519|9)$" + AND r.isacl + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-default members in Pre-Windows 2000 Compatible Access.yml b/queries/Non-default members in Pre-Windows 2000 Compatible Access.yml new file mode 100644 index 0000000..757620c --- /dev/null +++ b/queries/Non-default members in Pre-Windows 2000 Compatible Access.yml @@ -0,0 +1,18 @@ +name: Non-default members in Pre-Windows 2000 Compatible Access +guid: 091995b9-7254-473a-996f-6b8368d20431 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Group)-[:MemberOf]->(m:Group) + WHERE NOT n.objectid ENDS WITH "S-1-5-11" // Authenticated Users + AND NOT (n.objectid ENDS WITH "S-1-5-7" // Anonymous + AND NOT n.objectid ENDS WITH "S-1-1-0") // Everyone + AND m.objectid ENDS WITH "S-1-5-32-554" // Pre-Windows 2000 Compatible Access + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Non-default permissions on IssuancePolicy nodes.yml b/queries/Non-default permissions on IssuancePolicy nodes.yml new file mode 100644 index 0000000..5000a04 --- /dev/null +++ b/queries/Non-default permissions on IssuancePolicy nodes.yml @@ -0,0 +1,16 @@ +name: Non-default permissions on IssuancePolicy nodes +guid: b2280665-c91b-448c-8c0f-97d1f38b6f59 +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (s:Base)-[:GenericAll|GenericWrite|Owns|WriteOwner|WriteDacl]->(:IssuancePolicy) + WHERE NOT s.objectid ENDS WITH '-512' AND NOT s.objectid ENDS WITH '-519' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Object name conflict.yml b/queries/Object name conflict.yml new file mode 100644 index 0000000..12a117f --- /dev/null +++ b/queries/Object name conflict.yml @@ -0,0 +1,15 @@ +name: Object name conflict +guid: c561c4f8-ea45-453f-85a2-3fc2e20e7f8c +prebuilt: false +platform: 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) + WHERE n.distinguishedname CONTAINS 'CNF:' + RETURN n +note: +revision: 1 +resources: https://learn.microsoft.com/en-us/archive/technet-wiki/15435.active-directory-duplicate-object-name-resolution +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/On-Prem Users synced to Entra Users that Own Entra Objects.yml b/queries/On-Prem Users synced to Entra Users that Own Entra Objects.yml new file mode 100644 index 0000000..095e292 --- /dev/null +++ b/queries/On-Prem Users synced to Entra Users that Own Entra Objects.yml @@ -0,0 +1,17 @@ +name: On-Prem Users synced to Entra Users that Own Entra Objects +guid: 4baf1026-e64c-4e31-afeb-2090b8090130 +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwns]->(:AZBase) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/On-Prem Users synced to Entra Users with Azure RM Roles (direct).yml b/queries/On-Prem Users synced to Entra Users with Azure RM Roles (direct).yml new file mode 100644 index 0000000..e254257 --- /dev/null +++ b/queries/On-Prem Users synced to Entra Users with Azure RM Roles (direct).yml @@ -0,0 +1,17 @@ +name: On-Prem Users synced to Entra Users with Azure RM Roles (direct) +guid: 8569113b-e42e-49b0-a968-53bcf0ccd970 +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/On-Prem Users synced to Entra Users with Azure RM Roles (group delegated).yml b/queries/On-Prem Users synced to Entra Users with Azure RM Roles (group delegated).yml new file mode 100644 index 0000000..f400a7b --- /dev/null +++ b/queries/On-Prem Users synced to Entra Users with Azure RM Roles (group delegated).yml @@ -0,0 +1,17 @@ +name: On-Prem Users synced to Entra Users with Azure RM Roles (group delegated) +guid: e4f2eada-8a89-4ba9-89eb-abbee4efbc7a +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (direct).yml b/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (direct).yml new file mode 100644 index 0000000..c26aaf3 --- /dev/null +++ b/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (direct).yml @@ -0,0 +1,17 @@ +name: On-Prem Users synced to Entra Users with Entra Admin Roles (direct) +guid: de717635-d31f-4fbd-930b-b4dac0f22118 +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZHasRole]->(:AZRole) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated).yml b/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated).yml new file mode 100644 index 0000000..ff9310a --- /dev/null +++ b/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated).yml @@ -0,0 +1,17 @@ +name: On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated) +guid: 609d648f-7fb8-42d3-ad99-626f9ce1f121 +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZHasRole]->(:AZRole) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/On-Prem Users synced to Entra Users with Entra Group Membership.yml b/queries/On-Prem Users synced to Entra Users with Entra Group Membership.yml new file mode 100644 index 0000000..2c7255d --- /dev/null +++ b/queries/On-Prem Users synced to Entra Users with Entra Group Membership.yml @@ -0,0 +1,17 @@ +name: On-Prem Users synced to Entra Users with Entra Group Membership +guid: edb575df-2048-4ef0-a0e4-168544a496e9 +prebuilt: true +platform: +- Active Directory +- Azure +category: Cross Platform Attack Paths +description: +query: |- + MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/PKI hierarchy.yml b/queries/PKI hierarchy.yml new file mode 100644 index 0000000..d096694 --- /dev/null +++ b/queries/PKI hierarchy.yml @@ -0,0 +1,15 @@ +name: PKI hierarchy +guid: 928acc23-ee4c-40a5-bde7-64c05cc1491d +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p=()-[:HostsCAService|IssuedSignedBy|EnterpriseCAFor|RootCAFor|TrustedForNTAuth|NTAuthStoreFor*..]->(:Domain) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Paths from Domain Users to Tier Zero High Value targets.yml b/queries/Paths from Domain Users to Tier Zero High Value targets.yml new file mode 100644 index 0000000..3f31944 --- /dev/null +++ b/queries/Paths from Domain Users to Tier Zero High Value targets.yml @@ -0,0 +1,17 @@ +name: Paths from Domain Users to Tier Zero / High Value targets +guid: 977bec40-565c-40b8-90c8-e3e122c291cd +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=shortestPath((s:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Base)) + WHERE s.objectid ENDS WITH '-513' AND s<>t + AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Principal with SPN keyword.yml b/queries/Principal with SPN keyword.yml new file mode 100644 index 0000000..f7fdfbc --- /dev/null +++ b/queries/Principal with SPN keyword.yml @@ -0,0 +1,18 @@ +name: Principal with SPN keyword +guid: 38a9c4c9-3d70-453f-a017-cbfd35ed9917 +prebuilt: false +platform: Active Directory +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) + WITH "KEYWORD" as SPNKeyword + MATCH (n:User) + WHERE ANY(keyword IN n.serviceprincipalnames WHERE toUpper(keyword) CONTAINS toUpper(SPNKeyword)) + RETURN n +note: +revision: 1 +resources: https://adsecurity.org/?page_id=183 +acknowledgement: Ryan, @haus3c +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Principals with DCSync privileges.yml b/queries/Principals with DCSync privileges.yml new file mode 100644 index 0000000..3fbf826 --- /dev/null +++ b/queries/Principals with DCSync privileges.yml @@ -0,0 +1,15 @@ +name: Principals with DCSync privileges +guid: 6e9beb8a-ad14-43de-bda1-644d174a5906 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(:Base)-[:DCSync|AllExtendedRights|GenericAll]->(:Domain) + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Principals with DES-only Kerberos authentication.yml b/queries/Principals with DES-only Kerberos authentication.yml new file mode 100644 index 0000000..31da9ed --- /dev/null +++ b/queries/Principals with DES-only Kerberos authentication.yml @@ -0,0 +1,16 @@ +name: Principals with DES-only Kerberos authentication +guid: d03ea1ef-70f0-439b-b1ef-d7f94ceb2af3 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Base) + WHERE n.enabled = true + AND n.usedeskeyonly = true + RETURN n +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Principals with foreign domain group membership.yml b/queries/Principals with foreign domain group membership.yml new file mode 100644 index 0000000..776f3f6 --- /dev/null +++ b/queries/Principals with foreign domain group membership.yml @@ -0,0 +1,16 @@ +name: Principals with foreign domain group membership +guid: 8fb3214a-5a75-4ecd-b293-c121abd94b4b +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(s:Base)-[:MemberOf]->(t:Group) + WHERE s.domainsid<>t.domainsid + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Principals with passwords stored using reversible encryption.yml b/queries/Principals with passwords stored using reversible encryption.yml new file mode 100644 index 0000000..51a679e --- /dev/null +++ b/queries/Principals with passwords stored using reversible encryption.yml @@ -0,0 +1,15 @@ +name: Principals with passwords stored using reversible encryption +guid: ab900835-b2b8-4674-87b4-8b5141e80439 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Base) + WHERE n.encryptedtextpwdallowed = true + RETURN n +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Principals with weak supported Kerberos encryption types.yml b/queries/Principals with weak supported Kerberos encryption types.yml new file mode 100644 index 0000000..2d42f6f --- /dev/null +++ b/queries/Principals with weak supported Kerberos encryption types.yml @@ -0,0 +1,17 @@ +name: Principals with weak supported Kerberos encryption types +guid: ca329573-2157-41da-ab17-4d122c54b11d +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (u:Base) + WHERE 'DES-CBC-CRC' IN u.supportedencryptiontypes + OR 'DES-CBC-MD5' IN u.supportedencryptiontypes + OR 'RC4-HMAC-MD5' IN u.supportedencryptiontypes + RETURN u +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Public Key Services container.yml b/queries/Public Key Services container.yml new file mode 100644 index 0000000..e6217af --- /dev/null +++ b/queries/Public Key Services container.yml @@ -0,0 +1,16 @@ +name: Public Key Services container +guid: 07e94492-71aa-4665-ab8c-e7aec25906cd +prebuilt: true +platform: Active Directory +category: Active Directory Certificate Services +description: +query: |- + MATCH p = (c:Container)-[:Contains*..]->(:Base) + WHERE c.distinguishedname starts with 'CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC=' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Servers where Domain Users can RDP.yml b/queries/Servers where Domain Users can RDP.yml new file mode 100644 index 0000000..9613e54 --- /dev/null +++ b/queries/Servers where Domain Users can RDP.yml @@ -0,0 +1,16 @@ +name: Servers where Domain Users can RDP +guid: b9a330ae-1d89-44d4-8f74-9ca18e93eb92 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(s:Group)-[:CanRDP]->(t:Computer) + WHERE s.objectid ENDS WITH '-513' AND toUpper(t.operatingsystem) CONTAINS 'SERVER' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/Queries/Active Directory/Trusts/Sessions across trusts.yml b/queries/Sessions across trusts.yml similarity index 81% rename from Queries/Active Directory/Trusts/Sessions across trusts.yml rename to queries/Sessions across trusts.yml index c8366c9..76e010b 100644 --- a/Queries/Active Directory/Trusts/Sessions across trusts.yml +++ b/queries/Sessions across trusts.yml @@ -1,7 +1,8 @@ name: Sessions across trusts guid: aea7ac64-1f51-407b-b0ee-19fd30075794 +prebuilt: false platform: Active Directory -category: Trusts +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) @@ -12,4 +13,5 @@ note: revision: 1 resources: acknowledgement: +acknowledgements: Martin Sohn Christensen, @martinsohndk 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 new file mode 100644 index 0000000..551ebae --- /dev/null +++ b/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml @@ -0,0 +1,16 @@ +name: Shortest paths from Azure Applications to Tier Zero / High Value targets +guid: 60ff7c58-a98e-4bc1-9e32-8378d2db0c43 +prebuilt: true +platform: Azure +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:AZApp)-[:AZAvereContributor|AZContributor|AZGetCertificates|AZGetKeys|AZGetSecrets|AZHasRole|AZMemberOf|AZOwner|AZRunsAs|AZVMContributor|AZAutomationContributor|AZKeyVaultContributor|AZVMAdminLogin|AZAddMembers|AZAddSecret|AZExecuteCommand|AZGlobalAdmin|AZPrivilegedAuthAdmin|AZGrant|AZGrantSelf|AZPrivilegedRoleAdmin|AZResetPassword|AZUserAccessAdministrator|AZOwns|AZCloudAppAdmin|AZAppAdmin|AZAddOwner|AZManagedIdentity|AZAKSContributor|AZNodeResourceGroup|AZWebsiteContributor|AZLogicAppContributor|AZMGAddMember|AZMGAddOwner|AZMGAddSecret|AZMGGrantAppRoles|AZMGGrantRole|SyncedToADUser|AZRoleEligible|AZContains*1..]->(t:AZBase)) + WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths from Domain Users to Tier Zero High Value targets.yml b/queries/Shortest paths from Domain Users to Tier Zero High Value targets.yml new file mode 100644 index 0000000..6911caf --- /dev/null +++ b/queries/Shortest paths from Domain Users to Tier Zero High Value targets.yml @@ -0,0 +1,17 @@ +name: Shortest paths from Domain Users to Tier Zero / High Value targets +guid: 469dc0f3-71b8-41b0-a03b-b4af7874665d +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:Group)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Base)) + WHERE s.objectid ENDS WITH '-513' AND s<>t + AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p + LIMIT 1000 +note: +revision: 1 +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 new file mode 100644 index 0000000..abe9454 --- /dev/null +++ b/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml @@ -0,0 +1,17 @@ +name: Shortest paths from Entra Users to Tier Zero / High Value targets +guid: 58089b28-54e0-4fd2-bf66-3db480b00e2f +prebuilt: true +platform: Azure +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:AZUser)-[:AZAvereContributor|AZContributor|AZGetCertificates|AZGetKeys|AZGetSecrets|AZHasRole|AZMemberOf|AZOwner|AZRunsAs|AZVMContributor|AZAutomationContributor|AZKeyVaultContributor|AZVMAdminLogin|AZAddMembers|AZAddSecret|AZExecuteCommand|AZGlobalAdmin|AZPrivilegedAuthAdmin|AZGrant|AZGrantSelf|AZPrivilegedRoleAdmin|AZResetPassword|AZUserAccessAdministrator|AZOwns|AZCloudAppAdmin|AZAppAdmin|AZAddOwner|AZManagedIdentity|AZAKSContributor|AZNodeResourceGroup|AZWebsiteContributor|AZLogicAppContributor|AZMGAddMember|AZMGAddOwner|AZMGAddSecret|AZMGGrantAppRoles|AZMGGrantRole|SyncedToADUser|AZRoleEligible|AZContains*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 +note: +revision: 1 +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 new file mode 100644 index 0000000..9b4d700 --- /dev/null +++ b/queries/Shortest paths from Owned objects to Tier Zero.yml @@ -0,0 +1,18 @@ +name: Shortest paths from Owned objects to Tier Zero +guid: dfaa8e8f-2c79-4e92-a291-b1347f6e83b0 +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + // MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE + MATCH p=shortestPath((s:Tag_Owned)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Base)) + WHERE s<>t + AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths from Owned objects.yml b/queries/Shortest paths from Owned objects.yml new file mode 100644 index 0000000..d1057ba --- /dev/null +++ b/queries/Shortest paths from Owned objects.yml @@ -0,0 +1,17 @@ +name: Shortest paths from Owned objects +guid: e370a01d-c129-4f19-b88d-9479cbe00028 +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:Base)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Base)) + WHERE (s:Tag_Owned) + AND s<>t + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths to Azure Subscriptions.yml b/queries/Shortest paths to Azure Subscriptions.yml new file mode 100644 index 0000000..4f770e4 --- /dev/null +++ b/queries/Shortest paths to Azure Subscriptions.yml @@ -0,0 +1,16 @@ +name: Shortest paths to Azure Subscriptions +guid: 4785b305-c101-461c-80fc-3fb3ff67a8ce +prebuilt: true +platform: Azure +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:AZBase)-[:AZAvereContributor|AZContributor|AZGetCertificates|AZGetKeys|AZGetSecrets|AZHasRole|AZMemberOf|AZOwner|AZRunsAs|AZVMContributor|AZAutomationContributor|AZKeyVaultContributor|AZVMAdminLogin|AZAddMembers|AZAddSecret|AZExecuteCommand|AZGlobalAdmin|AZPrivilegedAuthAdmin|AZGrant|AZGrantSelf|AZPrivilegedRoleAdmin|AZResetPassword|AZUserAccessAdministrator|AZOwns|AZCloudAppAdmin|AZAppAdmin|AZAddOwner|AZManagedIdentity|AZAKSContributor|AZNodeResourceGroup|AZWebsiteContributor|AZLogicAppContributor|AZMGAddMember|AZMGAddOwner|AZMGAddSecret|AZMGGrantAppRoles|AZMGGrantRole|SyncedToADUser|AZRoleEligible|AZContains*1..]->(t:AZSubscription)) + WHERE s<>t + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths to Domain Admins from Kerberoastable users.yml b/queries/Shortest paths to Domain Admins from Kerberoastable users.yml new file mode 100644 index 0000000..a506e65 --- /dev/null +++ b/queries/Shortest paths to Domain Admins from Kerberoastable users.yml @@ -0,0 +1,21 @@ +name: Shortest paths to Domain Admins from Kerberoastable users +guid: bd163361-1e05-47c7-908b-962aef251535 +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:User)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Group)) + WHERE s.hasspn=true + AND s.enabled = true + AND NOT s.objectid ENDS WITH '-502' + AND NOT COALESCE(s.gmsa, false) = true + AND NOT COALESCE(s.msa, false) = true + AND t.objectid ENDS WITH '-512' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths to Domain Admins.yml b/queries/Shortest paths to Domain Admins.yml new file mode 100644 index 0000000..cd9786f --- /dev/null +++ b/queries/Shortest paths to Domain Admins.yml @@ -0,0 +1,16 @@ +name: Shortest paths to Domain Admins +guid: f40cb34b-5ec7-44bc-9aa8-a200a4a41f22 +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((t:Group)<-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]-(s:Base)) + WHERE t.objectid ENDS WITH '-512' AND s<>t + RETURN p + LIMIT 1000 +note: +revision: 1 +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 new file mode 100644 index 0000000..008462b --- /dev/null +++ b/queries/Shortest paths to Tier Zero High Value targets.yml @@ -0,0 +1,16 @@ +name: Shortest paths to Tier Zero / High Value targets +guid: 237aac58-8641-4703-a9f7-001d69546fd8 +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Tag_Tier_Zero)) + WHERE s<>t + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths to privileged roles.yml b/queries/Shortest paths to privileged roles.yml new file mode 100644 index 0000000..d402819 --- /dev/null +++ b/queries/Shortest paths to privileged roles.yml @@ -0,0 +1,16 @@ +name: Shortest paths to privileged roles +guid: 3dc73dd8-4873-4aeb-a88f-56a58c77f512 +prebuilt: true +platform: Azure +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s:AZBase)-[:AZAvereContributor|AZContributor|AZGetCertificates|AZGetKeys|AZGetSecrets|AZHasRole|AZMemberOf|AZOwner|AZRunsAs|AZVMContributor|AZAutomationContributor|AZKeyVaultContributor|AZVMAdminLogin|AZAddMembers|AZAddSecret|AZExecuteCommand|AZGlobalAdmin|AZPrivilegedAuthAdmin|AZGrant|AZGrantSelf|AZPrivilegedRoleAdmin|AZResetPassword|AZUserAccessAdministrator|AZOwns|AZCloudAppAdmin|AZAppAdmin|AZAddOwner|AZManagedIdentity|AZAKSContributor|AZNodeResourceGroup|AZWebsiteContributor|AZLogicAppContributor|AZMGAddMember|AZMGAddOwner|AZMGAddSecret|AZMGGrantAppRoles|AZMGGrantRole|SyncedToADUser|AZRoleEligible|AZContains*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 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Shortest paths to systems trusted for unconstrained delegation.yml b/queries/Shortest paths to systems trusted for unconstrained delegation.yml new file mode 100644 index 0000000..6b0c80e --- /dev/null +++ b/queries/Shortest paths to systems trusted for unconstrained delegation.yml @@ -0,0 +1,16 @@ +name: Shortest paths to systems trusted for unconstrained delegation +guid: 16a9e47b-45f8-4514-b409-771bb5186142 +prebuilt: true +platform: Active Directory +category: Shortest Paths +description: +query: |- + MATCH p=shortestPath((s)-[:Owns|GenericAll|GenericWrite|WriteOwner|WriteDacl|MemberOf|ForceChangePassword|AllExtendedRights|AddMember|HasSession|GPLink|AllowedToDelegate|CoerceToTGT|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|HasSIDHistory|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|SQLAdmin|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|GoldenCert|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|SyncedToEntraUser|CoerceAndRelayNTLMToSMB|CoerceAndRelayNTLMToADCS|WriteOwnerLimitedRights|OwnsLimitedRights|CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|Contains|DCFor|SameForestTrust|SpoofSIDHistory|AbuseTGTDelegation*1..]->(t:Computer)) + WHERE t.unconstraineddelegation = true AND s<>t + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Smart card accounts with passwords not rotated in over 1 year.yml b/queries/Smart card accounts with passwords not rotated in over 1 year.yml new file mode 100644 index 0000000..4ee2ad1 --- /dev/null +++ b/queries/Smart card accounts with passwords not rotated in over 1 year.yml @@ -0,0 +1,17 @@ +name: Smart card accounts with passwords not rotated in over 1 year +guid: 7e56f2e7-79c3-4f0d-aa3e-14cf3de7ab73 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Base) + WHERE n.pwdlastset < (datetime().epochseconds - (365 * 86400)) + AND n.enabled = true + AND n.smartcardrequired = true + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero AD principals synchronized with Entra ID.yml b/queries/Tier Zero AD principals synchronized with Entra ID.yml new file mode 100644 index 0000000..89c7ec6 --- /dev/null +++ b/queries/Tier Zero AD principals synchronized with Entra ID.yml @@ -0,0 +1,20 @@ +name: Tier Zero AD principals synchronized with Entra ID +guid: a8b6ec67-21aa-4dd2-8906-47bb81bf5262 +prebuilt: true +platform: Azure +category: Azure Hygiene +description: +query: |- + MATCH (ENTRA:AZBase) + MATCH (AD:Base) + WHERE ((AD:Tag_Tier_Zero) OR COALESCE(AD.system_tags, '') CONTAINS 'admin_tier_0') + AND ENTRA.onpremsyncenabled = true + AND ENTRA.onpremid = AD.objectid + RETURN ENTRA + // Replace 'RETURN ENTRA' with 'RETURN AD' to see the corresponding AD principals + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Tier Zero High Value enabled users not requiring smart card authentication.yml b/queries/Tier Zero High Value enabled users not requiring smart card authentication.yml new file mode 100644 index 0000000..fd907e6 --- /dev/null +++ b/queries/Tier Zero High Value enabled users not requiring smart card authentication.yml @@ -0,0 +1,20 @@ +name: Tier Zero / High Value enabled users not requiring smart card authentication +guid: 867f9f17-c149-4c4b-ad84-9a807622ff8c +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (u:User) + WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') + AND u.enabled = true + AND u.smartcardrequired = false + AND NOT u.name STARTS WITH 'MSOL_' // Removes false positive, Entra sync + AND NOT u.name STARTS WITH 'PROVAGENTGMSA' // Removes false positive, Entra sync + AND NOT u.name STARTS WITH 'ADSYNCMSA_' // Removes false positive, Entra sync + RETURN u +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Tier Zero High Value external Entra ID users.yml b/queries/Tier Zero High Value external Entra ID users.yml new file mode 100644 index 0000000..200134b --- /dev/null +++ b/queries/Tier Zero High Value external Entra ID users.yml @@ -0,0 +1,17 @@ +name: Tier Zero / High Value external Entra ID users +guid: 20e07417-d286-4dca-a962-568f2b262f65 +prebuilt: true +platform: Azure +category: Azure Hygiene +description: +query: |- + MATCH (n:AZUser) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND n.name CONTAINS '#EXT#@' + RETURN n + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Tier Zero High Value users with non-expiring passwords.yml b/queries/Tier Zero High Value users with non-expiring passwords.yml new file mode 100644 index 0000000..b03a263 --- /dev/null +++ b/queries/Tier Zero High Value users with non-expiring passwords.yml @@ -0,0 +1,17 @@ +name: Tier Zero / High Value users with non-expiring passwords +guid: 4eca1b69-00a2-48a0-abb3-b94ea647cf6b +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (u:User) + WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.enabled = true + AND u.pwdneverexpires = true + RETURN u + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + 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 new file mode 100644 index 0000000..6264980 --- /dev/null +++ b/queries/Tier Zero accounts not members of Denied RODC Password Replication Group.yml @@ -0,0 +1,21 @@ +name: Tier Zero accounts not members of Denied RODC Password Replication Group +guid: e9613406-e346-410b-a033-690a6cf0c708 +prebuilt: false +platform: 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: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 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero accounts that can be delegated.yml b/queries/Tier Zero accounts that can be delegated.yml new file mode 100644 index 0000000..08bb0a7 --- /dev/null +++ b/queries/Tier Zero accounts that can be delegated.yml @@ -0,0 +1,21 @@ +name: Tier Zero accounts that can be delegated +guid: 4316eaf1-6af0-4879-8f55-ac2633a711c3 +prebuilt: false +platform: Active Directory +category: Kerberos Interaction +description: +query: |- + MATCH (m:Base) + WHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0') + AND m.enabled = true + AND m.sensitive = false + OPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base) + WHERE g.objectid ENDS WITH '-525' + WITH m, COLLECT(n) AS matchingNs + WHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid) + RETURN m +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers at risk of constrained delegation.yml b/queries/Tier Zero computers at risk of constrained delegation.yml new file mode 100644 index 0000000..8b52703 --- /dev/null +++ b/queries/Tier Zero computers at risk of constrained delegation.yml @@ -0,0 +1,15 @@ +name: Tier Zero computers at risk of constrained delegation +guid: 8641e593-f2f2-48ba-bd45-fbc86e9f632a +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p = (n:Computer)<-[:AllowedToDelegate]-(:Base) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers at risk of resource-based constrained delegation.yml b/queries/Tier Zero computers at risk of resource-based constrained delegation.yml new file mode 100644 index 0000000..313944e --- /dev/null +++ b/queries/Tier Zero computers at risk of resource-based constrained delegation.yml @@ -0,0 +1,15 @@ +name: Tier Zero computers at risk of resource-based constrained delegation +guid: 4dc97cf4-3c03-4fe6-8a8b-4f665c67e1e5 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p = (n:Computer)<-[:AllowedToAct]-(:Base) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers not owned by Tier Zero.yml b/queries/Tier Zero computers not owned by Tier Zero.yml new file mode 100644 index 0000000..a81257f --- /dev/null +++ b/queries/Tier Zero computers not owned by Tier Zero.yml @@ -0,0 +1,15 @@ +name: Tier Zero computers not owned by Tier Zero +guid: 99d29ded-223a-442b-a0e0-f8b5694c6441 +prebuilt: false +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(n:Base)-[:Owns]->(:Computer) + WHERE NOT coalesce(n.system_tags, "") CONTAINS "admin_tier_0" + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers not requiring inbound SMB signing.yml b/queries/Tier Zero computers not requiring inbound SMB signing.yml new file mode 100644 index 0000000..7ed91b5 --- /dev/null +++ b/queries/Tier Zero computers not requiring inbound SMB signing.yml @@ -0,0 +1,16 @@ +name: Tier Zero omputers not requiring inbound SMB signing +guid: 13485477-f026-4b1f-906d-4f2e37364ba4 +prebuilt: false +platform: Active Directory +category: NTLM Relay Attacks +description: +query: |- + MATCH (n:Computer) + WHERE n.smbsigning = False + AND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers with passwords older than the default maximum password age.yml b/queries/Tier Zero computers with passwords older than the default maximum password age.yml new file mode 100644 index 0000000..ad2febb --- /dev/null +++ b/queries/Tier Zero computers with passwords older than the default maximum password age.yml @@ -0,0 +1,18 @@ +name: Tier Zero computers with passwords older than the default maximum password age +guid: b6d6d0bf-130e-4719-996b-adc29bba36e9 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:Computer) + WHERE n.enabled = true + AND n.whencreated < (datetime().epochseconds - (60 * 3 * 86400)) + AND n.pwdlastset < (datetime().epochseconds - (60 * 3 * 86400)) + AND coalesce(n.system_tags, "") CONTAINS "admin_tier_0" + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers with the WebClient running.yml b/queries/Tier Zero computers with the WebClient running.yml new file mode 100644 index 0000000..ba0ec58 --- /dev/null +++ b/queries/Tier Zero computers with the WebClient running.yml @@ -0,0 +1,16 @@ +name: Tier Zero computers with the WebClient running +guid: 27a6f917-8ed4-4e2e-9b38-41a4b6de1b14 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (c:Computer) + WHERE c.webclientrunning = True + AND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0') + RETURN c LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero computers with unsupported operating systems.yml b/queries/Tier Zero computers with unsupported operating systems.yml new file mode 100644 index 0000000..db861e1 --- /dev/null +++ b/queries/Tier Zero computers with unsupported operating systems.yml @@ -0,0 +1,17 @@ +name: Tier Zero computers with unsupported operating systems +guid: a87b558c-5746-4a90-9f83-c86e7b924a52 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (c:Computer) + WHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*' + AND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0') + RETURN c + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero users not member of Protected Users.yml b/queries/Tier Zero users not member of Protected Users.yml new file mode 100644 index 0000000..ccddd5d --- /dev/null +++ b/queries/Tier Zero users not member of Protected Users.yml @@ -0,0 +1,19 @@ +name: Tier Zero users not member of Protected Users +guid: 543eb01d-9fa3-4b8f-a936-b46bbfdaa2ae +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (m:User) + WHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0') + OPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base) + WHERE g.objectid ENDS WITH '-525' + WITH m, COLLECT(n) AS matchingNs + WHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid) + RETURN m +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero users with email.yml b/queries/Tier Zero users with email.yml new file mode 100644 index 0000000..c6c207b --- /dev/null +++ b/queries/Tier Zero users with email.yml @@ -0,0 +1,30 @@ +name: Tier Zero users with email +guid: 9654c0d4-f1e8-4393-a2d1-53a5554a9de8 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: Tier Zero accounts with email access have an increased attack surface. +query: |- + MATCH (n) + WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0') + AND n.email <> "" + AND n.enabled = true + AND NOT toUpper(n.email) ENDS WITH ".ONMICROSOFT.COM" + AND NOT ( + (toUpper(n.email) STARTS WITH "HEALTHMAILBOX" + OR toUpper(n.email) STARTS WITH "MSEXCHDISCOVERYMAILBOX" + OR toUpper(n.email) STARTS WITH "MSEXCHDISCOVERY" + OR toUpper(n.email) STARTS WITH "MSEXCHAPPROVAL" + OR toUpper(n.email) STARTS WITH "FEDERATEDEMAIL" + OR toUpper(n.email) STARTS WITH "SYSTEMMAILBOX" + OR toUpper(n.email) STARTS WITH "MIGRATION.") + AND + (n.name STARTS WITH "SM_" + OR n.name STARTS WITH "HEALTHMAILBOX") + ) + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Tier Zero users with passwords not rotated in over 1 year.yml b/queries/Tier Zero users with passwords not rotated in over 1 year.yml new file mode 100644 index 0000000..c3b898b --- /dev/null +++ b/queries/Tier Zero users with passwords not rotated in over 1 year.yml @@ -0,0 +1,19 @@ +name: Tier Zero users with passwords not rotated in over 1 year +guid: 5e0d69b1-37d1-43ae-ac5d-f297f312fab5 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + WITH 365 as days_since_change + MATCH (u:User) + WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') + AND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400)) + AND NOT u.pwdlastset IN [-1.0, 0.0] + RETURN u + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Trace ACE inheritance.yml b/queries/Trace ACE inheritance.yml new file mode 100644 index 0000000..ec6909f --- /dev/null +++ b/queries/Trace ACE inheritance.yml @@ -0,0 +1,19 @@ +name: Trace ACE inheritance +guid: 8c5454df-3ae8-412c-b271-3c4c55df7141 +prebuilt: false +platform: 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 +note: +revision: 1 +resources: +acknowledgement: Walter.Legowski, @SadProcessor +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Unresolved SID with outbound control.yml b/queries/Unresolved SID with outbound control.yml new file mode 100644 index 0000000..a20402d --- /dev/null +++ b/queries/Unresolved SID with outbound control.yml @@ -0,0 +1,17 @@ +name: Unresolved SID with outbound control +guid: 4e8429f9-cba2-41e9-bac6-0c42f96b2c57 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:Base)-[r]->(:Base) + WHERE r.isacl + AND n.name CONTAINS "S-1-5-21-" // Unresolved SID + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Usage of built-in domain Administrator account.yml b/queries/Usage of built-in domain Administrator account.yml new file mode 100644 index 0000000..e3b4272 --- /dev/null +++ b/queries/Usage of built-in domain Administrator account.yml @@ -0,0 +1,20 @@ +name: Usage of built-in domain Administrator account +guid: 35b1206f-871b-44aa-a601-c5258060dfcf +prebuilt: false +platform: 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) + WHERE n.objectid ENDS WITH "-500" + AND ( + n.lastlogontimestamp > (datetime().epochseconds - (60 * 86400)) OR + n.lastlogon > (datetime().epochseconds - (60 * 86400)) + ) + AND NOT n.whencreated > (datetime().epochseconds - (60 * 86400)) + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Users which do not require password to authenticate.yml b/queries/Users which do not require password to authenticate.yml new file mode 100644 index 0000000..d54acb2 --- /dev/null +++ b/queries/Users which do not require password to authenticate.yml @@ -0,0 +1,16 @@ +name: Users which do not require password to authenticate +guid: 23bdc2ad-6739-4b2b-85d3-258e3f424eb2 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (u:User) + WHERE u.passwordnotreqd = true + RETURN u + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Users with logon scripts stored in a trusted domain.yml b/queries/Users with logon scripts stored in a trusted domain.yml new file mode 100644 index 0000000..2fc4a45 --- /dev/null +++ b/queries/Users with logon scripts stored in a trusted domain.yml @@ -0,0 +1,18 @@ +name: Users with logon scripts stored in a trusted domain +guid: 8d94d3f3-3d53-4939-a206-3c0a4dd3f646 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (n:User) + WHERE n.logonscript IS NOT NULL + MATCH (d:Domain)-[:TrustedBy]->(:Domain)-[:Contains*1..]->(n) + WITH n,last(split(d.name, '@')) AS domain + WHERE toUpper(n.logonscript) STARTS WITH ("\\\\" + domain + "\\") + RETURN n +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Users with non-default Primary Group membership.yml b/queries/Users with non-default Primary Group membership.yml new file mode 100644 index 0000000..57df438 --- /dev/null +++ b/queries/Users with non-default Primary Group membership.yml @@ -0,0 +1,19 @@ +name: Users with non-default Primary Group membership +guid: 93890f88-df2c-4167-a945-a53961d08d00 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH p=(n:User)-[r:MemberOf]->(g:Group) + WHERE NOT g.objectid ENDS WITH "-513" // Domain Users + AND r.isprimarygroup = true + AND NOT n.objectid ENDS WITH "-501" // Guests account, as it has primaryGroup to Guests + AND (n.gmsa IS NULL OR n.gmsa = false) // Not gMSA, as it has primaryGroup to Domain Computers + AND (n.msa IS NULL OR n.msa = false) // Not MSA, as it has primaryGroup to Domain Computers + RETURN p +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Users with non-expiring passwords.yml b/queries/Users with non-expiring passwords.yml new file mode 100644 index 0000000..697cf8c --- /dev/null +++ b/queries/Users with non-expiring passwords.yml @@ -0,0 +1,17 @@ +name: Users with non-expiring passwords +guid: 212c2a98-53d9-4dfa-b177-42c601452dd1 +prebuilt: false +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + MATCH (u:User) + WHERE u.enabled = true + AND u.pwdneverexpires = true + RETURN u + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: Martin Sohn Christensen, @martinsohndk + diff --git a/queries/Users with passwords not rotated in over 1 year.yml b/queries/Users with passwords not rotated in over 1 year.yml new file mode 100644 index 0000000..c9b8c23 --- /dev/null +++ b/queries/Users with passwords not rotated in over 1 year.yml @@ -0,0 +1,18 @@ +name: Users with passwords not rotated in over 1 year +guid: be70d1bd-b7eb-40b0-971c-eefc50eca032 +prebuilt: true +platform: Active Directory +category: Active Directory Hygiene +description: +query: |- + WITH 365 as days_since_change + MATCH (u:User) + WHERE u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400)) + AND NOT u.pwdlastset IN [-1.0, 0.0] + RETURN u + LIMIT 100 +note: +revision: 1 +resources: +acknowledgements: + diff --git a/queries/Workstations where Domain Users can RDP.yml b/queries/Workstations where Domain Users can RDP.yml new file mode 100644 index 0000000..53f51b2 --- /dev/null +++ b/queries/Workstations where Domain Users can RDP.yml @@ -0,0 +1,16 @@ +name: Workstations where Domain Users can RDP +guid: 9486e0e6-2617-4595-b969-cf57ca21fc86 +prebuilt: true +platform: Active Directory +category: Dangerous Privileges +description: +query: |- + MATCH p=(s:Group)-[:CanRDP]->(t:Computer) + WHERE s.objectid ENDS WITH '-513' AND NOT toUpper(t.operatingsystem) CONTAINS 'SERVER' + RETURN p + LIMIT 1000 +note: +revision: 1 +resources: +acknowledgements: +