Атрибут контроля учетных записей пользователей userAccountControl является одним из важнейших атрибутов пользователя. Все администраторы Active Directory так или иначе используют этот атрибут в своей работе, но далеко не все понимают, что он из себя представляет и как работает.
Для примера возьмем самую простую, рутинную операцию — активация учетной записи. К вам обращается пользователь с жалобой на то, что его учетная запись отключена. Вы открываете оснастку Active Directory Users and Computers (ADUC), находите пользователя, открываете свойства его учетной записи и снимаете галочку «Account is disabled».
Задача выполнена, пользователь доволен. Но при чем тут userAccountControl спросите вы. А при том, что ставя галочку, вы меняете значение именно этого атрибута. Большинство свойств пользователя, представленных в этом окне, не являются самостоятельными атрибутами. Каждое из них является битом (флагом), который может принимать значение 1 (true) или 0 (false), но все эти значения не хранятся в виде отельных атрибутов в Active Directory, а являются частью одного единственного атрибута userAccountControl.
Таким образом, UserAccountControl представляет из себя битовую маску (bitwise) длиной в 32 бита (4 байта), где каждый параметр учетной записи является битом этой маски. Соответственно в зависимости от значений этих параметров и вычисляется общее значение userAccountControl.
Для наглядности разберем UserAccountControl по запчастям и поместим их в табличку.
Bit | Decimal | Hex | Binary | Flag |
0 | 1 | 0x00000001 | 0000 0000 0000 0000 0000 0000 0000 0001 | SCRIPT |
1 | 2 | 0x00000002 | 0000 0000 0000 0000 0000 0000 0000 0010 | ACCOUNTDISABLE |
2 | 4 | 0x00000004 | 0000 0000 0000 0000 0000 0000 0000 0100 | |
3 | 8 | 0x00000008 | 0000 0000 0000 0000 0000 0000 0000 1000 | HOMEDIR_REQUIRED |
4 | 16 | 0x00000010 | 0000 0000 0000 0000 0000 0000 0001 0000 | LOCKOUT |
5 | 32 | 0x00000020 | 0000 0000 0000 0000 0000 0000 0010 0000 | PASSWD_NOTREQD |
6 | 64 | 0x00000040 | 0000 0000 0000 0000 0000 0000 0100 0000 | PASSWD_CANT_CHANGE |
7 | 128 | 0x00000080 | 0000 0000 0000 0000 0000 0000 1000 0000 | ENCRYPTED_TEXT_PWD_ALLOWED |
8 | 256 | 0x00000100 | 0000 0000 0000 0000 0000 0001 0000 0000 | TEMP_DUPLICATE_ACCOUNT |
9 | 512 | 0x00000200 | 0000 0000 0000 0000 0000 0010 0000 0000 | NORMAL_ACCOUNT |
10 | 1024 | 0x00000400 | 0000 0000 0000 0000 0000 0100 0000 0000 | |
11 | 2048 | 0x00000800 | 0000 0000 0000 0000 0000 1000 0000 0000 | INTERDOMAIN_TRUST_ACCOUNT |
12 | 4096 | 0x00001000 | 0000 0000 0000 0000 0001 0000 0000 0000 | WORKSTATION_TRUST_ACCOUNT |
13 | 8192 | 0x00002000 | 0000 0000 0000 0000 0010 0000 0000 0000 | SERVER_TRUST_ACCOUNT |
14 | 16384 | 0x00004000 | 0000 0000 0000 0000 0100 0000 0000 0000 | |
15 | 32768 | 0x00008000 | 0000 0000 0000 0000 1000 0000 0000 0000 | |
16 | 65536 | 0x00010000 | 0000 0000 0000 0001 0000 0000 0000 0000 | DONT_EXPIRE_PASSWORD |
17 | 131072 | 0x00020000 | 0000 0000 0000 0010 0000 0000 0000 0000 | MNS_LOGON_ACCOUNT |
18 | 262144 | 0x00040000 | 0000 0000 0000 0100 0000 0000 0000 0000 | SMARTCARD_REQUIRED |
19 | 524288 | 0x00080000 | 0000 0000 0000 1000 0000 0000 0000 0000 | TRUSTED_FOR_DELEGATION |
20 | 1048576 | 0x00100000 | 0000 0000 0001 0000 0000 0000 0000 0000 | NOT_DELEGATED |
21 | 2097152 | 0x00200000 | 0000 0000 0010 0000 0000 0000 0000 0000 | USE_DES_KEY_ONLY |
22 | 4194304 | 0x00400000 | 0000 0000 0100 0000 0000 0000 0000 0000 | DONT_REQ_PREAUTH |
23 | 8388608 | 0x00800000 | 0000 0000 1000 0000 0000 0000 0000 0000 | PASSWORD_EXPIRED |
24 | 16777216 | 0x01000000 | 0000 0001 0000 0000 0000 0000 0000 0000 | TRUSTED_TO_AUTH_FOR_DELEGATION |
25 | 33554432 | 0x02000000 | 0000 0010 0000 0000 0000 0000 0000 0000 | |
26 | 67108864 | 0x04000000 | 0000 0100 0000 0000 0000 0000 0000 0000 | PARTIAL_SECRETS_ACCOUNT |
27 | 134217728 | 0x08000000 | 0000 1000 0000 0000 0000 0000 0000 0000 | |
28 | 268435456 | 0x10000000 | 10 000 000 000 000 000 000 000 000 000 | |
29 | 536870912 | 0x20000000 | 100 000 000 000 000 000 000 000 000 000 | |
30 | 1073741824 | 0x40000000 | 1 000 000 000 000 000 000 000 000 000 000 | |
31 | 2147483648 | 0x80000000 | 10 000 000 000 000 000 000 000 000 000 000 |
Всего 32 значения, хотя как можно заметить, используются далеко не все. Вот описание тех что используются:
SCRIPT — будет выполняться сценарий входа.
ACCOUNTDISABLE — учетная запись пользователя отключена.
HOMEDIR_REQUIRED — требуется домашняя папка.
LOCKOUT — учетная запись заблокирована.
PASSWD_NOTREQD — пароль не требуется. Этот флаг позволяет иметь полностью функционирующую учетную запись с пустым паролем, вне зависимости от действующей доменной политике паролей.
PASSWD_CANT_CHANGE — пользователь не может изменить пароль. На самом деле этот флаг регулируется разрешениями на объект пользователя, подробнее можно посмотреть здесь https://learn.microsoft.com/en-us/windows/win32/adsi/modifying-user-cannot-change-password-ldap-provider
ENCRYPTED_TEXT_PASSWORD_ALLOWED — указывает, будет ли AD хранить пароль в обратимом формате шифрования (Store password using reversible encryption), т.е. может ли пароль быть расшифрован. По умолчанию пароли хранятся в виде хеша, с использованием необратимого шифрования, т.е невозможно получить исходный пароль зная его хэш (за исключением использования полного перебора).
TEMP_DUPLICATE_ACCOUNT — учетная запись для пользователя, основная учетная запись которого находится в другом домене. Эта учетная запись предоставляет пользователю доступ к этому домену, но не к доменам, которые доверяют этому домену. Иногда его еще называют локальной учетной записью пользователя.
NORMAL_ACCOUNT — учетная запись пользователя по умолчанию.
INTERDOMAIN_TRUST_ACCOUNT — разрешение на доверие учетной записи для системного домена, который доверяет другим доменам.
WORKSTATION_TRUST_ACCOUNT — учетная запись компьютера под управлением рабочей станции Microsoft Windows NT 4.0, Microsoft Windows NT 4.0 Server, Microsoft Windows 2000 Professional или Windows 2000 Server, который является членом этого домена.
SERVER_TRUST_ACCOUNT — учетная запись компьютера для контроллера домена, который является членом этого домена.
DONT_EXPIRE_PASSWD — Срок действия пароля для учетной записи не ограничен (Password never expires). Этот флаг делает пароль пользователя бессрочным, вне зависимости от политики паролей в домене.
MNS_LOGON_ACCOUNT — это учетная запись для входа в MNS. Набор мажоритарных узлов ((Majority Node Set, MNS) представляет собой многосерверную конфигурацию с общей шиной хранения или без нее и кворумом, распределенным по всем серверам. Учетные записи входа в MNS можно использовать для настройки многоузлового кластера без использования общего жесткого диска.
SMARTCARD_REQUIRED — если этот флаг установлен, пользователь должен войти в систему с помощью смарт-карты.
TRUSTED_FOR_DELEGATION — если этот флаг установлен, учетная запись, под которой выполняется служба (учетная запись пользователя или компьютера) является доверенной для делегирования Kerberos. Любая такая служба может олицетворять клиента, запрашивающего службу. Чтобы включить службу для делегирования Kerberos, необходимо установить этот флаг в свойстве userAccountControl учетной записи службы.
NOT_DELEGATED — если этот флаг установлен, контекст безопасности пользователя не делегирован службе, даже если учетная запись службы настроена как доверенная для делегирования Kerberos.
USE_DES_KEY_ONLY — ограничить этот субъект использованием стандартных типов шифрования данных (DES).
DONT_REQUIRE_PREAUTH — эта учетная запись не требует предварительной проверки подлинности Kerberos для входа в систему.
PASSWORD_EXPIRED — срок действия пароля пользователя истек.
TRUSTED_TO_AUTH_FOR_DELEGATION — учетная запись включена для делегирования. Этот параметр позволяет службе, которая выполняется под учетной записью, использовать удостоверение клиента и выполнять проверку подлинности от имени этого пользователя на других удаленных серверах в сети. Этот параметр чувствителен к обеспечению безопасности, поэтому учетные записи, для которых он включен, должны строго контролироваться.
PARTIAL_SECRETS_ACCOUNT — учетная запись является контроллером домена только для чтения (RODC).
Как вычисляется текущее значение userAccountControl
Предположим у нас есть стандартная учетная запись пользователя (NORMAL_ACCOUNT) с бессрочным паролем (DONT_EXPIRE_PASSWORD). Берем оба значения в двоичном виде и проводим над ними операцию побитового ИЛИ (Bitwise OR):
00000000001000000000
00010000000000000000
00010000001000000000 = 66048 (Dec) = 0x10200 (Hex)
Этот пример я привел лишь для понимания того, что userAccountControl — это битовая маска, и все операции над ней проводятся побитно. В обычном случае можно просто сложить два десятичных значения:
512 + 65536 = 66048
Как посмотреть значение userAccountControl
Проще всего посмотреть текущее значение атрибута userAccountControl с помощью оснастки ADUC. Для этого надо включить отображение расширенных опций (Advanced features),
найти нужную учетную запись, перейти на вкладку редактора атрибутов (Attribute Editor) и найти атрибут userAccountControl. Как видите, он отображается в шестнадцатеричном виде и к нему прилагается название включенных флагов.
Если же выбрать атрибут и раскрыть его, то значение будет показано уже в десятичном виде.
Можно узнать значение userAccountControl и с помощью PowerShell. Например:
Get-ADUser ivanov_ii -Properties * | select Name,userAccountControl
Как видите, стандартный командлет возвращает только десятичное значение атрибута, без расшифровки флагов. Но это можно легко исправить с помощью найденного мной на просторах интернета скрипта вот такого содержания:
Function ConvertUserAccountControl ([int]$UAC)
{
$UACPropertyFlags = @(
"SCRIPT",
"ACCOUNTDISABLE",
"RESERVED",
"HOMEDIR_REQUIRED",
"LOCKOUT",
"PASSWD_NOTREQD",
"PASSWD_CANT_CHANGE",
"ENCRYPTED_TEXT_PWD_ALLOWED",
"TEMP_DUPLICATE_ACCOUNT",
"NORMAL_ACCOUNT",
"RESERVED",
"INTERDOMAIN_TRUST_ACCOUNT",
"WORKSTATION_TRUST_ACCOUNT",
"SERVER_TRUST_ACCOUNT",
"RESERVED",
"RESERVED",
"DONT_EXPIRE_PASSWORD",
"MNS_LOGON_ACCOUNT",
"SMARTCARD_REQUIRED",
"TRUSTED_FOR_DELEGATION",
"NOT_DELEGATED",
"USE_DES_KEY_ONLY",
"DONT_REQ_PREAUTH",
"PASSWORD_EXPIRED",
"TRUSTED_TO_AUTH_FOR_DELEGATION",
"RESERVED",
"PARTIAL_SECRETS_ACCOUNT"
"RESERVED"
"RESERVED"
"RESERVED"
"RESERVED"
"RESERVED"
)
return (0..($UACPropertyFlags.Length) | where {$UAC -bAnd [math]::Pow(2,$_)} | foreach {$UACPropertyFlags[$_]}) -join ” | ”
}
Эта функция получает на входе текущее значение userAccountControl в десятичном виде, а на выходе возвращает все включенные флаги (биты). С ее помощью мы можем вывести все флаги, вот примерно так:
Get-ADUser petrov_p -Properties * | fl Name,userAccountControl,@{Label="Flags";Expression={ConvertUserAccountControl($_.userAccountControl)}}
Еще одна распространенная ситуация — когда требуется найти всех пользователей с каким то конкретным флагом, например всех у кого срок действия пароля не истекает. Тут есть два пути.
Путь первый — можно просто искать всех пользователей с определенным значением userAccountControl, в случае с бессрочным паролем это будет 66048. Соответственно берем это значение и добавляем его в обычный фильтр:
Get-ADUser -Properties * -Filter {userAccountControl -like 66048} | select Name, userAccountControl
или в LDAP-фильтр, кому как больше нравится:
Get-ADUser -Properties * -LdapFilter "(userAccountControl=66048)" | select Name, userAccountControl
В большинстве ситуаций этого нехитрого фильтра вполне хватает. Но все таки не надо забывать, что userAccountControl включает в себя много разных флагов, и вполне может быть так, что кроме бессрочного пароля у пользователя включен еще какой нибудь из них. И в этом случае этот пользователь под фильтр не попадет, поскольку значение userAccountControl у него будет отличаться.
И тут нам поможет путь самурая второй — правила сопоставления, которые можно использовать для побитового сравнения числовых значений. Правила сопоставления имеют следующий синтаксис:
<attribute name>:<matching rule OID>:=<value>
Здесь attribute name — LDAPDisplayName имя атрибута, matching rule OID — идентификатора объекта правила (OID), value — значение, используемое для сравнения. Имейте в виду, что в этой строке нельзя использовать пробелы. Значение должно быть десятичным числом, оно не может быть шестнадцатеричным числом или константным именем.
Вот правила, которые можно использовать для поиска.
Идентификатор OID правила сопоставления | Идентификатор строки | Описание |
---|---|---|
1.2.840.113556.1.4.803 | LDAP_MATCHING_RULE_BIT_AND | Совпадение обнаруживается только в том случае, если все биты из атрибута соответствуют значению. Это правило эквивалентно побитовому И (bitwise AND) |
1.2.840.113556.1.4.804 | LDAP_MATCHING_RULE_BIT_OR | Совпадение обнаруживается, если какие-либо биты из атрибута соответствуют значению. Это правило эквивалентно побитовому ИЛИ (bitwise OR) |
С помощью этих правил мы можем найти значение для конкретного флага, вне зависимости от остальных. Вот так будет выглядеть команда для всех пользователей с неистекающим паролем:
Get-ADUser -Properties * -LdapFilter "(userAccountControl:1.2.840.113556.1.4.804=65536)" | select Name, userAccountControl
Как видите, результат отличается от предыдущего поиска. В выборку попала учетная запись гостя, поскольку у нее включена еще пара опций. Это в тестовой среде, в бою разница была бы гораздо больше.
Как изменить значение userAccountControl
Некоторые флаги userAccountControl можно изменять из оснастки ADUC, путем установки галочек. Для примера возьмем многострадальную 🙂 учетную запись ivanov_ii и поставим ему галку ″Password never Expires″.
Теперь проверим, значение атрибута. Изначально у него было значение 512 (NORMAL_ACCOUNT), теперь добавилось 65536 (DONT_EXPIRE_PASSWORD). Итого 66048 или 0x10200 в шестнадцатеричном виде.
Можно зайти с другой стороны и изменить значение userAccountControl напрямую, из редактора атрибутов. Возьмем получившееся значение 66048 и добавим к нему 2, тем самым отключив аккаунт.
Возвращаемся обратно к свойствам пользователя и видим, что галка ″Account is disabled″ установлена.
Можно менять значение userAccountControl и с помощью PowerShell. Так командлет Set-ADUser позволяет изменять некоторые флаги.
Для примера берем все ту же учетную запись ivanov_ii и возвращаем ее в исходное состояние. Затем устанавливаем ей флаг DONT_EXPIRE_PASSWORD командой:
Set-ADUser ivanov_ii -PasswordNeverExpires $true
Как и оснастка ADUC, командлет Set-ADUser может изменять не все флаги, по крайней мере явно. Но зато с его помощью можно менять значение userAccountControl напрямую. Добавим учетной записи флаг PASSWD_NOTREQD такой командой:
Set-ADUser ivanov_ii -Replace @{userAccountControl=66080}
Ну и начиная с 5 версии PowerShell для редактирования userAccountControl добавлен специальный командлет Set-ADAccountControl, который умеет менять почти все имеющиеся флаги. Возьмем его и уберем все лишнее с учетной записи:
Set-ADAccountControl -Identity ivanov_ii -PasswordNeverExpires $false -PasswordNotRequired $false
Есть у userAccountControl флаги, которые невозможно изменить в принудительном порядке. Так например если вы захотите установить флаг LOCKOUT, т.е. заблокировать пользователя, то у вас ничего не выйдет. Команда отработает, никаких ошибок не выдаст, но значение атрибута останется неизменным.
Скажу больше, даже если учетная запись пользователя действительно заблокирована, то значение userAccountControl останется неизменным. Дело в том, что флаг LOCKOUT был выпилен еще в Windows Server 2003 и заменен атрибутом msDS-User-Account-Control-Computed. При этом его описание до сих пор присутствует в официальной документации Microsoft.
Отдельно стоит упомянуть о флаге PASSWD_CANT_CHANGE. Этот флаг запрещает пользователю самостоятельно сменить свой пароль. Но если вы поставите галку ″User cannot change password″ в графической оснастке или проделаете эту операцию с помощью PowerShell, то значение userAccountControl никак не изменится. Дело в том, что эта операция не меняет значение атрибута, а вносит изменения в список доступа (Access Control List, ACL) пользователя. Если точнее, то ставится запрет на изменения пароля для объекта SELF, т.е. самого пользователя.
Конечно в документации есть небольшое уточнение на этот счет, но лично мне в целом непонятно, при чем тут вообще userAccountControl.
Данную тему можно развивать и дальше, но я пожалуй остановлюсь. Надеюсь у меня получилось хотя бы в общих чертах описать, что из себя представляет userAccountControl и как с ним обращаться.
Есть логическая ошибка в поиске UAC через LDAP_MATCHING_RULE_BIT_OR. Это так вы ловите не только нужные биты, но как раз любой их набор, достаточно попадания хотя бы одного бита. То есть в итоге будут как нужные, так и лишние записи.
Для поиска вхождения (отдельного набора битов) нужно использовать не OR a AND:
-LdapFilter «(UserAccountControl:1.2.840.113556.1.4.803:=$UacPart)»
-Filter «UserAccountControl -band $UacPart»