Recently I was tasked with conducting a quick audit of Active Directory. I was looking for user accounts who do not require a password to log into systems. I was also looking for user accounts on which passwords do not expire.
The UserAccountControl value in Active Directory stores this information. The UserAccountControl value is a 4-byte integer that represents flags on the object. This integer is calculated by performing a bitwise enumeration of these flags. When querying the full set of properties of an object, the value of UserAccountControl can be examined and interpreted to determine additional properties of the object.
The following table shows common values for the UserAccountControl property.
Description | Hexadecimal Value | Integer Value |
---|---|---|
ACCOUNTDISABLE | 0x0002 | 2 |
PASSWD_NOTREQD | 0x0020 | 32 |
NORMAL_ACCOUNT | 0x0200 | 512 |
DONT_EXPIRE_PASSWORD | 0x10000 | 65536 |
PASSWORD_EXPIRED | 0x800000 | 8388608 |
So how exactly does this work?
A normal account has the integer value of 512 as shown above. But a disabled normal account would have the integer value of 514. This is the result of adding the 512 value for NORMAL_ACCOUNT and the value for ACCOUNTDISABLE, which is 2.
User accounts that do not require a passwords have the PASSWD_NOTREQD bit added. The first step was to search for the integer values of 544 and 546. These values consist of the previously mentioned enabled normal account and disabled normal account, but with the PASSWD_NOTREQD value of 32 added.
- 544 = 512 (NORMAL_ACCOUNT) + 32 (PASSWD_NOTREQD)
- 546 = 512 (NORMAL_ACCOUNT) + 32 (PASSWD_NOTREQD) + 2 (ACCOUNTDISABLED)
A quick PowerShell yields the accounts that do not require a password.
Get-ADUser -Filter {samAccountName -like "*"} | Where-Object { ($_.UserAccountControl -eq 544) -or ($_.UserAccountControl -eq 546) }
This formula can also be extended to accounts with the DONT_EXPIRE_PASSWORD bit.
- 66080 = 544 (previous example) + 65536 (DONT_EXPIRE_PASSWORD)
- 66082 = 546 (previous example) + 65536 (DONT_EXPIRE_PASSWORD)
Get-ADUser -Filter {samAccountName -like "*"} | Where-Object { ($_.UserAccountControl -eq 66080) -or ($_.UserAccountControl -eq 66082) }
Once the accounts that are in violation were identified, they were updated with the Set-ADAccountControl cmdlet.
Additional Reading