Skip to content

AD-ACC-011: Privileged accounts with passwords older than a year

medium   Accounts   MITRE ATT&CK T1078.002   Reads: LDAP

Enabled tier-0 accounts, or the built-in Administrator, have not changed their password in over a year.

Why it matters

An administrator's password ends up in more places the longer it lives: cached logons and LSASS memory on the machines they used, scripts and scheduled tasks, old backups of workstations, password managers of former colleagues. Each copy is a way back to Domain Admin, and an attacker who obtained one months ago can use it today if the password never changed.

Rotation also limits Kerberoasting (AD-KRB-003): a ticket cracked offline over weeks is worthless if the password changed in the meantime.

How ad-doctor detects it

From the LDAP snapshot: every enabled user (computers and managed service accounts excluded) that is a transitive member of a tier-0 group or has RID 500 (the built-in Administrator, even if renamed or removed from the groups), whose password was last set more than 365 days before the scan time. That time is the older of pwdLastSet and the last write of unicodePwd in replication metadata, because pwdLastSet can be moved forward (AD-ACC-012). An account with pwdLastSet = 0 (must change at next logon) is judged by the metadata alone, and is not reported when that was not read either.

The tier-0 groups are Domain Admins, Schema Admins, Enterprise Admins, Administrators, Account Operators, Server Operators, Print Operators and Backup Operators, including membership through primaryGroupID.

Each object is a sAMAccountName, for example Administrator.

Attributes and probes read
  • pwdLastSet
  • msDS-ReplAttributeMetaData (unicodePwd)
  • objectSid
  • member (transitive) of the tier-0 groups
  • primaryGroupID

Severity

Always medium. An old password is not a path by itself; it is a tier-0 credential that has had a long time to leak and still works.

False positives and limits

  • Break-glass accounts with a long random password kept in a safe and not used are sometimes rotated only after use. If that is the procedure, record it in an accepted-risk file with an owner and an expiry date.
  • ANSSI's checklist flags privileged passwords unchanged for three years; ad-doctor uses one year, so expect more findings than that rule gives.

Fix

  1. List the accounts and their password age (read-only):

    Get-ADUser -LDAPFilter '(adminCount=1)' -Properties PasswordLastSet, LastLogonDate |
        Where-Object { $_.Enabled -and $_.PasswordLastSet -lt (Get-Date).AddDays(-365) } |
        Select-Object SamAccountName, PasswordLastSet, LastLogonDate
    
  2. Rotate each password to a long, unique value:

    Set-ADAccountPassword Administrator -Reset -NewPassword (Read-Host -AsSecureString 'New password') -WhatIf
    
  3. Disable admin accounts no one uses instead of rotating them.

  4. Make rotation automatic: a fine-grained password policy with a maximum age for tier-0 groups (see AD-ACC-003), or a privileged access management tool that checks passwords out and rotates them after use.

Verify

ad-doctor scan dc01.corp.example --ldaps -u 'CORP\auditor' --only AD-ACC-011

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

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

References

Microsoft and vendors

Specifications

MITRE ATT&CK

Available since 0.1.0.