Active Directory: Bad Passwords and Account Lockout
Not all logon attempts with a bad password count against the account lockout threshold. Passwords that match one of the two most recent passwords in password history will not increment the badPwdCount. Nor will they update the badPasswordTime attribute of the user. Because the lockoutObservationWindow attribute is the amount of time since the badPasswordTime was last updated, this affects how quickly badPwdCount is reset.
Introduction
Several features of Active Directory account lockout are not well understood. For example, not all bad password attempts count towards account lockout. And the lockoutObservationWindow attribute is not what many people think. It is not the amount of time during which the bad password attempts must occur. It is also not just the amount of time allowed between bad attempts without resetting badPwdCount. Rather, it is the amount of time since the badPasswordTime attribute was last updated before the badPwdCount attribute resets. In group policy, this is called "Reset account lockout counter after" and is shown in minutes. This Wiki article explains some of the lesser known features of account lockout.
Account Lockout Attributes
Some of the Active Directory attributes relevant to account lockout are documented in the table below. Also included are the corresponding PowerShell property name and the Group Policy Setting.
AD Attribute | PowerShell Property | Group Policy Setting |
lockoutThreshold | LockoutThreshold | Account lockout threshold |
lockoutDuration | LockoutDuration | Account lockout duration |
lockoutObservationWindow | LockoutObservationWindow | Reset account lockout counter after |
pwdHistoryLength | PasswordHistoryCount | Enforce password history |
lockoutTime | AccountLockoutTime | <none> |
logonCount | <none> | <none> |
pwdLastSet | PasswordLastSet | <none> |
pwdProperties | ComplexityEnabled | Password must meet complexity requirements |
badPwdCount | BadLogonCount | <none> |
badPasswordTime | LastBadPasswordAttempt | <none> |
The first four attributes in the table only apply to the domain object in Active Directory. This is the default Domain Password and Account Lockout Policy. Similar attributes apply to Password Setting Objects (PSO's). The corresponding PSO attribute names are the same but start with the string "msDS-". The only exception is the PSO attribute corresponding to pwdHistoryLength, which is msDS-PasswordHistoryLength. The last six attributes apply to users. The attributes logonCount, badPwdCount, and badPasswordTime are not replicated, so each domain controller maintains its own values for each user.
Account Lockout in Windows 2000
Account lockout was straightforward in a domain at Windows 2000 domain functional level. When the number of bad password attempts reached the value of the lockoutThreshold attribute, the account was locked. All bad password attempts were forwarded to the DC with the PDC Emulator role. The total count was maintained on that DC. The lockoutObservationWindow attribute specified the amount of time since the badPasswordTime attribute was last updated before the badPwdCount attribute was reset.
Account Lockout in Windows 2003 and Above
Enhancements were introduced for domains at Windows Server 2003 functional level and above. When the bad password matches either of the two most recent entries in password history, the badPwdCount attribute is not incremented and the badPasswordTime attribute is not updated. This means that normal users can make more attempts before they are locked out. Their bad password attempts are more likely to be passwords they recently used.
The meaning of the lockoutObservationWindow attribute is the same. But because badPasswordTime is not updated for every bad password attempt, it affects the number of attempts users are allowed in some cases. The badPwdCount is more likely to reset when a user attempts with an old password.
This new feature is sometimes called password history n-2. The most recent previous password is referred to as n-1. The next most recent is n-2. Not all authentication types will take advantage of this new feature. Kerberos and NTLM authentication protocols support password history n-2. These protocols are used when either a password or smart card is used for interactive login. Other protocols, such as RADIUS and PEAP, may or may not increment badPwdCount when a bad password is attempted. Some protocols do not forward bad password attempts to the PDC Emulator. That might explain why phone users can get locked out if the phone attempts repeatedly to authenticate with a bad password.
In addition, the system can only know about the previous 2 passwords in history if pwdHistoryLength is at least 3. With that setting, the user can rotate through 3 passwords, so the previous 2 are retained in password history. If pwdHistoryLength is 2, the user can alternate between two passwords. The only password attempt that will not increment badPwdCount, in that case, is the previous one. The system does not retain the second most recent password.
Test Results
Tests were conducted to verify several features of account lockout in a domain at Windows Server 2003 or higher functional level. The relevant settings for these tests are documented in the following table.
Setting | Value |
lockoutThreshold | 5 |
lockoutDuration | 56 min, 40 sec |
lockoutObservationWindow | 5 min |
pwdHistoryLength | 4 |
minPwdLength | 6 |
password Complexity | Enabled |
PDC Emulator role | DC03 |
The relevant group policy settings are shown in this image. Some of the values in the GUI are truncated to the nearest minutes or days. For example, minimum password age was actually 13 minutes 20 seconds.
Two PowerShell version 1 scripts were developed to help with these tests. The first script finds all accounts with one or more bad password attempts on any domain controller in the domain. This script is linked here: Find All Accounts with Bad Password Counts
The second script retrieves attribute values relative to bad password attempts for a specified account on every domain controller in the domain. The attributes are sAMAccountName, pwdLastSet, lockoutTime, lastLogon, logonCount, badPwdCount, and badPasswordTime. The last four are not replicated. The script is linked here: Troubleshoot Account Bad Password Attempts
For these tests, the current password of the user was "Pas$00". The most recent password in password history was "Pas$01". The second most recent were "Pas$02", and so on. The fifth most recent password, "Pas$05" was not retained in password history because pwdHistoryLength is 4.
In the table below, the first column, labeled "Elapsed", is the time in minutes and seconds since the badPasswordTime attribute was updated on a domain controller. "Client (DC)" shows the client computer used by the user when the login was attempted, with the name of the domain controller that the client is connected to in parentheses. This would be the value of the "LogonServer" environment variable on the client. The third column in the table is the password used in the logion attempt. Next in the table are the results found on three domain controllers after the login attempt. One DC was the LogonServer, where the login request was handled. The other DC was not affected, but the DC that holds the PDC Emulator role, designated by "PDCe", is always updated. For each of the three DCs, the column labeled "Count" is the value of the badPwdCount attribute for the user. The column labeled "Time" is the value of the badPasswordTime attribute on the DC.
The test results are documented below. Bad password attempts that increment badPwdCount and update badPasswordTime are highlighted in red. Bad password attempts that do not increment badPwdCount or update badPasswordTime are highlighted in orange. A successful login is highlighted in green.
DC01 | DC02 | DC03 (PDCe) | ||||||
---|---|---|---|---|---|---|---|---|
Elapsed | Client (DC) | Password | Count | Time | Count | Time | Count | Time |
0 | WS01 (DC01) | Pas$04 | 1 | 21:19 | 0 | - | 1 | 21:19 |
3:06 | WS01 (DC01) | Pas$03 | 2 | 24:25 | 0 | - | 2 | 24:25 |
2:55 | WS01 (DC01) | Pas$05 | 3 | 27:20 | 0 | - | 3 | 27:20 |
- | WS01 (DC01) | Pas$02 | 3 | 27:20 | 0 | - | 3 | 27:20 |
- | WS01 (DC01) | Pas$01 | 3 | 27:20 | 0 | - | 3 | 27:20 |
- | WS01 (DC01) | Pas$02 | 3 | 27:20 | 0 | - | 3 | 27:20 |
11:59 | WS01 (DC01) | Pas$04 | 1 | 39:19 | 0 | - | 1 | 39:19 |
0:35 | WS01 (DC01) | Pas$03 | 2 | 39:54 | 0 | - | 2 | 39:54 |
0:35 | WS01 (DC01) | Pas$05 | 3 | 40:29 | 0 | - | 3 | 40:29 |
- | WS01 (DC01) | Pas$02 | 3 | 40:29 | 0 | - | 3 | 40:29 |
- | WS02 (DC02) | Pas$02 | 3 | 40:29 | 0 | - | 3 | 40:29 |
1:54 | WS02 (DC02) | Pas$04 | 3 | 40:29 | 1 | 42:23 | 4 | 42:23 |
0:32 | WS02 (DC02) | Pas$03 | 3 | 40:29 | 2 | 42:55 | 5 | 42:55 |
- | WS02 (DC02) | Pas$01 | 3 | 40:29 | 2 | 42:55 | 5 | 42:55 |
- | WS02 (DC02) | Pas$00 | 3 | 40:29 | 2 | 42:55 | 5 | 42:55 |
1 hour | WS02 (DC02) | Pas$00 | 0 | 40:29 | 0 | 42:55 | 0 | 42:55 |
Notice that the DC with the PDC Emulator role always has the latest information, even though in these tests it is never the DC that handles the login attempt. Whenever a DC finds that a login attempt has a bad password, it immediately contacts the PDC Emulator to check if the password was recently changed. If the PDC Emulator replies that the password is still bad, it increments the value of badPwdCount and updates the value of badPasswordTime for that user on the PDC Emulator. In this way, these values on the PDCe always reflect the true values for the user, unless the PDCe is not available. Any documentation that implies you must query all domain controllers in the domain and add the badPwdCount on each to get the true value is wrong on this point. The most up-to-date values of badPasswordTime and badPwdCount should always be on the PDC Emulator.
The lockoutObservationWindow is 5 minutes for these tests. The first three bad password attempts in the table above cause the badPwdCount on DC01 to increment to 3. For the next three bad password attempts, badPwdCount is not incremented because the passwords are among the 2 most recent values in password history. By the time the next bad password is attempted that increments the count, almost 12 minutes has elapsed since badPasswordTime last updated. This exceeds the value of lockoutObservationWindow, so the count is reset and badPwdCount is back to 1. After this several more bad password attempts increment badPwdCount to 3 and updates badPasswordTime. The final password attempt on client "WS01" is a password among the 2 most recent in password history, so neither badPwdCount nor badPasswordTime is updated.
Next, the bad password attempts switch to client "WS02", which is connected to "DC02". The first login attempt on this client is again a password among the 2 most recent in history, so nothing is updated. But the next two attempts now increment badPwdCount and update badPasswordTime on "DC02". After this, the count on "DC01" is 3 and the count on "DC02" is 2, but because the bad password attempts were forwarded to the DC with the PDC Emulator role, this DC now reflects the total bad password attempts. "DC03" has badPwdCount of 5 and badPasswordTime of 42:55. Since lockoutObservationWindow was not exceeded, the account is locked out.
The next two logon attempts after the account are locked do not update any of the attributes. The user gets the message that the account is locked, even when the correct password, "Pas$00", is used. The final logon attempt in the table succeeds because the lockoutDuration has expired. At this point, badPwdCount resets to zero on all DC's, but badPasswordTime remains unchanged.
One conclusion is that lockoutObservationWindow is the maximum amount of time between bad password attempts that update badPasswordTime before badPwdCount will reset. If a bad password attempt is made on a DC, and the current time exceeds badPasswordTime plus lockoutObservationWindow, then badPwdCount is reset to 1. Then badPasswordTime on the DC is updated to the current time.
If the PDC Emulator is Unavailable
Because the domain controller with the PDC Emulator role is so important, several tests were run with the PDC Emulator offline. Typical results are in the table below.
DC01 | DC02 | DC03 (PDCe) | ||||||
---|---|---|---|---|---|---|---|---|
Elapsed | Client (DC) | Password | Count | Time | Count | Time | Count | Time |
- | WS02 (DC02) | Pas$04 | 1 | 55:23 | 2 | 55:13 | - | - |
1:17 | WS02 (DC02) | Pas$04 | 2 | 56:40 | 2 | 55:13 | - | - |
- | WS02 (DC02) | Pas$01 | 2 | 56:40 | 2 | 55:13 | - | - |
2:37 | WS02 (DC02) | Pas$04 | 3 | 59:17 | 5 | 59:12 | - | - |
- | WS02 (DC02) | Pas$04 | 3 | 59:17 | 5 | 59:12 | 0 | past |
1 hour | WS02 (DC02) | Pas$00 | 0 | 59:17 | 0 | 59:12 | 0 | past |
The first bad password attempt above was handled by DC02 since the workstation was connected to that domain controller. The value of the LogonServer environment variable was "DC02". This DC should have forwarded the bad password request to the DC with the PDC Emulator role, but this DC was not available. Apparently, the request instead got forwarded to DC01, after a slight timeout delay. DC01 also incremented the value of badPwdCount on that DC. For some reason, the badPwdCount got incremented a second time on DC02. No documentation could be found for this behavior.
The next bad password attempt looks as if it was handled by DC01 because only the Count and Time on that DC was updated. It is almost as if the LogonServer switched to DC01 during the first password attempt. The third bad password matches the most recent password for this user in password history, so the login attempt is rejected but nothing is updated on either DC.
The fourth bad password attempt, with elapsed time 2:37 since the previous badPasswordTime, causes the count on DC01 to increment by one, but the count on DC02 increments to 5. At this point, the account is locked out. The DC with the PDC Emulator role is then connected to the network to see if anything gets updated on this DC on the next bad password attempt. But the next bad password attempt results in no updates on any of the domain controllers since the account is locked. The final password attempt, after another hour has gone by, succeeds because the lockoutDuration has passed and the password is finally correct. The badPwdCount resets on all of the DC's, as expected.
Notice that DC03 never got updated in this case with any bad password information. Also, the user actually only got 3 tries with bad passwords, other than the one in recent password history, before getting locked out. Several similar tests were conducted with the PDCe unavailable. In all cases, badPwdCount sometimes increased by more than one after a bad password attempt.
Risks If Some Bad Passwords Do Not Contribute to Lockout
This feature helps reduce account lockouts and support calls to the help desk from regular users. However, it could reveal useful information to a potential attacker. A knowledgeable person doing a dictionary attack could monitor the value of badPwdCount on the authenticating DC after each attempt. Such a person would be able to tell if an attempted password was among the two most recent in password history. This would not allow the attacker to compromise the account immediately. But it would provide useful information. First, knowledge of past passwords can give hints about how the user constructs their passwords. Second, the attacker can assume the user will probably reuse an old password eventually.
Even assuming the information can be used by the attacker, the effect is that three passwords are being attacked rather than just one. The odds of identifying any of the three are only improved by a factor of 3 at most. As long as passwords are long and complex, this is not a bad trade-off. Instead of an attack taking 3 years, it may take but one.
Also, this is only useful to someone with an existing account in the domain. If account lockout is configured the attacker needs to greatly reduce the number of attempts per minute, or risk lockouts.
Policy Considerations
The role of the PDC Emulator is the most critical for users. It is used for bad password attempts and password changes. The PDC Emulator in each domain serves as the primary time source for all computers in the domain, while the PDC Emulator in the forest root domain is the primary time source for the forest. As such, the following is recommended.
- The domain controller with the PDC Emulator FSMO role should be among the most reliable in the domain. It is important that this DC be available.
- The domain controller with the PDC Emulator FSMO role should be well connected. Users should not experience an unnecessary delay when password attempts are forwarded to this DC.
There is always a tradeoff between security and convenience. If the network is very secure, but users are constantly making calls to the help desk to unlock their account, the balance may be wrong. Perhaps the best recommendations are those by Microsoft in the blog post Configuring Account Lockout. However, each organization should evaluate what is best for them, considering the sensitivity of the information in their environment, the risks they can tolerate, and their users.
Configuring password complexity greatly increases security. The universe of possible characters in any password becomes 94. This is much better than allowing a password among just the 26 lower case letters. The minimum password length is also critical for increasing the number of possible passwords.
The maxPwdAge, lockoutThreshold, lockoutObservationWindow, and lockoutDuration attributes determine how many attempts an attacker can make in a period of time. If passwords never expire, or account lockout is not configured, the time becomes unlimited.
Enforcing password history prevents users from reusing passwords. However, to be effective, the minimum password age must be long enough to discourage users from changing their password multiple times to get back to one favorite.
Several blog posts recommend not configuring account lockout. Two are linked in the "Other Resources" section below. The argument is that there are many devices and applications today that authenticate automatically. If they have old passwords, many will retry multiple times, causing lockouts. However, this argument is only valid if a protocol other than Kerberos or NTLM is used.
See Also
- Wiki: Active Directory Domain Services (AD DS) Portal
- Wiki: Portal of TechNet Wiki Portals
- Active Directory: Glossary
- Active Directory: Large Integer Attributes
- Active Directory: Fun with Maximum Password Age
Other Resources
- AD lockout/ maximum password age (Post in the Directory Services Forum)
- Password history check n-2 (Post in the Directory Services Forum)
- Account Lockout and Password Concepts
- Bad-Pwd-Count attribute
- Bad-Password-Time attribute
- Attribute badPasswordTime
- Details of Account Lockout Settings and Processes
- Configuring Account Lockout (blog post)
- Account Lockout Policy in Active Directory (blog post)
- Active Directory: Account Lockout Policy – Think Twice Before Applying (blog post)
- RODC Frequently Asked Questions
- How the Kerberos Version 5 Authentication Protocol Works
- Troubleshooting Account Lockout
- Find All Accounts with Bad Password Counts (Script Gallery)
- Troubleshoot Account Bad Password Attempts (Script Gallery)