Заметки о Windows и других программных продуктах Microsoft...

Разбираем атрибут пользователя UserAccountControl

Разбираем атрибут пользователя UserAccountControl

Атрибут контроля учетных записей пользователей 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

 

Если же выбрать атрибут и раскрыть его, то значение будет показано уже в десятичном виде.

значение атрибута userAccountControl в десятичном виде

 

Можно узнать значение userAccountControl и с помощью PowerShell. Например:

Get-ADUser ivanov_ii -Properties * | select Name,userAccountControl

Просмотр значения userAccountControl в PowerShell

 

Как видите, стандартный командлет возвращает только десятичное значение атрибута, без расшифровки флагов. Но это можно легко исправить с помощью найденного мной на просторах интернета скрипта вот такого содержания:

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 в PowerShell

 

Еще одна распространенная ситуация — когда требуется найти всех пользователей с каким то конкретным флагом, например всех у кого срок действия пароля не истекает. Тут есть два пути.

Путь первый — можно просто искать всех пользователей с определенным значением userAccountControl, в случае с бессрочным паролем это будет 66048. Соответственно берем это значение и добавляем его в обычный фильтр:

Get-ADUser -Properties * -Filter {userAccountControl -like 66048} | select Name, userAccountControl

Поиск пользователей по общему значению userAccountControl

 

или в LDAP-фильтр, кому как больше нравится:

Get-ADUser -Properties * -LdapFilter "(userAccountControl=66048)" | select Name, userAccountControl

Поиск пользователей по общему значению userAccountContro с помощью LDAP-фильтра

 

В большинстве ситуаций этого нехитрого фильтра вполне хватает. Но все таки не надо забывать, что 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″.

ставим галку Password never expires

 

Теперь проверим, значение атрибута. Изначально у него было значение 512 (NORMAL_ACCOUNT), теперь добавилось 65536 (DONT_EXPIRE_PASSWORD). Итого 66048  или 0x10200 в шестнадцатеричном виде.

проверяем значение userAccountControl

 

Можно зайти с другой стороны и изменить значение userAccountControl напрямую, из редактора атрибутов. Возьмем получившееся значение 66048 и добавим к нему 2, тем самым отключив аккаунт.

изменяем значение userAccountControl напрямую

 

Возвращаемся обратно к свойствам пользователя и видим, что галка ″Account is disabled″ установлена.

проверяем свойства пользователя

 

Можно менять значение userAccountControl и с помощью PowerShell. Так командлет Set-ADUser позволяет изменять некоторые флаги.

Для примера берем все ту же учетную запись ivanov_ii и возвращаем ее в исходное состояние. Затем устанавливаем ей флаг DONT_EXPIRE_PASSWORD командой:

Set-ADUser ivanov_ii -PasswordNeverExpires $true

изменение userAccountControl с помощью Set-ADUser

 

Как и оснастка ADUC, командлет Set-ADUser  может изменять не все флаги, по крайней мере явно. Но зато с его помощью можно менять значение userAccountControl напрямую. Добавим учетной записи флаг PASSWD_NOTREQD такой командой:

Set-ADUser ivanov_ii -Replace @{userAccountControl=66080}

прямое изменение userAccountControl с помощью Set-ADUser

 

Ну и начиная с 5 версии PowerShell для редактирования userAccountControl добавлен специальный командлет Set-ADAccountControl, который умеет менять почти все имеющиеся флаги. Возьмем его и уберем все лишнее с учетной записи:

Set-ADAccountControl -Identity ivanov_ii -PasswordNeverExpires $false -PasswordNotRequired $false

прямое изменение userAccountControl с помощью Set-ADAccountControl

 

Есть у 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.

ACL пользователя

 

Данную тему можно развивать и дальше, но я пожалуй остановлюсь. Надеюсь у меня получилось хотя бы в общих чертах описать, что из себя представляет userAccountControl и как с ним обращаться.

 
 
Комментарии

Есть логическая ошибка в поиске UAC через LDAP_MATCHING_RULE_BIT_OR. Это так вы ловите не только нужные биты, но как раз любой их набор, достаточно попадания хотя бы одного бита. То есть в итоге будут как нужные, так и лишние записи.
Для поиска вхождения (отдельного набора битов) нужно использовать не OR a AND:
-LdapFilter «(UserAccountControl:1.2.840.113556.1.4.803:=$UacPart)»
-Filter «UserAccountControl -band $UacPart»

Ответить