Skip to content

AD-ACC-012: pwdLastSet newer than the real password change on tier-0 accounts

medium high   Accounts   MITRE ATT&CK T1098   Reads: LDAP

On krbtgt or a tier-0 account, pwdLastSet is later than the time replication metadata gives for the last write of unicodePwd, so the password is older than it looks.

Also known as: fake-pwdlastset

Why it matters

pwdLastSet is not a record of a password change. Anyone who may write it can set it to 0 and then to -1, and the directory stores the current time, while the password stays the same. A stolen password or a krbtgt key an attacker holds then looks freshly rotated, and every age check that trusts the attribute goes quiet.

A real password change writes unicodePwd. Replication metadata records when that attribute was last written, and that time cannot be moved the same way.

How ad-doctor detects it

For krbtgt, the built-in Administrator, domain controllers and every account in a tier-0 group, ad-doctor asks for msDS-ReplAttributeMetaData in the BASE read of the account it makes anyway. The attribute is constructed, so a subtree search cannot return it, and the cost stays limited to tier 0. An ordinary domain user could read it on every account tried in the lab, krbtgt included.

An enabled account (and krbtgt, which is always disabled) is listed when pwdLastSet is more than 5 seconds later than the last originating change of unicodePwd. That is the rounding tolerance PingCastle's FakePasswordChangeDetector uses. The other direction is not reported: the built-in Administrator of a new forest has a pwdLastSet from before the promotion.

AD-KRB-001, AD-ACC-011 and the password part of AD-KRB-005 use the older of the two times. If the metadata does not come back for an account, the scan names it in a note, and its age checks fall back on pwdLastSet.

Accounts outside tier 0 are not read, so their pwdLastSet is still taken at face value.

Attributes and probes read
  • pwdLastSet
  • msDS-ReplAttributeMetaData (unicodePwd, BASE read of tier-0 accounts)

Severity

High for krbtgt: nobody has a routine reason to touch its pwdLastSet, and its age is what limits forged tickets. Medium for other tier-0 accounts, where an administrator clearing User must change password at next logon has the same effect.

False positives and limits

  • "User must change password at next logon" ticked and cleared. Both steps write pwdLastSet only. On an admin account it is still worth knowing: the password did not change.

Fix

  1. Find out when and where it was written (read-only):

    Get-ADReplicationAttributeMetadata -Object (Get-ADUser adm_bob) -Server dc01 `
        -Properties pwdLastSet, unicodePwd
    

    Event 4738 on that DC, at that time, names the account that made the change.

  2. Really change the password. For krbtgt, rotate it twice, waiting for replication in between.

  3. Treat an unexplained case as an incident: someone hid the age of a tier-0 password.

Verify

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

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

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

References

Specifications

Tools

MITRE ATT&CK

New in the next release.