├── tests
├── grammar
│ ├── __init__.py
│ └── cypher
│ │ ├── Cypher.tokens
│ │ └── CypherLexer.tokens
├── schema.py
├── templates
│ └── githubsummary.md.j2
├── conftest.py
└── test_cypher_syntax.py
├── queries.specterops.io.png
├── .github
├── CODEOWNERS
├── ISSUE_TEMPLATE
│ └── query-issue-report.yml
└── workflows
│ └── syntax.yml
├── requirements.txt
├── queries
├── Map OU structure.yml
├── Map domain trusts.yml
├── ESC8-vulnerable Enterprise CAs.yml
├── Entra Users with Entra Admin Role approval (direct).yml
├── Entra Users with Entra Admin Role direct eligibility.yml
├── Accounts with SID History.yml
├── Domain migration groups.yml
├── Computers not requiring inbound SMB signing.yml
├── Computers with the WebClient running.yml
├── All Global Administrators.yml
├── AdminSDHolder to protected objects relationship.yml
├── All DNSAdmins.yml
├── Principals with DCSync privileges.yml
├── All Domain Admins.yml
├── CA administrators and CA managers.yml
├── CA Administrators and CA Managers (ESC7).yml
├── Entra Users with Entra Admin Role approval (group delegated).yml
├── Entra Users with Entra Admin Roles group delegated eligibility.yml
├── PKI hierarchy.yml
├── Principals with DES-only Kerberos authentication.yml
├── Users which do not require password to authenticate.yml
├── All Azure VMs with a tied Managed Identity.yml
├── Computers with membership in Protected Users.yml
├── Computers with the outgoing NTLM setting set to Deny all.yml
├── Location of AdminSDHolder Protected objects.yml
├── Principals with passwords stored using reversible encryption.yml
├── Principals with foreign domain group membership.yml
├── Shortest paths to Domain Admins.yml
├── Enabled built-in guest user accounts.yml
├── All Schema Admins.yml
├── Computers where Domain Users are local administrators.yml
├── Users with non-expiring passwords.yml
├── Dangerous privileges for Domain Users groups.yml
├── Disabled Tier Zero High Value principals - AZ.yml
├── Locations of Owned objects - AZ.yml
├── Servers where Domain Users can RDP.yml
├── AS-REP Roastable users (DontReqPreAuth).yml
├── Accounts with SID History to a same-domain account.yml
├── Computers with unsupported operating systems.yml
├── Members of Allowed RODC Password Replication Group.yml
├── Synced Entra Users with Entra Admin Role approval (direct).yml
├── Synced Entra Users with Entra Admin Role direct eligibility.yml
├── All service principals with Microsoft Graph privilege to grant arbitrary App Roles.yml
├── Tier Zero High Value external Entra ID users.yml
├── Computers where Domain Users can read LAPS passwords.yml
├── Locations of Owned objects - AD.yml
├── Locations of Tier Zero High Value objects.yml
├── On-Prem Users synced to Entra Users that Own Entra Objects.yml
├── Owners of Azure Applications.yml
├── Shortest paths from Owned objects.yml
├── Workstations where Domain Users can RDP.yml
├── Cross-forest trusts with abusable configuration.yml
├── Enrollment rights on published certificate templates.yml
├── Public Key Services container.yml
├── Unresolved SID with outbound control.yml
├── On-Prem Users synced to Entra Users with Entra Group Membership.yml
├── Shortest Paths from Azure Users to Azure VMs.yml
├── On-Prem Users synced to Entra Users with Entra Admin Roles (direct).yml
├── Shortest paths to systems trusted for unconstrained delegation.yml
├── Tier Zero computers not owned by Tier Zero.yml
├── Domains with functional level not the latest version.yml
├── Tier Zero principals without AdminSDHolder protection.yml
├── Map Azure Management structure.yml
├── Synced Entra Users with Entra Admin Role approval (group delegated).yml
├── Shortest Paths from Azure Users to Azure Keyvaults.yml
├── Shortest paths to Azure Subscriptions.yml
├── Shortest paths to Tier Zero High Value targets.yml
├── Synced Entra Users with Entra Admin Roles group delegated eligibility.yml
├── Enrollment rights on CertTemplates with OIDGroupLink.yml
├── Domain Controllers allowing NTLMv1 or LM authentication.yml
├── Tier Zero computers not requiring inbound SMB signing.yml
├── Entra Users synced from On-Prem Users added to Domain Admins group.yml
├── Tier Zero computers at risk of constrained delegation.yml
├── Tier Zero computers with the WebClient running.yml
├── Domains with a minimum default password policy length less than 15 characters.yml
├── Non-Tier Zero account with unconstrained delegation.yml
├── Tier Zero High Value users with non-expiring passwords.yml
├── Users with passwords not rotated in over 1 year.yml
├── Accounts with SID History to a non-existent domain.yml
├── Accounts with clear-text password attributes.yml
├── All direct Controllers of MS Graph.yml
├── Domain controllers with weak certificate binding enabled.yml
├── Domains with a single-point-of-failure Domain Controller.yml
├── Domains without Microsoft LAPS computers.yml
├── On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated).yml
├── Principals with weak supported Kerberos encryption types.yml
├── All coerce and NTLM relay edges.yml
├── Non-default permissions on IssuancePolicy nodes.yml
├── Owners of Azure Subscriptions.yml
├── Domains without Protected Users group.yml
├── Shortest Paths from Owned Azure Users to Azure VMs.yml
├── All Kerberoastable users.yml
├── Tier Zero computers at risk of resource-based constrained delegation.yml
├── Smart card accounts with passwords not rotated in over 1 year.yml
├── AS-REP Roastable Tier Zero users (DontReqPreAuth).yml
├── Domains with List Object mode enabled.yml
├── Domains with more than 50 Tier Zero accounts.yml
├── Domains with smart card accounts where smart account passwords do not expire.yml
├── Domains allowing authenticated domain enumeration.yml
├── Paths from Domain Users to Tier Zero High Value targets.yml
├── Shortest Paths from Owned Azure Users to Azure Keyvaults.yml
├── Foreign principals in Tier Zero High Value targets.yml
├── Accounts with smart card required in domains where smart account passwords do not expire.yml
├── Domains affected by AdPrep privilege escalation risk.yml
├── Enrollment rights on published certificate templates with no security extension.yml
├── Sessions across trusts.yml
├── Shortest paths from Domain Users to Tier Zero High Value targets.yml
├── Domains affected by Exchange privilege escalation risk.yml
├── Domains allowing unauthenticated NSPI RPC binds.yml
├── Computers without Windows LAPS.yml
├── Domain Admins logons to non-Domain Controllers.yml
├── Domains not mitigating CVE-2021-42291.yml
├── Domains not verifying UPN and SPN uniqueness.yml
├── Nested groups within Tier Zero High Value.yml
├── Non-default delegation on MicrosoftDNS container.yml
├── Tier Zero computers with unsupported operating systems.yml
├── DCs vulnerable to NTLM relay to LDAP attacks.yml
├── All members of high privileged roles.yml
├── Domains allowing unauthenticated rootDSE searches and binds.yml
├── KRBTGT accounts with passwords not rotated in over 1 year.yml
├── Domains allowing unauthenticated domain enumeration.yml
├── Non-Tier Zero accounts with SID History of Tier Zero accounts.yml
├── ACEs across trusts.yml
├── Domains exempting privileged groups from AdminSDHolder protections.yml
├── Shortest paths from Entra Users to Tier Zero High Value targets.yml
├── Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled.yml
├── Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6).yml
├── Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8).yml
├── Disabled Tier Zero High Value principals - AD.yml
├── Tier Zero AD principals synchronized with Entra ID.yml
├── Shortest paths from Azure Applications to Tier Zero High Value targets.yml
├── Users with logon scripts stored in a trusted domain.yml
├── All service principals with Microsoft Graph App Role assignments.yml
├── Enrollment rights on published enrollment agent certificate templates.yml
├── Shortest paths to Domain Admins from Kerberoastable users.yml
├── Devices with unsupported operating systems.yml
├── Kerberos-enabled service account member of built-in Admins groups.yml
├── Tier Zero users not member of Protected Users.yml
├── Tier Zero users with passwords not rotated in over 1 year.yml
├── Circular AZ group memberships.yml
├── Compromising permissions on ADCS nodes (ESC5).yml
├── Kerberoastable members of Tier Zero High Value groups.yml
├── Circular AD group memberships.yml
├── Enrollment rights on published ESC1 certificate templates.yml
├── Domains where any user can join a computer to the domain.yml
├── Non-default members in Pre-Windows 2000 Compatible Access.yml
├── Computer owners who can obtain LAPS passwords.yml
├── Tier Zero computers with passwords older than the default maximum password age.yml
├── Accounts related to AAD Entra Connect.yml
├── On-Prem Users synced to Entra Users with Azure RM Roles (direct).yml
├── Principal with SPN keyword.yml
├── Tier Zero accounts that can be delegated.yml
├── All paths crossing a specific trust.yml
├── Shortest paths from Owned objects to Tier Zero.yml
├── Kerberoastable users with most admin privileges.yml
├── Shortest paths to privileged roles.yml
├── Non-Tier Zero account with excessive control.yml
├── Large default group added to computer-local group.yml
├── On-Prem Users synced to Entra Users with Azure RM Roles (group delegated).yml
├── Accounts with weak password storage encryption.yml
├── Usage of built-in domain Administrator account.yml
├── Object name conflict.yml
├── Overprivileged Microsoft Entra Connect accounts.yml
├── Large default groups with outbound control of OUs.yml
├── Domain controllers with UPN certificate mapping enabled.yml
├── Users with non-default Primary Group membership.yml
├── Non-Tier Zero principals with BadSuccessor rights (no prerequisites check).yml
├── All incoming and local paths for a specific computer.yml
├── Tier Zero High Value enabled users not requiring smart card authentication.yml
├── Entra ID SSO accounts not rolling Kerberos decryption key.yml
├── Foreign Service Principals With an EntraID Admin Role.yml
├── Foreign Service Principals With Group Memberships.yml
├── Enrollment rights on published ESC2 certificate templates.yml
├── Enabled users inactive for 180 days.yml
├── All Operators.yml
├── All privileged Azure Service Principals.yml
├── Microsoft Entra Connect accounts with passwords not rotated in over 90 days.yml
├── Computers with non-default Primary Group membership.yml
├── Enrollment rights on published ESC15 certificate templates.yml
├── Enabled computers inactive for 180 days.yml
├── Kerberos-enabled service accounts without AES encryption support.yml
├── All GPOs applied to a specific computer.yml
├── Collection health of DC Registry Data.yml
├── Foreign Service Principals With any Abusable MS Graph App Role Assignment.yml
├── Tier Zero accounts not members of Denied RODC Password Replication Group.yml
├── All ADCS ESC privilege escalation edges.yml
├── Non-Tier Zero principals with control of AdminSDHolder.yml
├── Enabled Tier Zero High Value principals inactive for 60 days.yml
├── Non-Tier Zero principals with BadSuccessor rights (with prerequisites check).yml
├── Tier Zero users with email.yml
├── Potential GPO 'Apply' misconfiguration.yml
├── Collection health of CA Registry Data.yml
├── AdminSDHolder protected Accounts and Groups.yml
├── Enabled computers inactive for 180 days - MSSQL Failover Cluster.yml
├── Large default groups with outbound control.yml
├── Computers with passwords older than the default maximum password age.yml
├── Direct Principal Rights Assignment.yml
├── Non-Tier Zero account with 'Admin Count' flag.yml
└── Uncommon permission on containers.yml
├── LICENSE
├── utilities
└── python
│ ├── convert.py
│ └── schema.py
├── docs
├── query-structure.yml
└── security-assessment-mapping.md
├── .gitignore
├── CODE_OF_CONDUCT.md
└── README.md
/tests/grammar/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/queries.specterops.io.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SpecterOps/BloodHoundQueryLibrary/HEAD/queries.specterops.io.png
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | /.github/workflows/ @d3vzer0
2 | /.github/actions/ @d3vzer0
3 | **/action.yml @d3vzer0
4 | **/action.yaml @d3vzer0
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | pytest==8.3.5
2 | PyYAML==6.0.2
3 | Jinja2==3.1.6
4 | pydantic==2.11.4
5 | typer==0.15.4
6 | antlr4-python3-runtime==4.13.2
--------------------------------------------------------------------------------
/queries/Map OU structure.yml:
--------------------------------------------------------------------------------
1 | name: Map OU structure
2 | guid: 8f14084b-5065-43d8-865a-a6ac52da25d1
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p = (:Domain)-[:Contains*1..]->(:OU)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Map domain trusts.yml:
--------------------------------------------------------------------------------
1 | name: Map domain trusts
2 | guid: 268d3d26-5bc2-4820-a6ed-09d20f3d5413
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p = (:Domain)-[:SameForestTrust|CrossForestTrust]->(:Domain)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/ESC8-vulnerable Enterprise CAs.yml:
--------------------------------------------------------------------------------
1 | name: ESC8-vulnerable Enterprise CAs
2 | guid: 60881923-296c-4702-adf7-a4f059dc9bb8
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH (n:EnterpriseCA)
9 | WHERE n.hasvulnerableendpoint=true
10 | RETURN n
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Entra Users with Entra Admin Role approval (direct).yml:
--------------------------------------------------------------------------------
1 | name: Entra Users with Entra Admin Role approval (direct)
2 | guid: 74d7993c-24af-4df7-8402-5c6fb22d088c
3 | prebuilt: true
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p = (:AZUser)-[:AZRoleApprover]->(:AZRole)
9 | RETURN p LIMIT 100
10 | revision: 1
11 | resources:
12 | acknowledgements:
13 |
--------------------------------------------------------------------------------
/queries/Entra Users with Entra Admin Role direct eligibility.yml:
--------------------------------------------------------------------------------
1 | name: Entra Users with Entra Admin Role direct eligibility
2 | guid: b87899ce-3a51-401a-ae39-ef271b566e3d
3 | prebuilt: true
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p = (:AZUser)-[:AZRoleEligible]->(:AZRole)
9 | RETURN p LIMIT 100
10 | revision: 1
11 | resources:
12 | acknowledgements:
13 |
--------------------------------------------------------------------------------
/queries/Accounts with SID History.yml:
--------------------------------------------------------------------------------
1 | name: Accounts with SID History
2 | guid: 8172d52c-a975-49bd-9180-5b6efc59c9ab
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(:Base)-[:HasSIDHistory]->(:Base)
9 | RETURN p
10 | revision: 1
11 | resources:
12 | acknowledgements: Martin Sohn Christensen, @martinsohndk
13 |
14 |
--------------------------------------------------------------------------------
/queries/Domain migration groups.yml:
--------------------------------------------------------------------------------
1 | name: Domain migration groups
2 | guid: f39c4953-ae92-4d67-bb50-eb1a161d4d3f
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH (n:Group)
9 | WHERE n.name CONTAINS "$$$@"
10 | RETURN n
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Computers not requiring inbound SMB signing.yml:
--------------------------------------------------------------------------------
1 | name: Computers not requiring inbound SMB signing
2 | guid: 6b1fcfb6-b010-41a2-9d31-f9872fe994ff
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH (n:Computer)
9 | WHERE n.smbsigning = False
10 | RETURN n
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Computers with the WebClient running.yml:
--------------------------------------------------------------------------------
1 | name: Computers with the WebClient running
2 | guid: 51107ad1-f0bc-43d3-a561-5cee471ca196
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH (c:Computer)
9 | WHERE c.webclientrunning = True
10 | RETURN c LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/All Global Administrators.yml:
--------------------------------------------------------------------------------
1 | name: All Global Administrators
2 | guid: 94d7d765-6837-4eb8-aa33-e1c9ef262cdc
3 | prebuilt: true
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p=(:AZBase)-[:AZHasRole*1..]->(t:AZRole)
9 | WHERE t.name =~ '(?i)Global Administrator.*'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 2
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/AdminSDHolder to protected objects relationship.yml:
--------------------------------------------------------------------------------
1 | name: AdminSDHolder to protected objects relationship
2 | guid: c751f95c-8bb0-4be4-b027-84f5709c91d2
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n)-[:ProtectAdminGroups]->(m)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
--------------------------------------------------------------------------------
/queries/All DNSAdmins.yml:
--------------------------------------------------------------------------------
1 | name: All DNSAdmins
2 | guid: 183fb320-f3ae-4ab3-a090-3f9a7db692e1
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[:MemberOf]->(g:Group)
9 | WHERE n.name STARTS WITH "DNSADMINS@"
10 | RETURN p
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Principals with DCSync privileges.yml:
--------------------------------------------------------------------------------
1 | name: Principals with DCSync privileges
2 | guid: 6e9beb8a-ad14-43de-bda1-644d174a5906
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(:Base)-[:DCSync|AllExtendedRights|GenericAll]->(:Domain)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/All Domain Admins.yml:
--------------------------------------------------------------------------------
1 | name: All Domain Admins
2 | guid: 0596dba7-9180-49a0-aa54-00243240037c
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p = (t:Group)<-[:MemberOf*1..]-(a)
9 | WHERE (a:User or a:Computer) and t.objectid ENDS WITH '-512'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/CA administrators and CA managers.yml:
--------------------------------------------------------------------------------
1 | name: CA administrators and CA managers
2 | guid: fd35e3d8-0c74-4b5a-a847-c0dd1f1c9f19
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/CA Administrators and CA Managers (ESC7).yml:
--------------------------------------------------------------------------------
1 | name: CA Administrators and CA Managers (ESC7)
2 | guid: 77a708b8-962e-4c3d-ad70-e994126aaeba
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:ManageCertificates|ManageCA]->(:EnterpriseCA)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
--------------------------------------------------------------------------------
/queries/Entra Users with Entra Admin Role approval (group delegated).yml:
--------------------------------------------------------------------------------
1 | name: Entra Users with Entra Admin Role approval (group delegated)
2 | guid: b70a6512-21e1-4d6e-926a-fba44646085d
3 | prebuilt: true
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)
9 | RETURN p LIMIT 100
10 | revision: 1
11 | resources:
12 | acknowledgements:
13 |
--------------------------------------------------------------------------------
/queries/Entra Users with Entra Admin Roles group delegated eligibility.yml:
--------------------------------------------------------------------------------
1 | name: Entra Users with Entra Admin Roles group delegated eligibility
2 | guid: 2e36c81b-25ed-40ba-afec-5f5f6443e095
3 | prebuilt: true
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p = (:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)
9 | RETURN p LIMIT 100
10 | revision: 1
11 | resources:
12 | acknowledgements:
13 |
--------------------------------------------------------------------------------
/queries/PKI hierarchy.yml:
--------------------------------------------------------------------------------
1 | name: PKI hierarchy
2 | guid: 928acc23-ee4c-40a5-bde7-64c05cc1491d
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p=()-[:HostsCAService|IssuedSignedBy|EnterpriseCAFor|RootCAFor|TrustedForNTAuth|NTAuthStoreFor*..]->(:Domain)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Principals with DES-only Kerberos authentication.yml:
--------------------------------------------------------------------------------
1 | name: Principals with DES-only Kerberos authentication
2 | guid: d03ea1ef-70f0-439b-b1ef-d7f94ceb2af3
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.enabled = true
10 | AND n.usedeskeyonly = true
11 | RETURN n
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Users which do not require password to authenticate.yml:
--------------------------------------------------------------------------------
1 | name: Users which do not require password to authenticate
2 | guid: 23bdc2ad-6739-4b2b-85d3-258e3f424eb2
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE u.passwordnotreqd = true
10 | RETURN u
11 | LIMIT 100
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/All Azure VMs with a tied Managed Identity.yml:
--------------------------------------------------------------------------------
1 | name: All Azure VMs with a tied Managed Identity
2 | guid: 3ceca01a-226e-4e61-8692-a4b4611f2af0
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: General
7 | description: Return all Azure VMs with a tied Managed Identity.
8 | query: |-
9 | MATCH p=(:AZVM)-[:AZManagedIdentity]->(n)
10 | RETURN p
11 | revision: 1
12 | resources: -
13 | acknowledgements: Daniel Scheidt, @theluemmel
14 |
--------------------------------------------------------------------------------
/queries/Computers with membership in Protected Users.yml:
--------------------------------------------------------------------------------
1 | name: Computers with membership in Protected Users
2 | guid: a26372f4-2e92-49f6-8993-6657fbc1569a
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:MemberOf*1..]->(g:Group)
9 | WHERE g.objectid ENDS WITH '-525'
10 | RETURN p LIMIT 1000
11 | revision: 2
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Computers with the outgoing NTLM setting set to Deny all.yml:
--------------------------------------------------------------------------------
1 | name: Computers with the outgoing NTLM setting set to Deny all
2 | guid: a9ddca74-feeb-4dbf-8b0f-de08b3cfa8a6
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH (c:Computer)
9 | WHERE c.restrictoutboundntlm = True
10 | RETURN c LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Location of AdminSDHolder Protected objects.yml:
--------------------------------------------------------------------------------
1 | name: Location of AdminSDHolder Protected objects
2 | guid: 3408ccaf-1f42-4c10-b09a-e986661f84d7
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p = (n:Base)<-[:Contains*1..]-(:Domain)
9 | WHERE n.adminsdholderprotected = True
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/Principals with passwords stored using reversible encryption.yml:
--------------------------------------------------------------------------------
1 | name: Principals with passwords stored using reversible encryption
2 | guid: ab900835-b2b8-4674-87b4-8b5141e80439
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.encryptedtextpwdallowed = true
10 | RETURN n
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Principals with foreign domain group membership.yml:
--------------------------------------------------------------------------------
1 | name: Principals with foreign domain group membership
2 | guid: 8fb3214a-5a75-4ecd-b293-c121abd94b4b
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(s:Base)-[:MemberOf]->(t:Group)
9 | WHERE s.domainsid<>t.domainsid
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Shortest paths to Domain Admins.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths to Domain Admins
2 | guid: f40cb34b-5ec7-44bc-9aa8-a200a4a41f22
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((t:Group)<-[:AD_ATTACK_PATHS*1..]-(s:Base))
9 | WHERE t.objectid ENDS WITH '-512' AND s<>t
10 | RETURN p
11 | LIMIT 1000
12 | revision: 2
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Enabled built-in guest user accounts.yml:
--------------------------------------------------------------------------------
1 | name: Enabled built-in guest user accounts
2 | guid: bb0f620d-6a55-4413-ac74-4c82905e8598
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:User)
9 | WHERE n.objectid ENDS WITH "-501"
10 | AND n.enabled = true
11 | RETURN n
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/All Schema Admins.yml:
--------------------------------------------------------------------------------
1 | name: All Schema Admins
2 | guid: 76d8e61d-7a86-40ff-8a85-fd37f1e2563f
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[:MemberOf*1..]->(m:Group)
9 | WHERE (n:User OR n:Computer)
10 | AND m.objectid ENDS WITH "-518" // Schema Admins
11 | RETURN p
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Computers where Domain Users are local administrators.yml:
--------------------------------------------------------------------------------
1 | name: Computers where Domain Users are local administrators
2 | guid: d43a7bdc-33c6-4a39-a3bb-24115749e595
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(s:Group)-[:AdminTo]->(:Computer)
9 | WHERE s.objectid ENDS WITH '-513'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Users with non-expiring passwords.yml:
--------------------------------------------------------------------------------
1 | name: Users with non-expiring passwords
2 | guid: 212c2a98-53d9-4dfa-b177-42c601452dd1
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE u.enabled = true
10 | AND u.pwdneverexpires = true
11 | RETURN u
12 | LIMIT 100
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Dangerous privileges for Domain Users groups.yml:
--------------------------------------------------------------------------------
1 | name: Dangerous privileges for Domain Users groups
2 | guid: 9b8b9c18-f8c6-4c54-a20f-de0f7a7edbe0
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(s:Group)-[r:AD_ATTACK_PATHS]->(:Base)
9 | WHERE s.objectid ENDS WITH '-513'
10 | AND NOT r:MemberOf
11 | RETURN p
12 | LIMIT 1000
13 | revision: 3
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Disabled Tier Zero High Value principals - AZ.yml:
--------------------------------------------------------------------------------
1 | name: Disabled Tier Zero / High Value principals
2 | guid: 860d5c2d-84fe-4c85-80de-e0a9badbd0e7
3 | prebuilt: true
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:AZBase)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND n.enabled = false
11 | RETURN n
12 | LIMIT 100
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Locations of Owned objects - AZ.yml:
--------------------------------------------------------------------------------
1 | name: Locations of Owned objects
2 | guid: 350b8b8a-ea4c-44f3-874b-c9316de6c41b
3 | prebuilt: false
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p = (t:AZBase)<-[:AZContains*1..]-(:AZTenant)
9 | WHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Servers where Domain Users can RDP.yml:
--------------------------------------------------------------------------------
1 | name: Servers where Domain Users can RDP
2 | guid: b9a330ae-1d89-44d4-8f74-9ca18e93eb92
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(s:Group)-[:CanRDP]->(t:Computer)
9 | WHERE s.objectid ENDS WITH '-513' AND toUpper(t.operatingsystem) CONTAINS 'SERVER'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/AS-REP Roastable users (DontReqPreAuth).yml:
--------------------------------------------------------------------------------
1 | name: AS-REP Roastable users (DontReqPreAuth)
2 | guid: 2570e359-dec1-419d-b0dc-a204bd64ee42
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Kerberos Interaction
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE u.dontreqpreauth = true
10 | AND u.enabled = true
11 | RETURN u
12 | LIMIT 100
13 | revision: 1
14 | resources: https://attack.mitre.org/techniques/T1558/004/
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Accounts with SID History to a same-domain account.yml:
--------------------------------------------------------------------------------
1 | name: Accounts with SID History to a same-domain account
2 | guid: 275d2d58-0cad-4cad-8103-e0874cece666
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)
9 | WHERE n.domainsid = m.domainsid
10 | RETURN p
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Computers with unsupported operating systems.yml:
--------------------------------------------------------------------------------
1 | name: Computers with unsupported operating systems
2 | guid: d06d3b14-0318-4fa9-9639-4b79ccaf3c2c
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (c:Computer)
9 | WHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'
10 | RETURN c
11 | LIMIT 100
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Members of Allowed RODC Password Replication Group.yml:
--------------------------------------------------------------------------------
1 | name: Members of Allowed RODC Password Replication Group
2 | guid: 19fc5acd-e30a-4038-a5b5-2e0494f93373
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p=(:Base)-[:MemberOf*1..]->(m:Group)
9 | WHERE m.objectid ENDS WITH "-571"
10 | RETURN p
11 | revision: 2
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Synced Entra Users with Entra Admin Role approval (direct).yml:
--------------------------------------------------------------------------------
1 | name: Synced Entra Users with Entra Admin Role approval (direct)
2 | guid: 1bfe2d75-0a51-4dbe-abc6-178cc0e4476f
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleApprover]->(:AZRole)
11 | RETURN p LIMIT 100
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/Synced Entra Users with Entra Admin Role direct eligibility.yml:
--------------------------------------------------------------------------------
1 | name: Synced Entra Users with Entra Admin Role direct eligibility
2 | guid: ea82e359-725c-4881-83e9-35007e859cf5
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZRoleEligible]->(:AZRole)
11 | RETURN p LIMIT 100
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/All service principals with Microsoft Graph privilege to grant arbitrary App Roles.yml:
--------------------------------------------------------------------------------
1 | name: All service principals with Microsoft Graph privilege to grant arbitrary App Roles
2 | guid: e6d6b5da-89da-4514-a409-2d6e368397da
3 | prebuilt: true
4 | platforms: Azure
5 | category: Microsoft Graph
6 | description:
7 | query: |-
8 | MATCH p=(:AZServicePrincipal)-[:AZMGGrantAppRoles]->(:AZTenant)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Tier Zero High Value external Entra ID users.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero / High Value external Entra ID users
2 | guid: 20e07417-d286-4dca-a962-568f2b262f65
3 | prebuilt: true
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:AZUser)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND n.name CONTAINS '#EXT#@'
11 | RETURN n
12 | LIMIT 100
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Computers where Domain Users can read LAPS passwords.yml:
--------------------------------------------------------------------------------
1 | name: Computers where Domain Users can read LAPS passwords
2 | guid: aa4bfa95-e7b9-4d56-8f35-f34f04d7b6f4
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(s:Group)-[:AllExtendedRights|ReadLAPSPassword]->(:Computer)
9 | WHERE s.objectid ENDS WITH '-513'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Locations of Owned objects - AD.yml:
--------------------------------------------------------------------------------
1 | name: Locations of Owned objects
2 | guid: c88bfab4-3da0-4b36-b71d-7b324ebd2243
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)
9 | WHERE ((t:Tag_Owned) OR COALESCE(t.system_tags, '') CONTAINS 'owned')
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Locations of Tier Zero High Value objects.yml:
--------------------------------------------------------------------------------
1 | name: Locations of Tier Zero / High Value objects
2 | guid: 18a83a17-b451-4343-acfe-7620516e2968
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p = (t:Base)<-[:Contains*1..]-(:Domain)
9 | WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/On-Prem Users synced to Entra Users that Own Entra Objects.yml:
--------------------------------------------------------------------------------
1 | name: On-Prem Users synced to Entra Users that Own Entra Objects
2 | guid: 4baf1026-e64c-4e31-afeb-2090b8090130
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwns]->(:AZBase)
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Owners of Azure Applications.yml:
--------------------------------------------------------------------------------
1 | name: Owners of Azure Applications
2 | guid: 3beb1260-61ad-42b5-819f-e1b619d28e22
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: General
7 | description: Return all Owners of Azure Applications to search for possible attack paths. Low privileged users should not be owners of applications.
8 | query: |-
9 | MATCH p = (n)-[r:AZOwns]->(g:AZApp)
10 | RETURN p
11 | revision: 1
12 | resources: -
13 | acknowledgements: Daniel Scheidt, @theluemmel
14 |
--------------------------------------------------------------------------------
/queries/Shortest paths from Owned objects.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths from Owned objects
2 | guid: e370a01d-c129-4f19-b88d-9479cbe00028
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((s:Base)-[:AD_ATTACK_PATHS*1..]->(t:Base))
9 | WHERE ((s:Tag_Owned) OR COALESCE(s.system_tags, '') CONTAINS 'owned')
10 | AND s<>t
11 | RETURN p
12 | LIMIT 1000
13 | revision: 3
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Workstations where Domain Users can RDP.yml:
--------------------------------------------------------------------------------
1 | name: Workstations where Domain Users can RDP
2 | guid: 9486e0e6-2617-4595-b969-cf57ca21fc86
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(s:Group)-[:CanRDP]->(t:Computer)
9 | WHERE s.objectid ENDS WITH '-513' AND NOT toUpper(t.operatingsystem) CONTAINS 'SERVER'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Cross-forest trusts with abusable configuration.yml:
--------------------------------------------------------------------------------
1 | name: Cross-forest trusts with abusable configuration
2 | guid: 5cf1f354-80d4-420e-bc4b-424fabc21a56
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Domain)-[:CrossForestTrust|SpoofSIDHistory|AbuseTGTDelegation]-(m:Domain)
9 | WHERE (n)-[:SpoofSIDHistory|AbuseTGTDelegation]-(m)
10 | RETURN p
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on published certificate templates.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on published certificate templates
2 | guid: a4ae2e54-aad3-4bfd-a12d-90cb8a9cbc86
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Public Key Services container.yml:
--------------------------------------------------------------------------------
1 | name: Public Key Services container
2 | guid: 07e94492-71aa-4665-ab8c-e7aec25906cd
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (c:Container)-[:Contains*..]->(:Base)
9 | WHERE c.distinguishedname starts with 'CN=PUBLIC KEY SERVICES,CN=SERVICES,CN=CONFIGURATION,DC='
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Unresolved SID with outbound control.yml:
--------------------------------------------------------------------------------
1 | name: Unresolved SID with outbound control
2 | guid: 4e8429f9-cba2-41e9-bac6-0c42f96b2c57
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[r]->(:Base)
9 | WHERE r.isacl
10 | AND n.name CONTAINS "S-1-5-21-" // Unresolved SID
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/On-Prem Users synced to Entra Users with Entra Group Membership.yml:
--------------------------------------------------------------------------------
1 | name: On-Prem Users synced to Entra Users with Entra Group Membership
2 | guid: edb575df-2048-4ef0-a0e4-168544a496e9
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Shortest Paths from Azure Users to Azure VMs.yml:
--------------------------------------------------------------------------------
1 | name: Shortest Paths from Azure Users to Azure VMs
2 | guid: 912454f1-75a3-4813-b3df-7bddac0ff00d
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: Shortest Paths
7 | description: Return shortest paths from Azure Users to Azure VMs to check for attack vectors.
8 | query: |-
9 | MATCH p = shortestPath((m:AZUser)-[:AZ_ATTACK_PATHS*..]->(n:AZVM))
10 | RETURN p
11 | revision: 1
12 | resources: -
13 | acknowledgements: Daniel Scheidt, @theluemmel
14 |
--------------------------------------------------------------------------------
/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (direct).yml:
--------------------------------------------------------------------------------
1 | name: On-Prem Users synced to Entra Users with Entra Admin Roles (direct)
2 | guid: de717635-d31f-4fbd-930b-b4dac0f22118
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZHasRole]->(:AZRole)
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Shortest paths to systems trusted for unconstrained delegation.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths to systems trusted for unconstrained delegation
2 | guid: 16a9e47b-45f8-4514-b409-771bb5186142
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Computer))
9 | WHERE t.unconstraineddelegation = true AND s<>t
10 | RETURN p
11 | LIMIT 1000
12 | revision: 2
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers not owned by Tier Zero.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers not owned by Tier Zero
2 | guid: 99d29ded-223a-442b-a0e0-f8b5694c6441
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[:Owns]->(:Computer)
9 | WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | RETURN p
11 | revision: 2
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Domains with functional level not the latest version.yml:
--------------------------------------------------------------------------------
1 | name: Domains with functional level not the latest version
2 | guid: 3da9d14a-f1cb-4df7-b3da-8d73ff5c401b
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE toString(n.functionallevel) IN ['2008','2003','2003 Interim','2000 Mixed/Native']
10 | RETURN n
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Tier Zero principals without AdminSDHolder protection.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero principals without AdminSDHolder protection
2 | guid: 82ce5e2e-415b-489d-b891-304e8bb25998
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND n.adminsdholderprotected = false
11 | RETURN n
12 | LIMIT 500
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
--------------------------------------------------------------------------------
/queries/Map Azure Management structure.yml:
--------------------------------------------------------------------------------
1 | name: Map Azure Management structure
2 | guid: c1bb109e-e6a4-4c91-864f-f78e1e42615e
3 | prebuilt: false
4 | platforms: Azure
5 | category: General
6 | description: Maps the structure of Azure Management
7 | query: |-
8 | MATCH p = (:AZTenant)-[:AZContains*1..]->(:AZResourceGroup)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 2
12 | resources: https://learn.microsoft.com/en-us/azure/governance/management-groups/overview
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Synced Entra Users with Entra Admin Role approval (group delegated).yml:
--------------------------------------------------------------------------------
1 | name: Synced Entra Users with Entra Admin Role approval (group delegated)
2 | guid: ead56ecb-fb88-427c-8f39-75e774bb9a0a
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleApprover]->(:AZRole)
11 | RETURN p LIMIT 100
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/Shortest Paths from Azure Users to Azure Keyvaults.yml:
--------------------------------------------------------------------------------
1 | name: Shortest Paths from Azure Users to Azure Keyvaults
2 | guid: 6395428d-2deb-404b-85b5-edbac3a6e05d
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: Shortest Paths
7 | description: Return shortest paths from Azure Users to Azure Keyvaults to check for attack vectors.
8 | query: |-
9 | MATCH p = shortestPath((n:AZUser)-[:AZ_ATTACK_PATHS*..]->(g:AZKeyVault))
10 | RETURN p
11 | revision: 1
12 | resources: -
13 | acknowledgements: Daniel Scheidt, @theluemmel
14 |
--------------------------------------------------------------------------------
/queries/Shortest paths to Azure Subscriptions.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths to Azure Subscriptions
2 | guid: 4785b305-c101-461c-80fc-3fb3ff67a8ce
3 | prebuilt: true
4 | platforms: Azure
5 | category: Shortest Paths
6 | description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE
7 | query: |-
8 | MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZSubscription))
9 | WHERE s<>t
10 | RETURN p
11 | LIMIT 1000
12 | revision: 3
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Shortest paths to Tier Zero High Value targets.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths to Tier Zero / High Value targets
2 | guid: 237aac58-8641-4703-a9f7-001d69546fd8
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((s)-[:AD_ATTACK_PATHS*1..]->(t:Base))
9 | WHERE ((t:Tag_Tier_Zero) OR (COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0'))
10 | AND s<>t
11 | RETURN p
12 | LIMIT 1000
13 | revision: 3
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Synced Entra Users with Entra Admin Roles group delegated eligibility.yml:
--------------------------------------------------------------------------------
1 | name: Synced Entra Users with Entra Admin Roles group delegated eligibility
2 | guid: bc610e20-e5c0-41f3-9e8e-7378f87a3f71
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZRoleEligible]->(:AZRole)
11 | RETURN p LIMIT 100
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on CertTemplates with OIDGroupLink.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on CertTemplates with OIDGroupLink
2 | guid: 140a68eb-d21c-4b75-971f-309225fb2d75
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(:CertTemplate)-[:ExtendedByPolicy]->(:IssuancePolicy)-[:OIDGroupLink]->(:Group)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Domain Controllers allowing NTLMv1 or LM authentication.yml:
--------------------------------------------------------------------------------
1 | name: Domain Controllers allowing NTLMv1 or LM authentication
2 | guid: 4b42513c-f89d-47ff-8d98-908af49d2b48
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH (dc:Computer)
9 | WHERE dc.isdc = true
10 | AND (dc.lmcompatibilitylevel IS NOT NULL AND NOT dc.lmcompatibilitylevel = 5)
11 | RETURN dc
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers not requiring inbound SMB signing.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers not requiring inbound SMB signing
2 | guid: 13485477-f026-4b1f-906d-4f2e37364ba4
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH (n:Computer)
9 | WHERE n.smbsigning = False
10 | AND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN n
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Entra Users synced from On-Prem Users added to Domain Admins group.yml:
--------------------------------------------------------------------------------
1 | name: Entra Users synced from On-Prem Users added to Domain Admins group
2 | guid: 62722d5f-bd93-4d11-beeb-9be261827e4e
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:AZUser)-[:SyncedToADUser]->(:User)-[:MemberOf]->(t:Group)
11 | WHERE t.objectid ENDS WITH '-512'
12 | RETURN p
13 | LIMIT 1000
14 | revision: 1
15 | resources:
16 | acknowledgements:
17 |
18 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers at risk of constrained delegation.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers at risk of constrained delegation
2 | guid: 8641e593-f2f2-48ba-bd45-fbc86e9f632a
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p = (n:Computer)<-[:AllowedToDelegate]-(:Base)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | RETURN p
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers with the WebClient running.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers with the WebClient running
2 | guid: 27a6f917-8ed4-4e2e-9b38-41a4b6de1b14
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (c:Computer)
9 | WHERE c.webclientrunning = True
10 | AND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN c LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Domains with a minimum default password policy length less than 15 characters.yml:
--------------------------------------------------------------------------------
1 | name: Domains with a minimum default password policy length less than 15 characters
2 | guid: 7d258d2d-a43d-4a90-85d7-71c946ae5fd7
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.minpwdlength < 15
10 | RETURN n
11 | revision: 1
12 | resources: https://pages.nist.gov/800-63-3/sp800-63b.html
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Non-Tier Zero account with unconstrained delegation.yml:
--------------------------------------------------------------------------------
1 | name: Non-Tier Zero account with unconstrained delegation
2 | guid: e7e9a927-3f34-42c7-b921-d8bcf626011e
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.unconstraineddelegation = true
10 | AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN n
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Tier Zero High Value users with non-expiring passwords.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero / High Value users with non-expiring passwords
2 | guid: 4eca1b69-00a2-48a0-abb3-b94ea647cf6b
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.enabled = true
10 | AND u.pwdneverexpires = true
11 | RETURN u
12 | LIMIT 100
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Users with passwords not rotated in over 1 year.yml:
--------------------------------------------------------------------------------
1 | name: Users with passwords not rotated in over 1 year
2 | guid: be70d1bd-b7eb-40b0-971c-eefc50eca032
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | WITH 365 as days_since_change
9 | MATCH (u:User)
10 | WHERE u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))
11 | AND NOT u.pwdlastset IN [-1.0, 0.0]
12 | RETURN u
13 | LIMIT 100
14 | revision: 1
15 | resources:
16 | acknowledgements:
17 |
18 |
--------------------------------------------------------------------------------
/queries/Accounts with SID History to a non-existent domain.yml:
--------------------------------------------------------------------------------
1 | name: Accounts with SID History to a non-existent domain
2 | guid: 2710401a-c4c2-4d2c-9edb-d7625045f2e8
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (d:Domain)
9 | WITH collect(d.objectid) AS domainSIDs
10 | MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)
11 | WHERE NOT n.domainsid IN domainSIDs
12 | RETURN p
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Accounts with clear-text password attributes.yml:
--------------------------------------------------------------------------------
1 | name: Accounts with clear-text password attributes
2 | guid: e303498f-e3d4-489d-8a34-b68e187bc4e7
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.userpassword IS NOT NULL
10 | OR n.unixpassword IS NOT NULL
11 | OR n.unicodepwd IS NOT NULL
12 | OR n.msSFU30Password IS NOT NULL
13 | RETURN n
14 | revision: 1
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/All direct Controllers of MS Graph.yml:
--------------------------------------------------------------------------------
1 | name: All direct Controllers of MS Graph
2 | guid: 45f949ca-ab69-43a4-adb2-796f9548beff
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: Microsoft Graph
7 | description: Return all direct Controllers of MS Graph.
8 | query: |-
9 | MATCH p = (n)-[r:AZAddOwner|AZAddSecret|AZAppAdmin|AZCloudAppAdmin|AZMGAddOwner|AZMGAddSecret|AZOwns]->(g:AZServicePrincipal)
10 | WHERE g.displayname = "MICROSOFT GRAPH"
11 | RETURN p
12 | revision: 1
13 | resources: -
14 | acknowledgements: Daniel Scheidt, @theluemmel
15 |
--------------------------------------------------------------------------------
/queries/Domain controllers with weak certificate binding enabled.yml:
--------------------------------------------------------------------------------
1 | name: Domain controllers with weak certificate binding enabled
2 | guid: a2444d99-10b5-412d-8fea-4b063cfddd2c
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (s:Computer)-[:DCFor]->(:Domain)
9 | WHERE s.strongcertificatebindingenforcementraw = 0 OR s.strongcertificatebindingenforcementraw = 1
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Domains with a single-point-of-failure Domain Controller.yml:
--------------------------------------------------------------------------------
1 | name: Domains with a single-point-of-failure Domain Controller
2 | guid: 3359a295-7cfd-491f-976b-c5a68647431c
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Group)<-[:MemberOf]-(:Computer)
9 | WHERE n.objectid ENDS WITH '-516'
10 | WITH n, COUNT(n) AS dcCount
11 | WHERE dcCount = 1
12 | RETURN n
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Domains without Microsoft LAPS computers.yml:
--------------------------------------------------------------------------------
1 | name: Domains without Microsoft LAPS computers
2 | guid: f9b440b5-732c-4ed3-b6d2-83857db17e1a
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH (d:Domain)
9 | OPTIONAL MATCH (c:Computer)
10 | WHERE c.domainsid = d.objectid AND c.haslaps = true
11 | WITH d, COLLECT(c) AS computers
12 | WHERE SIZE(computers) = 0
13 | RETURN d
14 | revision: 1
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated).yml:
--------------------------------------------------------------------------------
1 | name: On-Prem Users synced to Entra Users with Entra Admin Roles (group delegated)
2 | guid: 609d648f-7fb8-42d3-ad99-626f9ce1f121
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZHasRole]->(:AZRole)
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Principals with weak supported Kerberos encryption types.yml:
--------------------------------------------------------------------------------
1 | name: Principals with weak supported Kerberos encryption types
2 | guid: ca329573-2157-41da-ab17-4d122c54b11d
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (u:Base)
9 | WHERE 'DES-CBC-CRC' IN u.supportedencryptiontypes
10 | OR 'DES-CBC-MD5' IN u.supportedencryptiontypes
11 | OR 'RC4-HMAC-MD5' IN u.supportedencryptiontypes
12 | RETURN u
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/All coerce and NTLM relay edges.yml:
--------------------------------------------------------------------------------
1 | name: All coerce and NTLM relay edges
2 | guid: 15c5ff3b-856c-44d1-a731-a8cb72512dd1
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH p = (n:Base)-[:CoerceAndRelayNTLMToLDAP|CoerceAndRelayNTLMToLDAPS|CoerceAndRelayNTLMToADCS|CoerceAndRelayNTLMToSMB]->(:Base)
9 | RETURN p LIMIT 500
10 | revision: 1
11 | resources: https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/
12 | acknowledgements:
13 |
14 |
--------------------------------------------------------------------------------
/queries/Non-default permissions on IssuancePolicy nodes.yml:
--------------------------------------------------------------------------------
1 | name: Non-default permissions on IssuancePolicy nodes
2 | guid: b2280665-c91b-448c-8c0f-97d1f38b6f59
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (s:Base)-[:GenericAll|GenericWrite|Owns|WriteOwner|WriteDacl]->(:IssuancePolicy)
9 | WHERE NOT s.objectid ENDS WITH '-512' AND NOT s.objectid ENDS WITH '-519'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Owners of Azure Subscriptions.yml:
--------------------------------------------------------------------------------
1 | name: Owners of Azure Subscriptions
2 | guid: bd0daafd-4256-4ce6-9b7f-a9e38509d81c
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: General
7 | description: Return all Owners of Azure Subscriptions to search for possible attack paths. Low privileged users should not be owners of Subscriptions.
8 | query: |-
9 | MATCH p=shortestPath((s:AZBase)-[:AZOwner*1..]->(t:AZSubscription))
10 | WHERE s<>t
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources: -
15 | acknowledgements: Daniel Scheidt, @theluemmel
16 |
--------------------------------------------------------------------------------
/queries/Domains without Protected Users group.yml:
--------------------------------------------------------------------------------
1 | name: Domains without Protected Users group
2 | guid: 8c3e0811-a31b-45b4-a29d-1dce80fa2c5f
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.collected = true
10 | OPTIONAL MATCH (m:Group)
11 | WHERE m.name ENDS WITH n.name
12 | AND m.objectid ENDS WITH '-525'
13 | WITH n, m
14 | WHERE m IS NULL
15 | RETURN n
16 | revision: 1
17 | resources:
18 | acknowledgements: Martin Sohn Christensen, @martinsohndk
19 |
20 |
--------------------------------------------------------------------------------
/queries/Shortest Paths from Owned Azure Users to Azure VMs.yml:
--------------------------------------------------------------------------------
1 | name: Shortest Paths from Owned Azure Users to Azure VMs
2 | guid: bab9fbec-7a46-4c1e-902e-a1b53a454610
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: Shortest Paths
7 | description: Return shortest paths from Owned Azure Users to Azure VMs to check for attack vectors.
8 | query: |-
9 | MATCH p = shortestPath((m:AZUser)-[:AZ_ATTACK_PATHS*..]->(n:AZVM))
10 | WHERE m.system_tags CONTAINS 'owned'
11 | RETURN p
12 | revision: 1
13 | resources: -
14 | acknowledgements: Daniel Scheidt, @theluemmel
15 |
--------------------------------------------------------------------------------
/queries/All Kerberoastable users.yml:
--------------------------------------------------------------------------------
1 | name: All Kerberoastable users
2 | guid: 14ab4eaa-b73b-49c4-b2d1-1e020757c995
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Kerberos Interaction
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE u.hasspn=true
10 | AND u.enabled = true
11 | AND NOT u.objectid ENDS WITH '-502'
12 | AND NOT COALESCE(u.gmsa, false) = true
13 | AND NOT COALESCE(u.msa, false) = true
14 | RETURN u
15 | LIMIT 100
16 | revision: 1
17 | resources: https://attack.mitre.org/techniques/T1558/003/
18 | acknowledgements:
19 |
20 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers at risk of resource-based constrained delegation.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers at risk of resource-based constrained delegation
2 | guid: 4dc97cf4-3c03-4fe6-8a8b-4f665c67e1e5
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p = (n:Computer)<-[:AllowedToAct]-(:Base)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | RETURN p
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Smart card accounts with passwords not rotated in over 1 year.yml:
--------------------------------------------------------------------------------
1 | name: Smart card accounts with passwords not rotated in over 1 year
2 | guid: 7e56f2e7-79c3-4f0d-aa3e-14cf3de7ab73
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.pwdlastset < (datetime().epochseconds - (365 * 86400))
10 | AND n.enabled = true
11 | AND n.smartcardrequired = true
12 | RETURN n
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/AS-REP Roastable Tier Zero users (DontReqPreAuth).yml:
--------------------------------------------------------------------------------
1 | name: AS-REP Roastable Tier Zero users (DontReqPreAuth)
2 | guid: 6d51e4dc-e1ad-477a-b6c6-324f18f03120
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND n.dontreqpreauth = true
11 | RETURN n
12 | revision: 1
13 | resources: https://attack.mitre.org/techniques/T1558/004/
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Domains with List Object mode enabled.yml:
--------------------------------------------------------------------------------
1 | name: Domains with List Object mode enabled
2 | guid: 05e2a94b-5ee6-47ec-b715-3982f30af01b
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: Checks the fDoListObject flag of dSHeuristics.
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.dsheuristics =~ ".{2}[^0].*"
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Domains with more than 50 Tier Zero accounts.yml:
--------------------------------------------------------------------------------
1 | name: Domains with more than 50 Tier Zero accounts
2 | guid: f046e95a-5f84-4e83-bcda-6e83f3d8e21a
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (d:Domain)-[:Contains*1..]->(n:Base)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | WITH d, COUNT(n) AS adminCount
11 | WHERE adminCount > 50
12 | RETURN d
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Domains with smart card accounts where smart account passwords do not expire.yml:
--------------------------------------------------------------------------------
1 | name: Domains with smart card accounts where smart account passwords do not expire
2 | guid: 97e05e67-5961-4aba-a8e7-fe5f92334035
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (s:Domain)-[:Contains*1..]->(t:Base)
9 | WHERE s.expirepasswordsonsmartcardonlyaccounts = false
10 | AND t.enabled = true
11 | AND t.smartcardrequired = true
12 | RETURN s
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Domains allowing authenticated domain enumeration.yml:
--------------------------------------------------------------------------------
1 | name: Domains allowing authenticated domain enumeration
2 | guid: 1e1e6fdd-6973-4547-906c-a494b5fbdcba
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[:MemberOf]->(m:Group)
9 | WHERE n.objectid ENDS WITH "S-1-5-11" // Authenticated Users
10 | AND m.objectid ENDS WITH "S-1-5-32-554" // Pre-Windows 2000 Compatible Access
11 | RETURN p
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Paths from Domain Users to Tier Zero High Value targets.yml:
--------------------------------------------------------------------------------
1 | name: Paths from Domain Users to Tier Zero / High Value targets
2 | guid: 977bec40-565c-40b8-90c8-e3e122c291cd
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))
9 | WHERE s.objectid ENDS WITH '-513' AND s<>t
10 | AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN p
12 | LIMIT 1000
13 | revision: 2
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Shortest Paths from Owned Azure Users to Azure Keyvaults.yml:
--------------------------------------------------------------------------------
1 | name: Shortest Paths from Owned Azure Users to Azure Keyvaults
2 | guid: 53e73ae0-985e-4508-a82e-696d654f9538
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: Shortest Paths
7 | description: Return shortest paths from Owned Azure Users to Azure Keyvaults to check for attack vectors.
8 | query: |-
9 | MATCH p = shortestPath((n:AZUser)-[:AZ_ATTACK_PATHS*..]->(g:AZKeyVault))
10 | WHERE m.system_tags CONTAINS 'owned'
11 | RETURN p
12 | revision: 1
13 | resources: -
14 | acknowledgements: Daniel Scheidt, @theluemmel
15 |
--------------------------------------------------------------------------------
/queries/Foreign principals in Tier Zero High Value targets.yml:
--------------------------------------------------------------------------------
1 | name: Foreign principals in Tier Zero / High Value targets
2 | guid: 95bec736-86ef-4017-8465-9b9b66548b17
3 | prebuilt: true
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:AZServicePrincipal)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND NOT toUpper(n.appownerorganizationid) = toUpper(n.tenantid)
11 | AND n.appownerorganizationid CONTAINS '-'
12 | RETURN n
13 | LIMIT 100
14 | revision: 1
15 | resources:
16 | acknowledgements:
17 |
18 |
--------------------------------------------------------------------------------
/queries/Accounts with smart card required in domains where smart account passwords do not expire.yml:
--------------------------------------------------------------------------------
1 | name: Accounts with smart card required in domains where smart account passwords do not expire
2 | guid: bba7985e-f32a-4c62-b1b0-0365bf1455e6
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(s:Domain)-[:Contains*1..]->(t:Base)
9 | WHERE s.expirepasswordsonsmartcardonlyaccounts = false
10 | AND t.enabled = true
11 | AND t.smartcardrequired = true
12 | RETURN p
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
--------------------------------------------------------------------------------
/queries/Domains affected by AdPrep privilege escalation risk.yml:
--------------------------------------------------------------------------------
1 | name: Domains affected by AdPrep privilege escalation risk
2 | guid: 815ff190-f6f3-4757-a516-2f4bf589b705
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[r:GenericAll]->(m:Domain)
9 | WHERE n.objectid ENDS WITH "-527" // Enterprise Key Admins
10 | AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN p
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on published certificate templates with no security extension.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on published certificate templates with no security extension
2 | guid: 0677b70c-4e04-4e89-a6a2-f5764604a6a7
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)
9 | WHERE ct.nosecurityextension = true
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Sessions across trusts.yml:
--------------------------------------------------------------------------------
1 | name: Sessions across trusts
2 | guid: aea7ac64-1f51-407b-b0ee-19fd30075794
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: Users logging on across a trust, the users originate from trusted domains.
7 | query: |-
8 | MATCH p=(trustedDomainPrincipal:Computer)-[r:HasSession]->(trustingDomainPrincipal:User)
9 | WHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Shortest paths from Domain Users to Tier Zero High Value targets.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths from Domain Users to Tier Zero / High Value targets
2 | guid: 469dc0f3-71b8-41b0-a03b-b4af7874665d
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((s:Group)-[:AD_ATTACK_PATHS*1..]->(t:Base))
9 | WHERE s.objectid ENDS WITH '-513' AND s<>t
10 | AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN p
12 | LIMIT 1000
13 | revision: 2
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Domains affected by Exchange privilege escalation risk.yml:
--------------------------------------------------------------------------------
1 | name: Domains affected by Exchange privilege escalation risk
2 | guid: f2d09c94-b6f2-4901-9a2d-f8bacd61edc7
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[r:WriteDacl|ForceChangePassword|AddMember]->(m:Base)
9 | WHERE n.name STARTS WITH "EXCHANGE "
10 | AND ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN p
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Domains allowing unauthenticated NSPI RPC binds.yml:
--------------------------------------------------------------------------------
1 | name: Domains allowing unauthenticated NSPI RPC binds
2 | guid: a950fdab-5934-4c69-a88b-e2e0e3da9d52
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Checks the fAllowAnonNSPI flag of dSHeuristics.
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.dsheuristics =~ ".{7}[^0].*"
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Computers without Windows LAPS.yml:
--------------------------------------------------------------------------------
1 | name: Computers without Windows LAPS
2 | guid: 7c50f724-c467-4005-8e3f-9a6ce1461db0
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (c:Computer)
9 | WHERE c.operatingsystem =~ '(?i).*WINDOWS (SERVER)? ?(10|11|2019|2022|2025).*'
10 | AND c.haslaps = false
11 | AND c.enabled = true
12 | RETURN c
13 | LIMIT 100
14 | revision: 1
15 | resources: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Domain Admins logons to non-Domain Controllers.yml:
--------------------------------------------------------------------------------
1 | name: Domain Admins logons to non-Domain Controllers
2 | guid: e2f3fd0a-1df2-4089-b0a4-272ad6e369a9
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH (s)-[:MemberOf*0..]->(g:Group)
9 | WHERE g.objectid ENDS WITH '-516'
10 | WITH COLLECT(s) AS exclude
11 | MATCH p = (c:Computer)-[:HasSession]->(:User)-[:MemberOf*1..]->(g:Group)
12 | WHERE g.objectid ENDS WITH '-512' AND NOT c IN exclude
13 | RETURN p
14 | LIMIT 1000
15 | revision: 1
16 | resources:
17 | acknowledgements:
18 |
19 |
--------------------------------------------------------------------------------
/queries/Domains not mitigating CVE-2021-42291.yml:
--------------------------------------------------------------------------------
1 | name: Domains not mitigating CVE-2021-42291
2 | guid: 02202726-d86d-46c2-891c-9770c635f76f
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Checks the AttributeAuthorizationOnLDAPAdd flag of dSHeuristics.
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.dsheuristics =~ "^(.{0,27}|.{27}[^1].*)$"
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Domains not verifying UPN and SPN uniqueness.yml:
--------------------------------------------------------------------------------
1 | name: Domains not verifying UPN and SPN uniqueness
2 | guid: cb0b1591-5c3e-45f1-afb7-984e5ad865d0
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Checks the DoNotVerifyUPNAndOrSPNUniqueness flag of dSHeuristics.
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.dsheuristics =~ ".{20}[^0].*"
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Nested groups within Tier Zero High Value.yml:
--------------------------------------------------------------------------------
1 | name: Nested groups within Tier Zero / High Value
2 | guid: 8e541e75-df1d-423f-b429-4bbf0403a338
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(t:Group)<-[:MemberOf*..]-(s:Group)
9 | WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND NOT s.objectid ENDS WITH '-512' // Domain Admins
11 | AND NOT s.objectid ENDS WITH '-519' // Enterprise Admins
12 | RETURN p
13 | LIMIT 1000
14 | revision: 1
15 | resources:
16 | acknowledgements:
17 |
18 |
--------------------------------------------------------------------------------
/queries/Non-default delegation on MicrosoftDNS container.yml:
--------------------------------------------------------------------------------
1 | name: Non-default delegation on MicrosoftDNS container
2 | guid: 008792c0-4458-46a1-a10d-50cdaf95af1e
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[r]->(m:Container)
9 | WHERE m.distinguishedname STARTS WITH "CN=MICROSOFTDNS,CN=SYSTEM,DC="
10 | AND NOT n.name STARTS WITH "DNSADMINS@"
11 | AND NOT n.objectid =~ "-(512|544|519|9)$"
12 | AND r.isacl
13 | RETURN p
14 | revision: 1
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers with unsupported operating systems.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers with unsupported operating systems
2 | guid: a87b558c-5746-4a90-9f83-c86e7b924a52
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (c:Computer)
9 | WHERE c.operatingsystem =~ '(?i).*Windows.* (2000|2003|2008|2012|xp|vista|7|8|me|nt).*'
10 | AND ((c:Tag_Tier_Zero) OR COALESCE(c.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN c
12 | LIMIT 100
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/DCs vulnerable to NTLM relay to LDAP attacks.yml:
--------------------------------------------------------------------------------
1 | name: DCs vulnerable to NTLM relay to LDAP attacks
2 | guid: 3f87e0b0-fc06-4986-a94c-e08781253dc8
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: NTLM Relay Attacks
6 | description:
7 | query: |-
8 | MATCH p = (dc:Computer)-[:DCFor]->(:Domain)
9 | WHERE (dc.ldapavailable = True AND dc.ldapsigning = False)
10 | OR (dc.ldapsavailable = True AND dc.ldapsepa = False)
11 | OR (dc.ldapavailable = True AND dc.ldapsavailable = True AND dc.ldapsigning = False and dc.ldapsepa = True)
12 | RETURN p
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/All members of high privileged roles.yml:
--------------------------------------------------------------------------------
1 | name: All members of high privileged roles
2 | guid: 3df24d92-dd12-4125-811b-e696b098f60e
3 | prebuilt: true
4 | platforms: Azure
5 | category: General
6 | description:
7 | query: |-
8 | MATCH p=(t:AZRole)<-[:AZHasRole|AZMemberOf*1..2]-(:AZBase)
9 | WHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator|Privileged Role Administrator'
10 | RETURN p
11 | LIMIT 1000
12 | revision: 2
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Domains allowing unauthenticated rootDSE searches and binds.yml:
--------------------------------------------------------------------------------
1 | name: Domains allowing unauthenticated rootDSE searches and binds
2 | guid: ebc79aa4-e816-4be8-93fe-a0b30dbc771d
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Checks the fLDAPBlockAnonOps flag of dSHeuristics.
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.dsheuristics =~ ".{6}[^2].*"
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/KRBTGT accounts with passwords not rotated in over 1 year.yml:
--------------------------------------------------------------------------------
1 | name: KRBTGT accounts with passwords not rotated in over 1 year
2 | guid: 1b3ae310-ffa7-4ce5-a37f-6111aef600c8
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:User)
9 | WHERE (n.objectid ENDS WITH '-502'
10 | OR n.name STARTS WITH 'AZUREADKERBEROS.'
11 | OR n.name STARTS WITH 'KRBTGT_AZUREAD@')
12 | AND n.pwdlastset < (datetime().epochseconds - (365 * 86400))
13 | RETURN n
14 | revision: 1
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Domains allowing unauthenticated domain enumeration.yml:
--------------------------------------------------------------------------------
1 | name: Domains allowing unauthenticated domain enumeration
2 | guid: 41a08d76-f8a5-4296-ad19-464c4c5c69fe
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[:MemberOf]->(m:Group)
9 | WHERE (n.objectid ENDS WITH "S-1-5-7" // Anonymous
10 | OR n.objectid ENDS WITH "S-1-1-0") // Everyone
11 | AND m.objectid ENDS WITH "S-1-5-32-554" // Pre-Windows 2000 Compatible Access
12 | RETURN p
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Non-Tier Zero accounts with SID History of Tier Zero accounts.yml:
--------------------------------------------------------------------------------
1 | name: Non-Tier Zero accounts with SID History of Tier Zero accounts
2 | guid: 59744dfe-9411-4daf-b342-1203dc62acd4
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[:HasSIDHistory]->(m:Base)
9 | WHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | RETURN p
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/ACEs across trusts.yml:
--------------------------------------------------------------------------------
1 | name: ACEs across trusts
2 | guid: c902d3b4-1a75-4335-acd7-28246dab746d
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: ACEs granted across a trust, the ACEs are set on trusting objects and the rights are granted to objects from trusted domains.
7 | query: |-
8 | MATCH p=(trustedDomainPrincipal:Base)-[r]->(trustingDomainPrincipal:Base)
9 | WHERE trustedDomainPrincipal.domainsid <> trustingDomainPrincipal.domainsid
10 | AND r.isacl
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Domains exempting privileged groups from AdminSDHolder protections.yml:
--------------------------------------------------------------------------------
1 | name: Domains exempting privileged groups from AdminSDHolder protections
2 | guid: 79f8d8f9-8291-4bf7-a13a-15989018075f
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Checks the dwAdminSDExMask flag of dSHeuristics.
7 | query: |-
8 | MATCH (n:Domain)
9 | WHERE n.dsheuristics =~ ".{15}[^0].*"
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/e5899be4-862e-496f-9a38-33950617d2c5
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Shortest paths from Entra Users to Tier Zero High Value targets.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths from Entra Users to Tier Zero / High Value targets
2 | guid: 58089b28-54e0-4fd2-bf66-3db480b00e2f
3 | prebuilt: true
4 | platforms: Azure
5 | category: Shortest Paths
6 | description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE
7 | query: |-
8 | MATCH p=shortestPath((s:AZUser)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))
9 | WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')
10 | RETURN p
11 | LIMIT 1000
12 | revision: 3
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled
2 | guid: 96e70597-2d74-4503-a624-f1e30b642894
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)
9 | WHERE eca.isuserspecifiessanenabled = True
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6).yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on certificate templates published to Enterprise CA with User Specified SAN enabled (ESC6)
2 | guid: ab14e9dc-996c-4737-878c-583c19cdbf5a
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)
9 | WHERE eca.isuserspecifiessanenabled = True
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8).yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on certificate templates published to Enterprise CA with vulnerable HTTP(S) endpoint (ESC8)
2 | guid: 1c1435b1-bad0-49f2-ba7d-932e047c0af4
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(eca:EnterpriseCA)
9 | WHERE eca.hasvulnerableendpoint = True
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | acknowledgements:
15 |
--------------------------------------------------------------------------------
/queries/Disabled Tier Zero High Value principals - AD.yml:
--------------------------------------------------------------------------------
1 | name: Disabled Tier Zero / High Value principals
2 | guid: d65a801f-d3ef-4b7e-8030-99ebfd6dad12
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND n.enabled = false
11 | AND NOT n.objectid ENDS WITH '-502' // Removes false positive, KRBTGT
12 | AND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator
13 | RETURN n
14 | LIMIT 100
15 | revision: 1
16 | resources:
17 | acknowledgements:
18 |
19 |
--------------------------------------------------------------------------------
/queries/Tier Zero AD principals synchronized with Entra ID.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero AD principals synchronized with Entra ID
2 | guid: a8b6ec67-21aa-4dd2-8906-47bb81bf5262
3 | prebuilt: true
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description:
7 | query: |-
8 | MATCH (ENTRA:AZBase)
9 | MATCH (AD:Base)
10 | WHERE ((AD:Tag_Tier_Zero) OR COALESCE(AD.system_tags, '') CONTAINS 'admin_tier_0')
11 | AND ENTRA.onpremsyncenabled = true
12 | AND ENTRA.onpremid = AD.objectid
13 | RETURN ENTRA
14 | // Replace 'RETURN ENTRA' with 'RETURN AD' to see the corresponding AD principals
15 | LIMIT 100
16 | revision: 1
17 | resources:
18 | acknowledgements:
19 |
20 |
--------------------------------------------------------------------------------
/queries/Shortest paths from Azure Applications to Tier Zero High Value targets.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths from Azure Applications to Tier Zero / High Value targets
2 | guid: 60ff7c58-a98e-4bc1-9e32-8378d2db0c43
3 | prebuilt: true
4 | platforms: Azure
5 | category: Shortest Paths
6 | description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE
7 | query: |-
8 | MATCH p=shortestPath((s:AZApp)-[:AZ_ATTACK_PATHS*1..]->(t:AZBase))
9 | WHERE ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0') AND s<>t
10 | RETURN p
11 | LIMIT 1000
12 | revision: 3
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Users with logon scripts stored in a trusted domain.yml:
--------------------------------------------------------------------------------
1 | name: Users with logon scripts stored in a trusted domain
2 | guid: 8d94d3f3-3d53-4939-a206-3c0a4dd3f646
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:User)
9 | WHERE n.logonscript IS NOT NULL
10 | MATCH (d:Domain)<-[:SameForestTrust|CrossForestTrust]-(:Domain)-[:Contains*1..]->(n)
11 | WITH n,last(split(d.name, '@')) AS domain
12 | WHERE toUpper(n.logonscript) STARTS WITH ("\\\\" + domain + "\\")
13 | RETURN n
14 | revision: 2
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/All service principals with Microsoft Graph App Role assignments.yml:
--------------------------------------------------------------------------------
1 | name: All service principals with Microsoft Graph App Role assignments
2 | guid: 74440269-eb41-476b-8dec-b4095569b029
3 | prebuilt: true
4 | platforms: Azure
5 | category: Microsoft Graph
6 | description:
7 | query: |-
8 | 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)
9 | RETURN p
10 | LIMIT 1000
11 | revision: 1
12 | resources:
13 | acknowledgements:
14 |
15 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on published enrollment agent certificate templates.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on published enrollment agent certificate templates
2 | guid: 8483bf5b-89f1-4723-abb2-c48295f6393e
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)
9 | WHERE '1.3.6.1.4.1.311.20.2.1' IN ct.effectiveekus
10 | OR '2.5.29.37.0' IN ct.effectiveekus
11 | OR SIZE(ct.effectiveekus) = 0
12 | RETURN p
13 | LIMIT 1000
14 | revision: 1
15 | resources:
16 | acknowledgements:
17 |
18 |
--------------------------------------------------------------------------------
/queries/Shortest paths to Domain Admins from Kerberoastable users.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths to Domain Admins from Kerberoastable users
2 | guid: bd163361-1e05-47c7-908b-962aef251535
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description:
7 | query: |-
8 | MATCH p=shortestPath((s:User)-[:AD_ATTACK_PATHS*1..]->(t:Group))
9 | WHERE s.hasspn=true
10 | AND s.enabled = true
11 | AND NOT s.objectid ENDS WITH '-502'
12 | AND NOT COALESCE(s.gmsa, false) = true
13 | AND NOT COALESCE(s.msa, false) = true
14 | AND t.objectid ENDS WITH '-512'
15 | RETURN p
16 | LIMIT 1000
17 | revision: 2
18 | resources:
19 | acknowledgements:
20 |
21 |
--------------------------------------------------------------------------------
/queries/Devices with unsupported operating systems.yml:
--------------------------------------------------------------------------------
1 | name: Devices with unsupported operating systems
2 | guid: e3f2b53a-7ce6-4e52-9c74-68b69338288b
3 | prebuilt: true
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:AZDevice)
9 | WHERE n.operatingsystem CONTAINS 'WINDOWS'
10 | 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).?.*'
11 | RETURN n
12 | LIMIT 100
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Kerberos-enabled service account member of built-in Admins groups.yml:
--------------------------------------------------------------------------------
1 | name: Kerberos-enabled service account member of built-in Admins groups
2 | guid: 42a856fc-257a-4142-9592-ca95fd49e579
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Base)-[:MemberOf*1..]->(g:Group)
9 | WHERE (
10 | g.objectid ENDS WITH '-512' // Domain Admins
11 | OR g.objectid ENDS WITH '-519' // Enterprise Admins
12 | OR g.objectid ENDS WITH '-518' // Schema Admins
13 | )
14 | AND n.hasspn = true
15 | RETURN p
16 | revision: 1
17 | resources:
18 | acknowledgements: Martin Sohn Christensen, @martinsohndk
19 |
20 |
--------------------------------------------------------------------------------
/queries/Tier Zero users not member of Protected Users.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero users not member of Protected Users
2 | guid: 543eb01d-9fa3-4b8f-a936-b46bbfdaa2ae
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (m:User)
9 | WHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')
10 | OPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)
11 | WHERE g.objectid ENDS WITH '-525'
12 | WITH m, COLLECT(n) AS matchingNs
13 | WHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)
14 | RETURN m
15 | revision: 1
16 | resources:
17 | acknowledgements: Martin Sohn Christensen, @martinsohndk
18 |
19 |
--------------------------------------------------------------------------------
/queries/Tier Zero users with passwords not rotated in over 1 year.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero users with passwords not rotated in over 1 year
2 | guid: 5e0d69b1-37d1-43ae-ac5d-f297f312fab5
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | WITH 365 as days_since_change
9 | MATCH (u:User)
10 | WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')
11 | AND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))
12 | AND NOT u.pwdlastset IN [-1.0, 0.0]
13 | RETURN u
14 | LIMIT 100
15 | revision: 1
16 | resources:
17 | acknowledgements: Martin Sohn Christensen, @martinsohndk
18 |
19 |
--------------------------------------------------------------------------------
/queries/Circular AZ group memberships.yml:
--------------------------------------------------------------------------------
1 | name: Circular AZ group memberships
2 | guid: b005669c-d8af-47ae-a0f1-4f36cd5334ab
3 | prebuilt: false
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description: Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.
7 | query: |-
8 | MATCH p=(x:AZGroup)-[:AZMemberOf*2..]->(y:AZGroup)
9 | WHERE x.objectid=y.objectid
10 | RETURN p
11 | LIMIT 100
12 | revision: 1
13 | resources: https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Compromising permissions on ADCS nodes (ESC5).yml:
--------------------------------------------------------------------------------
1 | name: Compromising permissions on ADCS nodes (ESC5)
2 | guid: 396c7b67-fb5d-4c04-bb13-8007f0dfc9b1
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (n:Base)-[:Owns|WriteOwner|WriteDacl|GenericAll|GenericWrite]->(m:Base)
9 | WHERE m.distinguishedname CONTAINS "PUBLIC KEY SERVICES"
10 | AND NOT n.objectid ENDS WITH "-512" // Domain Admins
11 | AND NOT n.objectid ENDS WITH "-519" // Enterprise Admins
12 | AND NOT n.objectid ENDS WITH "-544" // Administrators
13 | RETURN p
14 | LIMIT 1000
15 | revision: 1
16 | resources:
17 | acknowledgements:
18 |
--------------------------------------------------------------------------------
/queries/Kerberoastable members of Tier Zero High Value groups.yml:
--------------------------------------------------------------------------------
1 | name: Kerberoastable members of Tier Zero / High Value groups
2 | guid: e6da7800-ae06-41cb-80a6-d5421ab2143a
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Kerberos Interaction
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0') AND u.hasspn=true
10 | AND u.enabled = true
11 | AND NOT u.objectid ENDS WITH '-502'
12 | AND NOT COALESCE(u.gmsa, false) = true
13 | AND NOT COALESCE(u.msa, false) = true
14 | RETURN u
15 | LIMIT 100
16 | revision: 2
17 | resources: https://attack.mitre.org/techniques/T1558/003/
18 | acknowledgements:
19 |
20 |
--------------------------------------------------------------------------------
/queries/Circular AD group memberships.yml:
--------------------------------------------------------------------------------
1 | name: Circular AD group memberships
2 | guid: fcaa5ffc-3d22-481f-a2a2-18a4eec30058
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Detects circular group membership chains where groups are members of themselves through one or more intermediate groups. This causes an administrative complexity.
7 | query: |-
8 | MATCH p=(x:Group)-[:MemberOf*2..]->(y:Group)
9 | WHERE x.objectid=y.objectid
10 | RETURN p
11 | LIMIT 100
12 | revision: 1
13 | resources: https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on published ESC1 certificate templates.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on published ESC1 certificate templates
2 | guid: 2af855bc-f48f-4b22-9839-627d8231e425
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)
9 | WHERE ct.enrolleesuppliessubject = True
10 | AND ct.authenticationenabled = True
11 | AND ct.requiresmanagerapproval = False
12 | AND (ct.authorizedsignatures = 0 OR ct.schemaversion = 1)
13 | RETURN p
14 | LIMIT 1000
15 | revision: 1
16 | resources:
17 | acknowledgements:
18 |
19 |
--------------------------------------------------------------------------------
/queries/Domains where any user can join a computer to the domain.yml:
--------------------------------------------------------------------------------
1 | name: Domains where any user can join a computer to the domain
2 | guid: 421921fa-bc0f-4659-9680-b7481adcb132
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (d:Domain)
9 | WHERE d.machineaccountquota > 0
10 | RETURN d
11 | revision: 2
12 | resources:
13 | - https://learn.microsoft.com/en-us/troubleshoot/windows-server/active-directory/default-workstation-numbers-join-domain
14 | - https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/security-policy-settings/add-workstations-to-domain
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Non-default members in Pre-Windows 2000 Compatible Access.yml:
--------------------------------------------------------------------------------
1 | name: Non-default members in Pre-Windows 2000 Compatible Access
2 | guid: 091995b9-7254-473a-996f-6b8368d20431
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[:MemberOf]->(m:Group)
9 | WHERE NOT n.objectid ENDS WITH "S-1-5-11" // Authenticated Users
10 | AND NOT (n.objectid ENDS WITH "S-1-5-7" // Anonymous
11 | AND NOT n.objectid ENDS WITH "S-1-1-0") // Everyone
12 | AND m.objectid ENDS WITH "S-1-5-32-554" // Pre-Windows 2000 Compatible Access
13 | RETURN p
14 | revision: 1
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Computer owners who can obtain LAPS passwords.yml:
--------------------------------------------------------------------------------
1 | name: Computer owners who can obtain LAPS passwords
2 | guid: 92aa81d6-b08e-4abb-ae39-ecbe5735a74c
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | 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.
7 | query: |-
8 | MATCH p = (c:Computer)<-[:GenericAll|Owns|WriteDacl|WriteOwner|AllExtendedRights]-(n:User)
9 | WHERE c.haslaps = true AND c.ownersid = n.objectid
10 | RETURN p
11 | revision: 1
12 | resources:
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Tier Zero computers with passwords older than the default maximum password age.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero computers with passwords older than the default maximum password age
2 | guid: b6d6d0bf-130e-4719-996b-adc29bba36e9
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (n:Computer)
9 | WHERE n.enabled = true
10 | AND n.whencreated < (datetime().epochseconds - (60 * 3 * 86400))
11 | AND n.pwdlastset < (datetime().epochseconds - (60 * 3 * 86400))
12 | AND ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
13 | RETURN n
14 | revision: 2
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Accounts related to AAD Entra Connect.yml:
--------------------------------------------------------------------------------
1 | name: Accounts related to AAD Entra Connect
2 | guid: 5993208e-6189-40e6-be03-c23c872d0ca4
3 | prebuilt: false
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Active Directory Hygiene
8 | description: Query to start reconnaissance about AADConnect / Entra Connect related accounts
9 | query: |-
10 | MATCH (u)
11 | WHERE (u:User OR u:AZUser)
12 | AND (u.name =~ '(?i)^MSOL_|.*AADConnect.*|.*ADSyncMSA.*|.*AAD_.*|.*PROVAGENTGMSA.*'
13 | OR u.userprincipalname =~ '(?i)^sync_.*')
14 | RETURN u
15 | revision: 1
16 | resources: https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/concept-adsync-service-account
17 | acknowledgements: Daniel Scheidt, @theluemmel
18 |
--------------------------------------------------------------------------------
/queries/On-Prem Users synced to Entra Users with Azure RM Roles (direct).yml:
--------------------------------------------------------------------------------
1 | name: On-Prem Users synced to Entra Users with Azure RM Roles (direct)
2 | guid: 8569113b-e42e-49b0-a968-53bcf0ccd970
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Principal with SPN keyword.yml:
--------------------------------------------------------------------------------
1 | name: Principal with SPN keyword
2 | guid: 38a9c4c9-3d70-453f-a017-cbfd35ed9917
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Kerberos Interaction
6 | 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.
7 | query: |-
8 | // Replace keyword with a service type or server name (not FQDN)
9 | WITH "KEYWORD" as SPNKeyword
10 | MATCH (n:User)
11 | WHERE ANY(keyword IN n.serviceprincipalnames WHERE toUpper(keyword) CONTAINS toUpper(SPNKeyword))
12 | RETURN n
13 | revision: 1
14 | resources: https://adsecurity.org/?page_id=183
15 | acknowledgements: Ryan, @haus3c
16 |
17 |
--------------------------------------------------------------------------------
/queries/Tier Zero accounts that can be delegated.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero accounts that can be delegated
2 | guid: 4316eaf1-6af0-4879-8f55-ac2633a711c3
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Kerberos Interaction
6 | description:
7 | query: |-
8 | MATCH (m:Base)
9 | WHERE ((m:Tag_Tier_Zero) OR COALESCE(m.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND m.enabled = true
11 | AND m.sensitive = false
12 | OPTIONAL MATCH (g:Group)<-[:MemberOf*1..]-(n:Base)
13 | WHERE g.objectid ENDS WITH '-525'
14 | WITH m, COLLECT(n) AS matchingNs
15 | WHERE NONE(n IN matchingNs WHERE n.objectid = m.objectid)
16 | RETURN m
17 | revision: 1
18 | resources:
19 | acknowledgements: Martin Sohn Christensen, @martinsohndk
20 |
21 |
--------------------------------------------------------------------------------
/queries/All paths crossing a specific trust.yml:
--------------------------------------------------------------------------------
1 | name: All paths crossing a specific trust
2 | guid: 251fc893-7a6b-4a0a-8650-9d5408d38c3c
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: All paths crossing a specific trust from a trusted to a trusting domain.
7 | query: |-
8 | // Replace the TRUSTED domain SID
9 | // Replace the TRUSTING domain SID
10 | MATCH p=(Trusted:Base)-[:AD_ATTACK_PATHS]->(Trusting:Base)
11 | WHERE Trusted.domainsid = 'S-1-5-21-1111111111-1111111111-1111111111'
12 | AND Trusting.domainsid = 'S-1-5-21-2222222222-2222222222-2222222222'
13 | RETURN p
14 | LIMIT 1000
15 | revision: 2
16 | resources:
17 | acknowledgements: Martin Sohn Christensen, @martinsohndk
18 |
19 |
--------------------------------------------------------------------------------
/queries/Shortest paths from Owned objects to Tier Zero.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths from Owned objects to Tier Zero
2 | guid: dfaa8e8f-2c79-4e92-a291-b1347f6e83b0
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Shortest Paths
6 | description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE
7 | query: |-
8 | // MANY TO MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE
9 | MATCH p=shortestPath((s:Tag_Owned)-[:AD_ATTACK_PATHS*1..]->(t:Base))
10 | WHERE s<>t
11 | AND ((t:Tag_Tier_Zero) OR COALESCE(t.system_tags, '') CONTAINS 'admin_tier_0')
12 | RETURN p
13 | LIMIT 1000
14 | revision: 4
15 | resources:
16 | acknowledgements:
17 |
18 |
--------------------------------------------------------------------------------
/queries/Kerberoastable users with most admin privileges.yml:
--------------------------------------------------------------------------------
1 | name: Kerberoastable users with most admin privileges
2 | guid: 9907b208-494c-4ba6-846d-485e6de14e17
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Kerberos Interaction
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE u.hasspn = true
10 | AND u.enabled = true
11 | AND NOT u.objectid ENDS WITH '-502'
12 | AND NOT COALESCE(u.gmsa, false) = true
13 | AND NOT COALESCE(u.msa, false) = true
14 | MATCH (u)-[:MemberOf|AdminTo*1..]->(c:Computer)
15 | WITH DISTINCT u, COUNT(c) AS adminCount
16 | RETURN u
17 | ORDER BY adminCount DESC
18 | LIMIT 100
19 | revision: 1
20 | resources: https://attack.mitre.org/techniques/T1558/003/
21 | acknowledgements:
22 |
23 |
--------------------------------------------------------------------------------
/queries/Shortest paths to privileged roles.yml:
--------------------------------------------------------------------------------
1 | name: Shortest paths to privileged roles
2 | guid: 3dc73dd8-4873-4aeb-a88f-56a58c77f512
3 | prebuilt: true
4 | platforms: Azure
5 | category: Shortest Paths
6 | description: WARNING! MANY-TO-MANY SHORTEST PATH QUERIES USE EXCESSIVE SYSTEM RESOURCES AND TYPICALLY WILL NOT COMPLETE
7 | query: |-
8 | MATCH p=shortestPath((s:AZBase)-[:AZ_ATTACK_PATHS*1..]->(t:AZRole))
9 | WHERE t.name =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|Privileged Authentication Administrator|Privileged Role Administrator' AND s<>t
10 | RETURN p
11 | LIMIT 1000
12 | revision: 3
13 | resources:
14 | acknowledgements:
15 |
16 |
--------------------------------------------------------------------------------
/queries/Non-Tier Zero account with excessive control.yml:
--------------------------------------------------------------------------------
1 | name: Non-Tier Zero object with excessive control
2 | guid: 944cecfe-519b-4318-b226-e8520161b454
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description: Returns non-Tier Zero principals with >= 1000 direct rights to other principals. This does not include rights from group memberships.
7 | query: |-
8 | MATCH (n:Base)-[r:AD_ATTACK_PATHS]->(m:Base)
9 | WHERE NOT r:MemberOf
10 | AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | WITH n, COLLECT(DISTINCT(m)) AS endNodes
12 | WHERE SIZE(endNodes) >= 1000
13 | RETURN n
14 | revision: 4
15 | resources:
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Large default group added to computer-local group.yml:
--------------------------------------------------------------------------------
1 | name: Large default group added to computer-local group
2 | guid: dde133d2-b4d2-4de9-a656-905f3bf066f3
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[:MemberOfLocalGroup]->(m:ADLocalGroup)-[:LocalToComputer]->(:Computer)
9 | 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
10 | AND NOT m.objectid =~ ".*-(545|574|554)$" // Users, Certificate Service DCOM Access, Pre-Windows 2000 Compatible Access
11 | RETURN p
12 | revision: 1
13 | resources:
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/On-Prem Users synced to Entra Users with Azure RM Roles (group delegated).yml:
--------------------------------------------------------------------------------
1 | name: On-Prem Users synced to Entra Users with Azure RM Roles (group delegated)
2 | guid: e4f2eada-8a89-4ba9-89eb-abbee4efbc7a
3 | prebuilt: true
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Cross Platform Attack Paths
8 | description:
9 | query: |-
10 | MATCH p = (:User)-[:SyncedToEntraUser]->(:AZUser)-[:AZMemberOf]->(:AZGroup)-[:AZOwner|AZUserAccessAdministrator|AZGetCertificates|AZGetKeys|AZGetSecrets|AZAvereContributor|AZKeyVaultContributor|AZContributor|AZVMAdminLogin|AZVMContributor|AZAKSContributor|AZAutomationContributor|AZLogicAppContributor|AZWebsiteContributor]->(:AZBase)
11 | RETURN p
12 | LIMIT 1000
13 | revision: 1
14 | resources:
15 | acknowledgements:
16 |
17 |
--------------------------------------------------------------------------------
/queries/Accounts with weak password storage encryption.yml:
--------------------------------------------------------------------------------
1 | name: Accounts with weak password storage encryption
2 | guid: 8bd6fcf2-3f3c-414c-857a-4caf28e49def
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Accounts with passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008 release
10 | RETURN n
11 | LIMIT 100
12 | revision: 2
13 | resources: https://techcommunity.microsoft.com/blog/coreinfrastructureandsecurityblog/decrypting-the-selection-of-supported-kerberos-encryption-types/1628797
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/queries/Usage of built-in domain Administrator account.yml:
--------------------------------------------------------------------------------
1 | name: Usage of built-in domain Administrator account
2 | guid: 35b1206f-871b-44aa-a601-c5258060dfcf
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Usage of Active Directory's built-in Administrator account is a sign that the account is not only used for break-glass purposes.
7 | query: |-
8 | MATCH (n:User)
9 | WHERE n.objectid ENDS WITH "-500"
10 | AND (
11 | n.lastlogontimestamp > (datetime().epochseconds - (60 * 86400)) OR
12 | n.lastlogon > (datetime().epochseconds - (60 * 86400))
13 | )
14 | AND NOT n.whencreated > (datetime().epochseconds - (60 * 86400))
15 | RETURN n
16 | revision: 1
17 | resources:
18 | acknowledgements: Martin Sohn Christensen, @martinsohndk
19 |
20 |
--------------------------------------------------------------------------------
/queries/Object name conflict.yml:
--------------------------------------------------------------------------------
1 | name: Object name conflict
2 | guid: c561c4f8-ea45-453f-85a2-3fc2e20e7f8c
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | 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'
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.distinguishedname CONTAINS 'CNF:'
10 | RETURN n
11 | revision: 1
12 | resources: https://learn.microsoft.com/en-us/archive/technet-wiki/15435.active-directory-duplicate-object-name-resolution
13 | acknowledgements: Martin Sohn Christensen, @martinsohndk
14 |
15 |
--------------------------------------------------------------------------------
/queries/Overprivileged Microsoft Entra Connect accounts.yml:
--------------------------------------------------------------------------------
1 | name: Overprivileged Microsoft Entra Connect accounts
2 | guid: 9e6e75b4-9ecc-45d4-a39b-b6427b813f0a
3 | prebuilt: false
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Active Directory Hygiene
8 | description: Legacy MSOL accounts were by default deployed with Domain Admins or Enterprise Admins membership.
9 | query: |-
10 | MATCH p=(n:User)-[:MemberOf*1..]->(g:Group)
11 | WHERE n.name STARTS WITH "MSOL_"
12 | AND (g.objectid ENDS WITH "-512" // Domain Admins
13 | OR g.objectid ENDS WITH "-519") // Entterprise Admins
14 | RETURN p
15 | revision: 1
16 | resources: https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/reference-connect-accounts-permissions
17 | acknowledgements: Martin Sohn Christensen, @martinsohndk
18 |
19 |
--------------------------------------------------------------------------------
/queries/Large default groups with outbound control of OUs.yml:
--------------------------------------------------------------------------------
1 | name: Large default groups with outbound control of OUs
2 | guid: 310b3626-f8e6-4ab0-832c-72df6048597f
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | MATCH p=(n:Group)-[]->(:OU)
9 | WHERE n.objectid ENDS WITH "-513" // DOMAIN USERS
10 | OR n.objectid ENDS WITH "-515" // DOMAIN COMPUTERS
11 | OR n.objectid ENDS WITH "-S-1-5-11" // AUTHENTICATED USERS
12 | OR n.objectid ENDS WITH "-S-1-1-0" // EVERYONE
13 | OR n.objectid ENDS WITH "S-1-5-32-545" // USERS
14 | OR n.objectid ENDS WITH "S-1-5-32-546" // GUESTS
15 | OR n.objectid ENDS WITH "S-1-5-7" // ANONYMOUS
16 | RETURN p
17 | revision: 1
18 | resources:
19 | acknowledgements: Martin Sohn Christensen, @martinsohndk
20 |
21 |
--------------------------------------------------------------------------------
/queries/Domain controllers with UPN certificate mapping enabled.yml:
--------------------------------------------------------------------------------
1 | name: Domain controllers with UPN certificate mapping enabled
2 | guid: 799ea3ce-572b-4594-98c4-041aa2ae6176
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (s:Computer)-[:DCFor]->(:Domain)
9 | WHERE s.certificatemappingmethodsraw IN [4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 28, 29, 30, 31]
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources:
14 | - https://support.microsoft.com/en-us/topic/kb5014754-certificate-based-authentication-changes-on-windows-domain-controllers-ad2c23b0-15d8-4340-a468-4d4f3b188f16
15 | - https://specterops.io/blog/2024/02/28/adcs-esc14-abuse-technique/
16 | acknowledgements: Jonas Bülow Knudsen, @Jonas_B_K
17 |
18 |
--------------------------------------------------------------------------------
/queries/Users with non-default Primary Group membership.yml:
--------------------------------------------------------------------------------
1 | name: Users with non-default Primary Group membership
2 | guid: 93890f88-df2c-4167-a945-a53961d08d00
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:User)-[r:MemberOf]->(g:Group)
9 | WHERE NOT g.objectid ENDS WITH "-513" // Domain Users
10 | AND r.isprimarygroup = true
11 | AND NOT n.objectid ENDS WITH "-501" // Guests account, as it has primaryGroup to Guests
12 | AND (n.gmsa IS NULL OR n.gmsa = false) // Not gMSA, as it has primaryGroup to Domain Computers
13 | AND (n.msa IS NULL OR n.msa = false) // Not MSA, as it has primaryGroup to Domain Computers
14 | RETURN p
15 | revision: 1
16 | resources:
17 | acknowledgements: Martin Sohn Christensen, @martinsohndk
18 |
19 |
--------------------------------------------------------------------------------
/queries/Non-Tier Zero principals with BadSuccessor rights (no prerequisites check).yml:
--------------------------------------------------------------------------------
1 | name: Non-Tier Zero principals with BadSuccessor rights (no prerequisites check)
2 | guid: 2b9fb71e-73ad-4061-a2df-40c7132b044d
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description: Finds non-Tier Zero principals with BadSuccessor rights with no prerequisites check (DC2025 & KDC key).
7 | query: |-
8 | // Find OU control
9 | MATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)
10 | // Exclude Tier Zero
11 | WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
12 | RETURN p LIMIT 1000
13 | revision: 1
14 | resources: https://bsky.app/profile/specterops.io/post/3lpua65qeu22l
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/All incoming and local paths for a specific computer.yml:
--------------------------------------------------------------------------------
1 | name: All incoming and local paths for a specific computer
2 | guid: 1f67e538-19d4-4020-89c8-5b39b31571bd
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: All incoming and local paths for a specific computer; incoming from domain objects and paths local inside the computer.
7 | query: |-
8 | // Replace 'HOSTNAME' with the computer's shortname eg. 'SRV01', not FQDN
9 | MATCH p=(n:Base)-[:RemoteInteractiveLogonRight|AdminTo|CanRDP|LocalToComputer|MemberOfLocalGroup]-(m:Base)
10 | WHERE m.name CONTAINS 'HOSTNAME'
11 | AND m.name CONTAINS '.' // Only see computer-related objects (eg. not AD Groups)
12 | RETURN p
13 | revision: 2
14 | resources:
15 | acknowledgements: Martin Sohn Christensen, @martinsohndk
16 |
17 |
--------------------------------------------------------------------------------
/queries/Tier Zero High Value enabled users not requiring smart card authentication.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero / High Value enabled users not requiring smart card authentication
2 | guid: 867f9f17-c149-4c4b-ad84-9a807622ff8c
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH (u:User)
9 | WHERE ((u:Tag_Tier_Zero) OR COALESCE(u.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND u.enabled = true
11 | AND u.smartcardrequired = false
12 | AND NOT u.name STARTS WITH 'MSOL_' // Removes false positive, Entra sync
13 | AND NOT u.name STARTS WITH 'PROVAGENTGMSA' // Removes false positive, Entra sync
14 | AND NOT u.name STARTS WITH 'ADSYNCMSA_' // Removes false positive, Entra sync
15 | RETURN u
16 | revision: 1
17 | resources:
18 | acknowledgements:
19 |
20 |
--------------------------------------------------------------------------------
/queries/Entra ID SSO accounts not rolling Kerberos decryption key.yml:
--------------------------------------------------------------------------------
1 | name: Entra ID SSO accounts not rolling Kerberos decryption key
2 | guid: 1867abf8-08e3-4ea8-8f65-8366079d35c4
3 | prebuilt: false
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Configuration Weakness
8 | description: Microsoft highly recommends that you roll over the Entra ID SSO Kerberos decryption key at least every 30 days.
9 | query: |-
10 | MATCH (n:Computer)
11 | WHERE n.name STARTS WITH "AZUREADSSOACC."
12 | AND n.pwdlastset < (datetime().epochseconds - (30 * 86400))
13 | RETURN n
14 | revision: 1
15 | 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-
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Foreign Service Principals With an EntraID Admin Role.yml:
--------------------------------------------------------------------------------
1 | name: Foreign Service Principals With an EntraID Admin Role
2 | guid: b6235820-4e0d-4dfa-af5b-729b5644feb5
3 | prebuilt: false
4 | platforms: Azure
5 | category: Dangerous Privileges
6 | description: Entra ID admin roles grant significant control over a tenant environment, even if the role is not a default Tier Zero / High Value role
7 | query: |-
8 | MATCH p = (sp:AZServicePrincipal)-[:AZHasRole]->(r:AZRole)
9 | WHERE toUpper(sp.appownerorganizationid) <> toUpper(sp.tenantid)
10 | // Ensure AZServicePrincipal has a valid appownerorganizationid
11 | AND sp.appownerorganizationid CONTAINS "-"
12 | RETURN p
13 | LIMIT 1000
14 | revision: 1
15 | resources: https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65
16 | acknowledgements: Stephen Hinck
17 |
18 |
--------------------------------------------------------------------------------
/queries/Foreign Service Principals With Group Memberships.yml:
--------------------------------------------------------------------------------
1 | name: Foreign Service Principals With Group Memberships
2 | guid: 327ef6a5-bfa8-4c92-b35a-d3df85264a24
3 | prebuilt: false
4 | platforms: Azure
5 | category: Azure Hygiene
6 | description: Review each to validate whether their presence is expected and whether the assigned group memberships are appropriate for the foreign service principal.
7 | query: |-
8 | MATCH p = (sp:AZServicePrincipal)-[:AZMemberOf]->(g:AZGroup)
9 | WHERE toUpper(sp.appownerorganizationid) <> toUpper(g.tenantid)
10 | // Ensure AZServicePrincipal has a valid appownerorganizationid
11 | AND sp.appownerorganizationid CONTAINS "-"
12 | RETURN p
13 | LIMIT 1000
14 | revision: 1
15 | resources: https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65
16 | acknowledgements: Stephen Hinck
17 |
18 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on published ESC2 certificate templates.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on published ESC2 certificate templates
2 | guid: ebc77984-1ceb-4ed2-a395-ce1067847941
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p = (:Base)-[:Enroll|GenericAll|AllExtendedRights]->(c:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)
9 | WHERE c.requiresmanagerapproval = false
10 | AND (c.effectiveekus = [''] OR '2.5.29.37.0' IN c.effectiveekus OR c.effectiveekus IS NULL)
11 | AND (c.authorizedsignatures = 0 OR c.schemaversion = 1)
12 | RETURN p
13 | LIMIT 1000
14 | revision: 2
15 | resources:
16 | - https://posts.specterops.io/certified-pre-owned-d95910965cd2
17 | - https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547
18 | acknowledgements:
19 |
20 |
--------------------------------------------------------------------------------
/queries/Enabled users inactive for 180 days.yml:
--------------------------------------------------------------------------------
1 | name: Enabled users inactive for 180 days
2 | guid: 71972f3c-b32d-4023-a841-5cc8cc1c1867
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | WITH 180 as inactive_days
9 | MATCH (n:User)
10 | WHERE n.enabled = true
11 | AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value
12 | AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value
13 | AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals
14 | AND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator
15 | RETURN n
16 | LIMIT 1000
17 | revision: 1
18 | resources:
19 | acknowledgements: Martin Sohn Christensen, @martinsohndk
20 |
21 |
--------------------------------------------------------------------------------
/queries/All Operators.yml:
--------------------------------------------------------------------------------
1 | name: All Operators
2 | guid: 3dfd0843-1ff9-4c21-aa67-feae08d109de
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description:
7 | query: |-
8 | MATCH p=(:Base)-[:MemberOf]->(n:Group)
9 | WHERE (
10 | n.objectid ENDS WITH 'S-1-5-32-551' OR // Backup Operators
11 | n.objectid ENDS WITH 'S-1-5-32-556' OR // Network Configuration Operators
12 | n.objectid ENDS WITH 'S-1-5-32-549' OR // Server Operators
13 | n.objectid ENDS WITH 'S-1-5-32-579' OR // Access Control Assistance Operators
14 | n.objectid ENDS WITH 'S-1-5-32-548' OR // Account Operators
15 | n.objectid ENDS WITH 'S-1-5-32-569' OR // Cryptographic Operators
16 | n.objectid ENDS WITH 'S-1-5-32-550' // Print Operators
17 | )
18 | RETURN p
19 | revision: 1
20 | resources:
21 | acknowledgements: Martin Sohn Christensen, @martinsohndk
22 |
23 |
--------------------------------------------------------------------------------
/queries/All privileged Azure Service Principals.yml:
--------------------------------------------------------------------------------
1 | name: All privileged Azure Service Principals
2 | guid: 92f269ee-3727-4ffa-947b-aad492ac0fa2
3 | prebuilt: false
4 | platforms:
5 | - Azure
6 | category: Azure Hygiene
7 | description: Return all privileged Azure Service Principals.
8 | query: |-
9 | MATCH p=(n:AZServicePrincipal)-[:AZHasRole|AZMemberOf*1..2]->(r:AZRole)
10 | WHERE r.displayname =~ '(?i)Global Administrator|User Administrator|Cloud Application Administrator|Authentication Policy Administrator|Exchange Administrator|Helpdesk Administrator|PRIVILEGED AUTHENTICATION ADMINISTRATOR|Domain Name Administrator|Hybrid Identity Administrator|External Identity Provider Administrator|Privileged Role Administrator|Partner Tier2 Support|Application Administrator|Directory Synchronization Accounts'
11 | RETURN p
12 | revision: 1
13 | resources: -
14 | acknowledgements: Daniel Scheidt, @theluemmel
15 |
--------------------------------------------------------------------------------
/queries/Microsoft Entra Connect accounts with passwords not rotated in over 90 days.yml:
--------------------------------------------------------------------------------
1 | name: Microsoft Entra Connect accounts with passwords not rotated in over 90 days
2 | guid: 97fb1310-d15d-4d63-82a2-8788056250f1
3 | prebuilt: false
4 | platforms:
5 | - Active Directory
6 | - Azure
7 | category: Active Directory Hygiene
8 | description: Micosoft recommends to change the password of MSOL accounts every 90 days to prevent attackers from allowing use of the high privileges
9 | query: |-
10 | WITH 90 as days_since_change
11 | MATCH (u:User)
12 | WHERE u.name STARTS WITH "MSOL_"
13 | AND u.pwdlastset < (datetime().epochseconds - (days_since_change * 86400))
14 | AND NOT u.pwdlastset IN [-1.0, 0.0]
15 | RETURN u
16 | revision: 1
17 | resources: https://learn.microsoft.com/en-us/defender-for-identity/rotate-password-microsoft-entra-connect
18 | acknowledgements: Martin Sohn Christensen, @martinsohndk
19 |
20 |
--------------------------------------------------------------------------------
/queries/Computers with non-default Primary Group membership.yml:
--------------------------------------------------------------------------------
1 | name: Computers with non-default Primary Group membership
2 | guid: 5862dc4e-6f6f-4321-9474-d838968495ed
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | MATCH p=(n:Computer)-[r:MemberOf]->(g:Group)
9 | WHERE NOT g.objectid ENDS WITH "-515" // Domain Computers
10 | AND NOT n.isdc = true
11 | AND NOT n.isreadonlydc = true
12 | AND r.isprimarygroup = true
13 | RETURN p
14 | revision: 2
15 | resources:
16 | - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-ada3/e12954a4-6865-4432-94e6-00c310ca87c0
17 | - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/5dbcf875-e802-4357-a6e2-1bdff19ff9b5
18 | - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/73d11ea7-e634-453e-944d-559654cc91c5
19 | acknowledgements: Martin Sohn Christensen, @martinsohndk
20 |
--------------------------------------------------------------------------------
/queries/Enrollment rights on published ESC15 certificate templates.yml:
--------------------------------------------------------------------------------
1 | name: Enrollment rights on published ESC15 certificate templates
2 | guid: 78d59fe1-e1a0-4813-adc9-c3c96ac08b66
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description: Enrollment rights on certificate templates that meet the requirements for the ADCS ESC15 (EKUwu) attack.
7 | query: |-
8 | MATCH p=(:Base)-[:Enroll|AllExtendedRights]->(ct:CertTemplate)-[:PublishedTo]->(:EnterpriseCA)-[:TrustedForNTAuth]->(:NTAuthStore)-[:NTAuthStoreFor]->(:Domain)
9 | WHERE ct.enrolleesuppliessubject = True
10 | AND ct.authenticationenabled = False
11 | AND ct.requiresmanagerapproval = False
12 | AND ct.schemaversion = 1
13 | RETURN p
14 | revision: 1
15 | resources:
16 | - https://x.com/SpecterOps/status/1844800558151901639
17 | - https://msrc.microsoft.com/update-guide/en-US/advisory/CVE-2024-49019
18 | acknowledgements: Jonas Bülow Knudsen, @Jonas_B_K
19 |
20 |
--------------------------------------------------------------------------------
/queries/Enabled computers inactive for 180 days.yml:
--------------------------------------------------------------------------------
1 | name: Enabled computers inactive for 180 days
2 | guid: 0768e810-1e1e-4319-a216-76d9c2058644
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | WITH 180 as inactive_days
9 | MATCH (n:Computer)
10 | WHERE n.enabled = true
11 | AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value
12 | AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value
13 | AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals
14 | AND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT
15 | AND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO
16 | RETURN n
17 | LIMIT 1000
18 | revision: 1
19 | resources:
20 | acknowledgements: Martin Sohn Christensen, @martinsohndk
21 |
22 |
--------------------------------------------------------------------------------
/queries/Kerberos-enabled service accounts without AES encryption support.yml:
--------------------------------------------------------------------------------
1 | name: Kerberos-enabled service accounts without AES encryption support
2 | guid: cb8cf96e-21c9-422b-9439-390a13446ca6
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Accounts without Kerberos AES encryption support, or passwords set before the existence of Windows Server 2008 Domain Controller which therefore lack AES encryption keys.
7 | query: |-
8 | MATCH (n:Base)
9 | WHERE n.hasspn = true
10 | AND ((
11 | n.supportedencryptiontypes <> ['Not defined']
12 | OR n.supportedencryptiontypes <> []
13 | OR NONE(type IN n.supportedencryptiontypes WHERE type CONTAINS 'AES128' OR type CONTAINS 'AES256')
14 | )
15 | OR (n.pwdlastset < 1204070400 // Password Last Set before Windows Server 2008
16 | AND NOT n.pwdlastset IN [-1.0, 0.0]
17 | ))
18 | RETURN n
19 | LIMIT 100
20 | revision: 2
21 | resources:
22 | acknowledgements: Martin Sohn Christensen, @martinsohndk
23 |
24 |
--------------------------------------------------------------------------------
/queries/All GPOs applied to a specific computer.yml:
--------------------------------------------------------------------------------
1 | name: All GPOs applied to a specific Computer
2 | guid: 1d75a21e-0d34-40c5-9360-281b60737d87
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: View all GPOs that are applied to any specific computer. This query identifies GPOs that are applied at both the Domain Level and the OU level, saving time in large Active Directory environments where GPO inheritance is complex. Replace "COMPUTER_NAME" with the target computer name or a substring. Note this does not take OU 'Block inheritance' and GPO 'No Override' into account.
7 | query: |-
8 | // Replace "HOSTNAME/FQDN" with the computer's
9 | MATCH p=(c:Computer)<-[:Contains*..]-(:Base)<-[:GPLink]-(:GPO)
10 | WHERE toLower(c.name) CONTAINS toLower("HOSTNAME/FQDN")
11 | RETURN p
12 | revision: 1
13 | resources:
14 | - https://learn.microsoft.com/en-us/previous-versions/windows/desktop/Policy/overriding-and-blocking-group-policy
15 | acknowledgements: Adnan Ullah Khan, @auk0x01
16 |
--------------------------------------------------------------------------------
/queries/Collection health of DC Registry Data.yml:
--------------------------------------------------------------------------------
1 | name: Collection health of DC Registry Data
2 | guid: 3f0fa2f3-fbdf-42c0-9e7d-97e689009161
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured DC to potentially a full forest compromise by any principal. DCs returned by this query have not been collected.
7 | query: |-
8 | MATCH p=(:Domain)<-[:DCFor]-(c:Computer)
9 | WHERE c.strongcertificatebindingenforcementraw IS NULL
10 | // Exclude inactive DCs
11 | AND c.enabled = true
12 | AND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))
13 | RETURN p
14 | revision: 1
15 | resources: https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#dc-registry
16 | acknowledgements: Martin Sohn Christensen, @martinsohndk
17 |
18 |
--------------------------------------------------------------------------------
/queries/Foreign Service Principals With any Abusable MS Graph App Role Assignment.yml:
--------------------------------------------------------------------------------
1 | name: Foreign Service Principals With any Abusable MS Graph App Role Assignment
2 | guid: d7a180c8-5624-4fc1-a407-deeb2ad3054c
3 | prebuilt: false
4 | platforms: Azure
5 | category: Dangerous Privileges
6 | description: MS Graph app role assignments provide significant power within an Entra ID tenant, similar to an Admin role.
7 | query: |-
8 | MATCH p = (sp1:AZServicePrincipal)-[r:AZMGGroupMember_ReadWrite_All|AZMGServicePrincipalEndpoint_ReadWrite_All|AZMGAppRoleAssignment_ReadWrite_All|AZMGGroup_ReadWrite_All|AZMGDirectory_ReadWrite_All|AZMGRoleManagement_ReadWrite_Directory]->(sp2:AZServicePrincipal)
9 | WHERE toUpper(sp1.appownerorganizationid) <> toUpper(sp1.tenantid)
10 | // Ensure AZServicePrincipal has a valid appownerorganizationid
11 | AND sp1.appownerorganizationid CONTAINS "-"
12 | RETURN p
13 | LIMIT 1000
14 | revision: 1
15 | resources: https://posts.specterops.io/microsoft-breach-how-can-i-see-this-in-bloodhound-33c92dca4c65
16 | acknowledgements: Stephen Hinck
17 |
18 |
--------------------------------------------------------------------------------
/queries/Tier Zero accounts not members of Denied RODC Password Replication Group.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero accounts not members of Denied RODC Password Replication Group
2 | guid: e9613406-e346-410b-a033-690a6cf0c708
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | // Get all Tier Zero accounts that are members of Denied RODC Password Replication Group
9 | MATCH (n:Base)-[:MemberOf*1..]->(m:Group)
10 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | AND (n:User OR n:Computer)
12 | AND m.objectid ENDS WITH '-519'
13 | WITH COLLECT(n.objectid) AS MembersOfDeniedGroup
14 |
15 | // Get all Tier Zero accounts
16 | MATCH (x:Base)
17 | WHERE ((x:Tag_Tier_Zero) OR COALESCE(x.system_tags, '') CONTAINS 'admin_tier_0')
18 | AND (x:User OR x:Computer)
19 |
20 | // Filter the members of Denied RODC Password Replication Group
21 | AND NOT x.objectid IN MembersOfDeniedGroup
22 | RETURN x
23 | revision: 2
24 | resources:
25 | acknowledgements: Martin Sohn Christensen, @martinsohndk
26 |
27 |
--------------------------------------------------------------------------------
/queries/All ADCS ESC privilege escalation edges.yml:
--------------------------------------------------------------------------------
1 | name: All ADCS ESC privilege escalation edges
2 | guid: 49db8edc-8421-438f-b97b-23c042959bef
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Certificate Services
6 | description:
7 | query: |-
8 | MATCH p=(:Base)-[:ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13|GoldenCert|CoerceAndRelayNTLMToADCS]->(:Base)
9 | RETURN p
10 | revision: 1
11 | resources:
12 | - https://posts.specterops.io/certified-pre-owned-d95910965cd2
13 | - https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-1-799f3d3b03cf
14 | - https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-2-ac7f925d1547
15 | - https://posts.specterops.io/adcs-attack-paths-in-bloodhound-part-3-33efb00856ac
16 | - https://posts.specterops.io/adcs-esc13-abuse-technique-fda4272fbd53
17 | - https://specterops.io/blog/2025/04/08/the-renaissance-of-ntlm-relay-attacks-everything-you-need-to-know/#:~:text=Introducing%20the%20CoerceAndRelayNTLMToADCS%20Edge
18 | acknowledgements: Jonas Bülow Knudsen, @Jonas_B_K
19 |
20 |
--------------------------------------------------------------------------------
/queries/Non-Tier Zero principals with control of AdminSDHolder.yml:
--------------------------------------------------------------------------------
1 | name: Non-Tier Zero principals with control of AdminSDHolder
2 | guid: 4c1e0137-5b7f-48d8-bd09-9db7674bca61
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | 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)
9 | WHERE NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND m.name STARTS WITH "ADMINSDHOLDER@"
11 | RETURN p
12 | revision: 1
13 | 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
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2025 SpecterOps
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/queries/Enabled Tier Zero High Value principals inactive for 60 days.yml:
--------------------------------------------------------------------------------
1 | name: Enabled Tier Zero / High Value principals inactive for 60 days
2 | guid: 72550bcb-3c4f-463d-8973-91a49163dc5a
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | WITH 60 as inactive_days
9 | MATCH (n:Base)
10 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
11 | AND n.enabled = true
12 | AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value
13 | AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value
14 | AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals
15 | AND NOT n.name STARTS WITH 'AZUREADKERBEROS.' // Removes false positive, Azure KRBTGT
16 | AND NOT n.objectid ENDS WITH '-500' // Removes false positive, built-in Administrator
17 | AND NOT n.name STARTS WITH 'AZUREADSSOACC.' // Removes false positive, Entra Seamless SSO
18 | RETURN n
19 | revision: 1
20 | resources:
21 | acknowledgements:
22 |
23 |
--------------------------------------------------------------------------------
/queries/Non-Tier Zero principals with BadSuccessor rights (with prerequisites check).yml:
--------------------------------------------------------------------------------
1 | name: Non-Tier Zero principals with BadSuccessor rights (with prerequisites check)
2 | guid: 74daaebe-6040-4f7a-9c9a-416faf73dcc3
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description: Finds non-Tier Zero principals with BadSuccessor rights after checking prerequisites check (DC2025 & KDC key).
7 | query: |-
8 | // Find 2025 DCs
9 | MATCH (dc:Computer)
10 | WHERE dc.isdc = true AND dc.operatingsystem CONTAINS '2025'
11 | // Find gMSAs
12 | MATCH (m:User)
13 | WHERE m.gmsa = true
14 | // Find OU control
15 | MATCH p = (ou:OU)<-[:WriteDacl|Owns|GenericAll|WriteOwner]-(n:Base)
16 | // Confirm domain has a 2025 DC
17 | WHERE ou.domain = dc.domain
18 | // Confirm domain KDC key
19 | AND ou.domain = m.domain
20 | // Exclude Tier Zero
21 | AND NOT ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
22 | RETURN p LIMIT 1000
23 | revision: 1
24 | resources: https://bsky.app/profile/specterops.io/post/3lpua65qeu22l
25 | acknowledgements: Martin Sohn Christensen, @martinsohndk
26 |
27 |
--------------------------------------------------------------------------------
/queries/Tier Zero users with email.yml:
--------------------------------------------------------------------------------
1 | name: Tier Zero users with email
2 | guid: 9654c0d4-f1e8-4393-a2d1-53a5554a9de8
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: Tier Zero accounts with email access have an increased attack surface.
7 | query: |-
8 | MATCH (n)
9 | WHERE ((n:Tag_Tier_Zero) OR COALESCE(n.system_tags, '') CONTAINS 'admin_tier_0')
10 | AND n.email <> ""
11 | AND n.enabled = true
12 | AND NOT toUpper(n.email) ENDS WITH ".ONMICROSOFT.COM"
13 | AND NOT (
14 | (toUpper(n.email) STARTS WITH "HEALTHMAILBOX"
15 | OR toUpper(n.email) STARTS WITH "MSEXCHDISCOVERYMAILBOX"
16 | OR toUpper(n.email) STARTS WITH "MSEXCHDISCOVERY"
17 | OR toUpper(n.email) STARTS WITH "MSEXCHAPPROVAL"
18 | OR toUpper(n.email) STARTS WITH "FEDERATEDEMAIL"
19 | OR toUpper(n.email) STARTS WITH "SYSTEMMAILBOX"
20 | OR toUpper(n.email) STARTS WITH "MIGRATION.")
21 | AND
22 | (n.name STARTS WITH "SM_"
23 | OR n.name STARTS WITH "HEALTHMAILBOX")
24 | )
25 | RETURN n
26 | revision: 1
27 | resources:
28 | acknowledgements: Martin Sohn Christensen, @martinsohndk
29 |
30 |
--------------------------------------------------------------------------------
/queries/Potential GPO 'Apply' misconfiguration.yml:
--------------------------------------------------------------------------------
1 | name: Potential GPO 'Apply' misconfiguration
2 | guid: f5f2455e-afdc-4708-9a34-98f539ce52d8
3 | prebuilt: true
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description: In Active Directory, GPO's are applied to objects in the Group Policy Management Console by ticking "Allow - Apply group policy", but administrators can mistakenly tick "Allow - Write" or "Allow - Full Control" resulting in a misconfigured GPO that allows a principal to compromise other principals the GPO also applies to. Results are potential risks and must be audited for for correctness.
7 | query: |-
8 | MATCH p=(n:Base)-[:GenericAll|GenericWrite]->(g:GPO)
9 |
10 | // Exclude Enterprise Admins and Domain Admins
11 | WHERE NOT n.objectid =~ "-(519|512)$"
12 |
13 | // Exclude unresolved SIDs
14 | AND NOT (n.distinguishedname IS NULL)
15 |
16 | // Asset description may reveal if it's a delegation group (false-positive) or a filter group (true-positive)
17 | //AND n.description is not null
18 | //AND n.description =~ "(?i)apply"
19 |
20 | RETURN p
21 | LIMIT 1000
22 | revision: 2
23 | resources:
24 | acknowledgements: Martin Sohn Christensen, @martinsohndk
25 |
26 |
--------------------------------------------------------------------------------
/queries/Collection health of CA Registry Data.yml:
--------------------------------------------------------------------------------
1 | name: Collection health of CA Registry Data
2 | guid: c8dd3479-8063-450a-9456-557bc5f39e10
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | description: BloodHound's ADCS analysis requires collecting CA registry data to increase accuracy/enable more edges. Collection by default requires SharpHound has Administrators membership. Requires SharpHound v2.3.5 or above. It only requires one misconfigured CA to potentially a full forest compromise by any principal. CAs returned by this query have not been collected.
7 | query: |-
8 | MATCH p=(eca:EnterpriseCA)<-[:HostsCAService]-(c:Computer)
9 | WHERE (
10 | eca.isuserspecifiessanenabledcollected = false
11 | OR eca.casecuritycollected = false
12 | OR eca.enrollmentagentrestrictionscollected = false
13 | OR eca.roleseparationenabledcollected = false
14 | )
15 | // Exclude inactive CAs
16 | AND c.enabled = true
17 | AND c.lastlogontimestamp > (datetime().epochseconds - (30 * 86400))
18 | RETURN p
19 | revision: 1
20 | resources: https://bloodhound.specterops.io/collect-data/enterprise-collection/permissions#ca-registry
21 | acknowledgements: Martin Sohn Christensen, @martinsohndk
22 |
23 |
--------------------------------------------------------------------------------
/queries/AdminSDHolder protected Accounts and Groups.yml:
--------------------------------------------------------------------------------
1 | name: AdminSDHolder protected Accounts and Groups
2 | guid: 5ee2f40e-a55c-4140-ab8a-91746ba3752b
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Domain Information
6 | 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
7 | query: |-
8 | MATCH (n:Base)-[:MemberOf*0..]->(m:Group)
9 | WHERE (
10 | 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
11 | 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
12 | OR n.objectid =~ ".*-(500|502|516|521)$" // Direct objects
13 | )
14 | RETURN n
15 | revision: 1
16 | resources:
17 | - https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-adts/a0d0b4fa-2895-4c64-b182-ba64ad0f84b8
18 | - https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory
19 | acknowledgements: Martin Sohn Christensen, @martinsohndk
20 |
21 |
--------------------------------------------------------------------------------
/utilities/python/convert.py:
--------------------------------------------------------------------------------
1 | from typing_extensions import Annotated
2 | from pathlib import Path
3 | from schema import CypherQuery
4 | import json
5 | import glob
6 | import typer
7 | import yaml
8 |
9 | app = typer.Typer()
10 |
11 |
12 | @app.command()
13 | def to_json(
14 | input_dir: Annotated[
15 | Path,
16 | typer.Argument(
17 | exists=True,
18 | file_okay=True,
19 | dir_okay=True,
20 | readable=True,
21 | resolve_path=True,
22 | ),
23 | ],
24 | output_file: Annotated[typer.FileTextWrite, typer.Argument()]
25 | ):
26 | cypher_queries = glob.glob(f"{input_dir}/**/*.yml", recursive=True)
27 | typer.echo(f"Converting Queries {len(cypher_queries)} to combined JSON")
28 | all_objects = []
29 | for cypher_query in cypher_queries:
30 | with open(cypher_query, "r") as yaml_file:
31 | yaml_obj = yaml.safe_load(yaml_file)
32 | query = CypherQuery(**yaml_obj)
33 | all_objects.append(query.model_dump())
34 |
35 | output_file.write(json.dumps(all_objects, indent=2))
36 | typer.echo(f"Finished converting Cypher queries to JSON to {output_file.name}")
37 |
38 |
39 | if __name__ == "__main__":
40 | app()
41 |
--------------------------------------------------------------------------------
/queries/Enabled computers inactive for 180 days - MSSQL Failover Cluster.yml:
--------------------------------------------------------------------------------
1 | name: Enabled computers inactive for 180 days - MSSQL Failover Cluster
2 | guid: d263e621-7f1b-4efb-ad25-098fc7d4fb72
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description:
7 | query: |-
8 | WITH 180 as inactive_days
9 | MATCH (n:Computer)
10 | WHERE n.enabled = true
11 | AND n.lastlogontimestamp < (datetime().epochseconds - (inactive_days * 86400)) // Replicated value
12 | AND n.lastlogon < (datetime().epochseconds - (inactive_days * 86400)) // Non-replicated value
13 | AND n.whencreated < (datetime().epochseconds - (inactive_days * 86400)) // Exclude recently created principals
14 | AND ANY(type IN n.serviceprincipalnames WHERE
15 | toLower(type) CONTAINS 'mssqlservercluster' OR
16 | toLower(type) CONTAINS 'mssqlserverclustermgmtapi' OR
17 | toLower(type) CONTAINS 'msclustervirtualserver')
18 | RETURN n
19 | LIMIT 1000
20 | revision: 1
21 | 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
22 | acknowledgements: Martin Sohn Christensen, @martinsohndk
23 |
24 |
--------------------------------------------------------------------------------
/queries/Large default groups with outbound control.yml:
--------------------------------------------------------------------------------
1 | name: Large default groups with outbound control
2 | guid: a334f21a-3d7f-448e-b7ea-1465a3127bce
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Dangerous Privileges
6 | description:
7 | query: |-
8 | 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)
9 | WHERE n.objectid ENDS WITH "-513" // DOMAIN USERS
10 | OR n.objectid ENDS WITH "-515" // DOMAIN COMPUTERS
11 | OR n.objectid ENDS WITH "-S-1-5-11" // AUTHENTICATED USERS
12 | OR n.objectid ENDS WITH "-S-1-1-0" // EVERYONE
13 | OR n.objectid ENDS WITH "S-1-5-32-545" // USERS
14 | OR n.objectid ENDS WITH "S-1-5-32-546" // GUESTS
15 | OR n.objectid ENDS WITH "S-1-5-7" // ANONYMOUS
16 | RETURN p
17 | revision: 1
18 | resources:
19 | acknowledgements: Martin Sohn Christensen, @martinsohndk
20 |
21 |
--------------------------------------------------------------------------------
/queries/Computers with passwords older than the default maximum password age.yml:
--------------------------------------------------------------------------------
1 | name: Computers with passwords older than the default maximum password age
2 | guid: 185c5010-8d4f-4f9b-b24e-831707dddfca
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | 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.
7 | query: |-
8 | WITH 60 as rotation_period
9 | MATCH (n:Computer)
10 | WHERE n.pwdlastset < (datetime().epochseconds - (rotation_period * 86400)) // password not rotated
11 | AND n.enabled = true // enabled computers
12 | AND n.whencreated < (datetime().epochseconds - (rotation_period * 86400)) // exclude recently created computers
13 | AND n.lastlogontimestamp > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Replicated value)
14 | AND n.lastlogon > (datetime().epochseconds - (rotation_period * 86400)) // active computers (Non-replicated value)
15 | RETURN n
16 | revision: 1
17 | resources: https://learn.microsoft.com/en-us/troubleshoot/windows-server/windows-security/disable-machine-account-password
18 | acknowledgements: Martin Sohn Christensen, @martinsohndk
19 |
20 |
--------------------------------------------------------------------------------
/queries/Direct Principal Rights Assignment.yml:
--------------------------------------------------------------------------------
1 | name: Direct Principal Rights Assignment
2 | guid: 1d9c6ae3-38fc-4089-b5ad-fc3be0fa8eec
3 | prebuilt: false
4 | platforms: Active Directory
5 | category: Active Directory Hygiene
6 | description: This query identifies rights assigned directly to users or computers instead of groups. Active Directory best practice requires granting rights to groups, then adding users as group members. This role-based access control (RBAC) approach ensures permissions are easily auditable and manageable. Results include inherited rights, which must be modified at the parent container level.
7 | query: |-
8 | MATCH p=(n:Base)-[r:GenericAll|GenericWrite|WriteOwner|WriteDacl|ForceChangePassword|AllExtendedRights|AddMember|AllowedToDelegate|AllowedToAct|AdminTo|CanPSRemote|CanRDP|ExecuteDCOM|AddSelf|DCSync|ReadLAPSPassword|ReadGMSAPassword|DumpSMSAPassword|AddAllowedToAct|WriteSPN|AddKeyCredentialLink|SyncLAPSPassword|WriteAccountRestrictions|WriteGPLink|ADCSESC1|ADCSESC3|ADCSESC4|ADCSESC6a|ADCSESC6b|ADCSESC9a|ADCSESC9b|ADCSESC10a|ADCSESC10b|ADCSESC13]->(:Base)
9 | WHERE (n:User OR n:Computer)
10 | RETURN p
11 | LIMIT 1000
12 | revision: 1
13 | resources: https://softwareengineering.stackexchange.com/questions/11856/whats-wrong-with-circular-references
14 | acknowledgements: Martin Sohn Christensen, @martinsohndk
15 |
16 |
--------------------------------------------------------------------------------
/tests/schema.py:
--------------------------------------------------------------------------------
1 | from pydantic import BaseModel, field_validator, ConfigDict
2 | from typing import Optional, Union
3 |
4 |
5 | class CypherQuery(BaseModel):
6 | model_config = ConfigDict(extra='forbid')
7 |
8 | name: str
9 | guid: str
10 | prebuilt: bool = False
11 | platforms: Union[str, list[str]]
12 | category: str
13 | description: Optional[str] = None
14 | query: str
15 | revision: int
16 | resources: Optional[Union[str, list[str]]] = None
17 | acknowledgements: Optional[Union[str, list[str]]] = None
18 |
19 | @field_validator('platforms', mode='after')
20 | @classmethod
21 | def platforms_is_list(cls, value: str | list[str]) -> list[str]:
22 | if value is None:
23 | return []
24 | return value if isinstance(value, list) else [value]
25 |
26 | @field_validator('resources', mode='after')
27 | @classmethod
28 | def resources_is_list(cls, value: str | list[str]) -> list[str]:
29 | if value is None:
30 | return []
31 | return value if isinstance(value, list) else [value]
32 |
33 | @field_validator('acknowledgements', mode='after')
34 | @classmethod
35 | def acknowledgementsis_list(cls, value: str | list[str]) -> list[str]:
36 | if value is None:
37 | return []
38 | return value if isinstance(value, list) else [value]
39 |
--------------------------------------------------------------------------------
/tests/templates/githubsummary.md.j2:
--------------------------------------------------------------------------------
1 | # Test Results
2 |
3 | Run on: {{ data.timestamp }}
4 |
5 | | Status | Count |
6 | |--------|-------|
7 | | ✅ Passed | {{ data.summary.passed }} |
8 | | ❌ Failed | {{ data.summary.failed }} |
9 | | ⏭️ Skipped | {{ data.summary.skipped }} |
10 |
11 | {% if data.summary.failed > 0 -%}
12 | ## Failed Tests
13 |
14 | {%- for test in data.tests.failed %}
15 | ### {{ test.name }}
16 | {% if "query" in test %}
17 | ```
18 | {{ test.query }}
19 | ```
20 | {% endif %}
21 | - Path: `{{ test.path }}`
22 | - Reason: {{ test.message }}
23 | - Duration: {{ "%.2f"|format(test.duration) }}s
24 | {% if test.get('error') %}
25 | Error Details
27 | ```
28 | {{ test.error }}
29 | ```
30 | Show all passed tests
40 | {% for test in data.tests.passed %}
41 | ### {{ test.name }}
42 | - Path: `{{ test.path }}`
43 | - Duration: {{ "%.2f"|format(test.duration) }}s
44 | {% endfor %}
45 | Show all skipped tests
53 |
54 | {% for test in data.tests %}
55 | ### {{ test.name }}
56 | - Path: `{{ test.path }}`
57 | {% endfor %}
58 |