Skip to content

AD-INV-002: Tier 0 is larger than declared

medium   Invariants   Reads: LDAP

More distinct accounts sit in tier-0 groups than the limit declared in the invariants file allows.

Why it matters

Tier 0 grows quietly: a service account added for an install, an admin who changed roles and kept the rights, a vendor account. Each member can take over the domain, so the attack surface grows with every one of them. A hard limit is easier to keep than an exact list in organizations where admins change often, and still forces a review when the number goes up.

How ad-doctor detects it

Runs only with --invariants FILE that has a limit:

[limits]
tier0_users = 5

ad-doctor counts the distinct accounts that are transitive members of the privileged groups it collects (Domain Admins, Enterprise Admins, Schema Admins, Administrators, and Account, Server, Print and Backup Operators, with primaryGroupID members added back) and reports when the count is above the limit. An account in several groups counts once.

The detail gives the count and the limit (6 distinct accounts in tier-0 groups; the limit is 5.) and the objects list every counted account by sAMAccountName, for example Administrator, adm_bob, svc_sql.

Attributes and probes read
  • member
  • sAMAccountName

Severity

Always medium. Growth of tier 0 is not an attack by itself, but every extra account is another password, session and workstation that leads to the domain.

False positives and limits

  • Computer accounts in tier-0 groups count too. They should not be there (see AD-PRIV-006), but if one is, raise the limit only after review.
  • Members of operator groups (Account, Server, Backup, Print Operators) count. They can reach tier 0 in a few steps, so empty those groups (AD-PRIV-008) rather than raising the limit.

Fix

  1. Review every listed account: who owns it, why it needs tier 0, and when it last logged on.

    foreach ($g in 'Domain Admins', 'Enterprise Admins', 'Schema Admins', 'Administrators') {
        Get-ADGroupMember $g -Recursive | Select-Object @{n = 'Group'; e = { $g }}, SamAccountName
    }
    
  2. Remove the accounts that do not need tier 0 and give them narrower delegated rights instead:

    Remove-ADGroupMember 'Domain Admins' -Members old_admin -WhatIf
    
  3. Move service accounts out of admin groups; a service seldom needs Domain Admins.

  4. If the larger tier 0 is intended, raise tier0_users in a reviewed change to the invariants file; see Invariants.

Verify

ad-doctor scan dc01.corp.example --ldaps -u 'CORP\auditor' --invariants invariants.toml --only AD-INV-002

To accept the risk instead, add an entry to the file passed with --accept (see accepted risks):

[[accept]]
check = "AD-INV-002"
objects = ["..."]        # optional; without it the whole check is accepted
reason = "..."
expires = 2027-03-31

References

Microsoft and vendors

Available since 0.1.0.