Windows Server для самых маленьких. Часть 6: Kerberos изнутри — как работает протокол
Kerberos придумали в MIT в 1980-х для проекта Athena: тысячи рабочих станций, десятки серверов, и ни одному из них нельзя доверять пароль пользователя. Решение — доверенная третья сторона, которая знает ключи всех участников и выдаёт им билеты: зашифрованные удостоверения с ограниченным сроком, которые можно предъявить службе вместо пароля. Версия 5 протокола описана в RFC 4120, Microsoft взяла её в Windows 2000 как основную аутентификацию домена и добавила к ней свои расширения, описанные в MS-KILE и MS-PAC. С тех пор каждый вход в домен, каждое открытие сетевой папки и каждый запрос к контроллеру по LDAP начинаются с Kerberos.
В прошлой части мы видели в Wireshark, как LDAP-соединение после SASL-привязки стало нечитаемым. Сегодня разберём, что именно там произошло: по сообщениям, по полям и по ключам.
Участники и ключи
Принципал — любой участник, у которого есть ключ. Пользователь записывается как alice@CORP.EXAMPLE.COM, служба — как cifs/srv1.corp.example.com@CORP.EXAMPLE.COM. Часть после @ — realm, область Kerberos; в Active Directory realm равен DNS-имени домена в верхнем регистре.
KDC (Key Distribution Center) — служба на каждом контроллере домена, процесс lsass.exe, служба Kdc. Внутри две логические части: AS (Authentication Server) выдаёт первичный билет, TGS (Ticket-Granting Server) выдаёт билеты на службы. Ключи всех принципалов KDC берёт из каталога: у каждой учётной записи они хранятся в атрибутах, которые не читаются по LDAP ни с какими правами, а только реплицируются между контроллерами.
Долговременный ключ принципала выводится из его пароля. Для пользователя — из того, что он набирает; для компьютера — из случайного 120-символьного пароля, который машина меняет сама раз в 30 дней; для службы — из пароля учётной записи, под которой она работает. Способ вывода зависит от типа шифрования:
- RC4-HMAC (тип 23): ключ — это NT-хеш пароля, MD4 от UTF-16-строки. Без соли: у двух пользователей с одинаковым паролем одинаковый ключ. Ключ эквивалентен паролю, и на этом держится семейство атак pass-the-hash.
- AES128-CTS-HMAC-SHA1-96 (тип 17) и AES256-CTS-HMAC-SHA1-96 (тип 18): ключ — PBKDF2 от пароля с 4096 итерациями и солью
REALM + имя(CORP.EXAMPLE.COMalice). Одинаковые пароли дают разные ключи, перебор в тысячи раз медленнее.
Какие типы разрешены у учётной записи, хранит атрибут msDS-SupportedEncryptionTypes — битовое поле (0x4 RC4, 0x8 AES128, 0x10 AES256, 0x18 оба AES); у пользователей он обычно пуст, и KDC берёт умолчание домена. RC4 объявлен Microsoft устаревшим, и в современных доменах его стоит выключить, предварительно убедившись по событиям аудита, что им никто не пользуется; как — в конце части.
krbtgt — учётная запись, созданная при установке домена (часть 4), всегда отключённая, с RID 502. Её ключ — главный ключ домена: им KDC шифрует все выдаваемые TGT. Любой контроллер, зная этот ключ, может расшифровать TGT, выданный другим контроллером, и обслужить клиента; никто другой расшифровать TGT не может. Два факта. Пароль krbtgt не меняется автоматически никогда, и в домене, созданном в 2008 году, он может быть всё тем же — а это значит, что кто-то, когда-то получивший его хеш, до сих пор может выписывать себе любые билеты (атака golden ticket). Поэтому его меняют руками, и дважды: KDC хранит текущий и предыдущий ключ и принимает билеты, зашифрованные любым из них, чтобы действующие TGT не протухли разом; вторая смена не раньше чем через срок жизни TGT (10 часов, лучше сутки) окончательно выводит старый ключ. Между сменами должна пройти репликация на все контроллеры.
Три обмена
ws1 (alice) dc1 (KDC: AS + TGS) srv1 (cifs/srv1)
│ │ │
│ 1. AS-REQ: alice, krbtgt/CORP, │ │
│ etypes, nonce, │ │
│ PA-ENC-TIMESTAMP {время}K_alice ───►│ │
│ │ расшифровать время ключом alice: │
│ │ получилось и время свежее → это alice│
│◄── 2. AS-REP: TGT {…}K_krbtgt, │ │
│ {сеансовый ключ S1, срок}K_alice │ │
│ │ │
│ 3. TGS-REQ: TGT, cifs/srv1, │ │
│ Authenticator {alice, время}S1 ────►│ │
│ │ расшифровать TGT ключом krbtgt, │
│ │ достать S1, проверить Authenticator │
│◄── 4. TGS-REP: билет {…, S2}K_srv1$, │ │
│ {S2, срок}S1 │ │
│ │ │
│ 5. AP-REQ внутри SMB: билет, Authenticator {alice, время}S2 ─────────────────►│
│ │ расшифровать билет своим ключом, │
│ │ достать S2, проверить Authenticator│
│◄── 6. AP-REP: {время}S2 ───────────────────────────────────────────────────────┤
AS-REQ / AS-REP: получить TGT. При входе клиент посылает KDC: своё имя, имя службы krbtgt/CORP.EXAMPLE.COM, список поддерживаемых типов шифрования, случайный nonce и предварительную аутентификацию — текущее время, зашифрованное ключом пользователя (PA-ENC-TIMESTAMP). KDC расшифровывает время тем ключом, что хранит для alice: если получилось осмысленное время в пределах пяти минут от своего, значит, клиент знает пароль. Если клиент прислал запрос без предварительной аутентификации, KDC отвечает ошибкой KDC_ERR_PREAUTH_REQUIRED с подсказкой, какие типы шифрования и какую соль использовать, и клиент повторяет запрос; это нормальный ход событий, и первый AS-REQ в любом захвате трафика всегда получает эту ошибку.
Зачем предварительная аутентификация: без неё KDC выдавал бы AS-REP кому угодно по одному имени, и в ответе лежит блок, зашифрованный ключом пользователя, который можно перебирать офлайн. Флаг DONT_REQ_PREAUTH в userAccountControl отключает требование для конкретной учётной записи, и учётные записи с этим флагом — первое, что ищет атакующий (AS-REP roasting).
Ответ AS-REP содержит две части. TGT — билет, зашифрованный ключом krbtgt; клиент не может его прочитать и хранит как есть. И блок, зашифрованный ключом пользователя: сеансовый ключ S1 (тот же, что лежит внутри TGT), срок действия, nonce из запроса (защита от повтора). Клиент расшифровывает блок паролем, и с этого момента пароль ему не нужен: все дальнейшие операции идут с S1. Windows держит пароль в памяти lsass для продления TGT, но по сети он больше не ходит ни в каком виде.
TGS-REQ / TGS-REP: получить билет на службу. Чтобы открыть \\srv1\share, клиенту нужен билет на cifs/srv1.corp.example.com. Он посылает TGS: TGT, имя службы и аутентификатор — своё имя и текущее время, зашифрованные S1. KDC расшифровывает TGT ключом krbtgt, достаёт оттуда S1 и имя клиента, расшифровывает аутентификатор S1: совпало имя, свежее время — запрос подлинный. Дальше KDC находит в каталоге учётную запись, на которой зарегистрировано SPN cifs/srv1.corp.example.com (это SRV1$), генерирует сеансовый ключ S2 и отвечает: сервисный билет, зашифрованный ключом SRV1$ (внутри — S2, имя клиента, срок, PAC), и блок с S2, зашифрованный S1.
AP-REQ / AP-REP: предъявить билет. Клиент открывает SMB-соединение с srv1 и в сообщении согласования передаёт AP-REQ: сервисный билет и аутентификатор, зашифрованный S2. Сервер расшифровывает билет своим ключом — тем самым, что выведен из пароля его учётной записи компьютера, — достаёт S2, проверяет аутентификатор и узнаёт из билета, кто пришёл и в каких группах состоит. Контроллер в этом шаге не участвует: сервер проверил клиента сам, и так работает даже когда контроллер недоступен, пока билет не истёк. Если клиент просил взаимную аутентификацию (в Windows всегда), сервер отвечает AP-REP с временем из аутентификатора, зашифрованным S2: так клиент убеждается, что сервер действительно знает ключ SRV1$, то есть это настоящий srv1.
AP-REQ почти никогда не ходит отдельным пакетом. Его заворачивают в GSS-API и SPNEGO (механизм согласования: «я умею Kerberos и NTLM, выбери») и вкладывают в протокол приложения: в SASL-привязку LDAP, в Session Setup SMB, в заголовок Authorization: Negotiate HTTP, в RPC-привязку. Поэтому в Wireshark Kerberos виден на порту 88 (AS и TGS) и внутри других протоколов (AP).
Что внутри билета
Ticket
├─ tkt-vno: 5
├─ realm: CORP.EXAMPLE.COM
├─ sname: cifs/srv1.corp.example.com
└─ enc-part (зашифровано долговременным ключом службы)
├─ flags: forwardable, renewable, pre_authent, …
├─ key: сеансовый ключ S2
├─ crealm, cname: CORP.EXAMPLE.COM, alice
├─ transited: через какие realm'ы прошёл (для доверий)
├─ authtime: когда клиент аутентифицировался (время AS-REQ)
├─ starttime, endtime, renew-till
├─ caddr: адреса клиента (Windows не заполняет)
└─ authorization-data
└─ AD-IF-RELEVANT → AD-WIN2K-PAC → PAC
Открытая часть — только имя службы и realm: по ним сервер понимает, каким ключом расшифровывать. Всё остальное закрыто ключом службы, и клиент, передающий билет, не может ни прочитать, ни изменить его содержимое.
PAC (Privilege Attribute Certificate) — расширение Microsoft, ради которого Kerberos и годится для Windows. Стандартный билет говорит только «это alice». Windows нужно знать SID пользователя и всех его групп, чтобы построить токен доступа и проверить ACL, не обращаясь к контроллеру за каждым файлом. PAC содержит:
- Logon Info — SID пользователя, RID основной группы, список RID групп домена, список SID групп из других доменов и встроенных (
Extra SIDs), имя, профиль, время входа, флаги учётной записи; - Client Info — имя и время для проверки;
- UPN and DNS Info — UPN и имя домена;
- Signatures — подпись ключом службы (чтобы служба увидела подмену) и подпись ключом
krbtgt(чтобы служба могла попросить контроллер проверить PAC, а сама не могла его подделать), а с 2022 года ещё две подписи для защиты от подмены имени и от переноса PAC между билетами.
Два следствия для администратора. Группы пользователя фиксируются в момент выдачи TGT: добавили пользователя в группу — он не увидит её, пока не получит новый TGT, то есть не выйдет и не войдёт (или не выполнит klist purge, после чего Windows получит TGT заново при следующем обращении). И у PAC есть размер: пользователь в тысяче групп получает билет на десятки килобайт, который может не влезть в заголовок HTTP или в буфер старого приложения; с 2012 года предел MaxTokenSize — 48 000 байт, и это предел не Kerberos, а Windows.
Флаги билета, которые показывает klist:
| Флаг | Значение |
|---|---|
initial |
получен через AS-REQ, а не из другого билета; есть только у TGT |
pre_authent |
клиент прошёл предварительную аутентификацию |
renewable |
можно продлить без пароля до renew-till |
forwardable |
по этому TGT можно получить TGT для другого хоста; нужен для неограниченного делегирования |
forwarded |
это и есть такой пересланный TGT |
ok_as_delegate |
KDC сообщает клиенту, что службе разрешено делегирование |
name_canonicalize |
KDC мог вернуть каноническое имя принципала вместо запрошенного |
enc_pa_rep |
в ответе была зашифрованная копия данных предварительной аутентификации (защита от подмены ответа) |
Сроки задаются политикой Kerberos в Default Domain Policy и по умолчанию такие: билет на службу — 10 часов, TGT — 10 часов, продление TGT — 7 дней, максимальное расхождение часов — 5 минут. Клиент продлевает TGT сам (TGS-REQ с опцией renew), пока не истёк renew-till, после чего понадобится пароль — в Windows это незаметно, потому что lsass его помнит. Про пять минут: аутентификатор несёт время, и KDC или служба отвергают его, если оно расходится с их часами больше допуска. Это защита от повтора перехваченных сообщений, и это же причина, по которой машина с ушедшими часами не может войти в домен — к этому мы вернёмся в части про время.
SPN
Клиент, запрашивая билет, называет службу по имени — SPN (service principal name): класс/хост[:порт][/имя]. Класс — cifs, ldap, HTTP, MSSQLSvc, host, RestrictedKrbHost, TERMSRV, WSMAN и любые другие строки, о которых договорились клиент и сервер; хост — полное DNS-имя. KDC ищет учётную запись, у которой это значение есть в многозначном атрибуте servicePrincipalName, и шифрует билет её ключом.
У учётной записи компьютера с момента вступления в домен есть HOST/srv1 и HOST/srv1.corp.example.com. HOST — обобщённый класс: в объекте CN=Directory Service,CN=Windows NT,CN=Services,CN=Configuration атрибут sPNMappings перечисляет, какие классы считаются псевдонимами HOST — cifs, ldap, http, rpcss, wsman, termsrv и ещё три десятка. Поэтому для SMB, WinRM и RDP на сервере ничего регистрировать не нужно. Регистрировать нужно, когда служба работает под другой учётной записью — SQL Server под CORP\svc-sql требует MSSQLSvc/sql1.corp.example.com:1433 на svc-sql, веб-приложение в IIS под CORP\svc-web — HTTP/web.corp.example.com на svc-web, — или когда к серверу обращаются по другому имени: CNAME intranet.corp.example.com, указывающий на srv1, требует HTTP/intranet.corp.example.com на SRV1$, потому что клиент строит SPN из имени, которое набрал, а не из того, в которое оно разрешилось.
PS C:\> setspn -L srv1
Registered ServicePrincipalNames for CN=SRV1,CN=Computers,DC=corp,DC=example,DC=com:
WSMAN/srv1
WSMAN/srv1.corp.example.com
TERMSRV/SRV1
TERMSRV/srv1.corp.example.com
RestrictedKrbHost/SRV1
HOST/SRV1
RestrictedKrbHost/srv1.corp.example.com
HOST/srv1.corp.example.com
PS C:\> setspn -S MSSQLSvc/sql1.corp.example.com:1433 svc-sql
Checking domain DC=corp,DC=example,DC=com
Registering ServicePrincipalNames for CN=svc-sql,OU=Service Accounts,DC=corp,DC=example,DC=com
MSSQLSvc/sql1.corp.example.com:1433
Updated object
PS C:\> setspn -X
Checking domain DC=corp,DC=example,DC=com
Processing entry 0
found 0 groups of duplicate SPNs.
-S вместо старого -A проверяет, что такого SPN ещё нет; -X ищет дубликаты по всему лесу. То же в PowerShell: Set-ADUser svc-sql -ServicePrincipalNames @{Add='MSSQLSvc/sql1.corp.example.com:1433'}.
Две ошибки с SPN, которые встречаются чаще всех остальных вместе взятых:
SPN не найден. KDC отвечает KDC_ERR_S_PRINCIPAL_UNKNOWN, и клиент, если он использует SPNEGO, молча откатывается на NTLM. Всё работает, но по NTLM: без взаимной аутентификации, с передачей проверки на контроллер при каждом соединении, без возможности делегирования. Так происходит при обращении по IP-адресу (SPN вида cifs/192.168.1.20 нет ни у кого, если не включена отдельная настройка), по CNAME без SPN, к службе под учётной записью без SPN. Увидеть можно по событиям 4776 на контроллере или по klist, где билета на эту службу нет.
SPN на неправильной учётной записи или дубликат. Билет зашифрован ключом учётной записи A, а служба работает под B и расшифровать его не может. Клиент получает KRB_AP_ERR_MODIFIED, и в зависимости от протокола это выглядит как «The target principal name is incorrect», «Cannot generate SSPI context» у SQL Server или событие Kerberos с кодом 4 в системном журнале клиента: «The Kerberos client received a KRB_AP_ERR_MODIFIED error from the server srv1$. The target name used was MSSQLSvc/sql1…». Лечится переносом SPN на правильную учётную запись.
Делегирование
Веб-приложение на web1 обращается к SQL Server на sql1 от имени пользователя, который открыл страницу. У web1 есть билет пользователя на HTTP/web1, но этот билет годится только для web1: предъявить его sql1 нельзя, он зашифрован ключом web1. Это проблема второго прыжка, и Kerberos решает её делегированием трёх видов.
Неограниченное (unconstrained): флаг TRUSTED_FOR_DELEGATION на учётной записи web1. KDC выдаёт на HTTP/web1 билеты с флагом ok_as_delegate, клиент, видя его, запрашивает пересланный TGT (forwarded) и отправляет его web1 вместе с билетом. web1 получает полноценный TGT пользователя и может получить от его имени билет на что угодно. Удобно и опасно: скомпрометированный web1 действует как любой зашедший на него пользователь, включая администратора домена. Контроллеры домена имеют этот флаг по необходимости; рядовым серверам его не дают.
Ограниченное (constrained, Windows Server 2003): в атрибуте msDS-AllowedToDelegateTo на web1 перечислены SPN, к которым он может обращаться от имени клиентов, — MSSQLSvc/sql1.corp.example.com:1433. Механизм — два расширения протокола: S4U2Proxy позволяет web1 предъявить KDC билет пользователя на себя и получить билет на sql1 от имени пользователя; S4U2Self позволяет получить билет на себя от имени любого пользователя без его участия («с переходом протокола», когда пользователь аутентифицировался не по Kerberos, а, например, по форме на сайте). Настройка — на вкладке Delegation учётной записи или Set-ADComputer web1 -Add @{'msDS-AllowedToDelegateTo'='MSSQLSvc/sql1.corp.example.com:1433'}.
На основе ресурса (resource-based constrained, Windows Server 2012): то же ограниченное, но разрешение задаёт не администратор web1, а владелец sql1 — в атрибуте msDS-AllowedToActOnBehalfOfOtherIdentity на sql1 список тех, кому разрешено к нему приходить от чужого имени. Работает через доверие между лесами и не требует прав администратора домена: Set-ADComputer sql1 -PrincipalsAllowedToDelegateToAccount (Get-ADComputer web1).
Проблема второго прыжка возникает и в PowerShell Remoting — когда вы, подключившись к серверу, пытаетесь с него обратиться к сетевой папке, — и мы увидим её решения, от делегирования до CredSSP, в части про WinRM.
Ошибки
Коды из RFC 4120, которые встречаются в журналах и захватах:
| Код | Имя | Что означает на практике |
|---|---|---|
| 6 | KDC_ERR_C_PRINCIPAL_UNKNOWN |
нет такого пользователя (или клиент обратился в другой realm) |
| 7 | KDC_ERR_S_PRINCIPAL_UNKNOWN |
нет учётной записи с таким SPN; клиент откатится на NTLM |
| 12 | KDC_ERR_POLICY |
политика запрещает: вход в это время, на этот компьютер, протокол транзишена |
| 13 | KDC_ERR_BADOPTION |
обычно делегирование не разрешено для запрошенной службы |
| 14 | KDC_ERR_ETYPE_NOSUPP |
нет общего типа шифрования: у клиента только RC4, у службы только AES, или наоборот |
| 18 | KDC_ERR_CLIENT_REVOKED |
учётная запись отключена, заблокирована или истекла |
| 23 | KDC_ERR_KEY_EXPIRED |
истёк пароль; клиент предложит сменить |
| 24 | KDC_ERR_PREAUTH_FAILED |
неправильный пароль |
| 25 | KDC_ERR_PREAUTH_REQUIRED |
нормальный первый ответ на AS-REQ без предварительной аутентификации |
| 32 | KRB_AP_ERR_TKT_EXPIRED |
билет истёк, клиент запросит новый |
| 37 | KRB_AP_ERR_SKEW |
часы расходятся больше чем на 5 минут |
| 41 | KRB_AP_ERR_MODIFIED |
служба не смогла расшифровать билет: SPN на другой учётной записи или дубликат, устаревший пароль службы |
| 52 | KRB_ERR_RESPONSE_TOO_BIG |
ответ не влезает в UDP; клиент повторит по TCP. Windows ходит по TCP сразу, если ответ больше 1465 байт |
| 68 | KDC_ERR_WRONG_REALM |
клиент обратился не в тот realm; KDC подсказывает правильный (используется при доверии) |
На контроллере каждый запрос к KDC записывается в журнал Security, если включён аудит Kerberos (в Default Domain Controllers Policy он включён):
| Событие | Что |
|---|---|
| 4768 | выдан TGT (AS-REP) или отказано — код ошибки в поле Result Code |
| 4769 | выдан билет на службу (TGS-REP) или отказано; поле Ticket Encryption Type показывает 0x12 (AES256), 0x11 (AES128) или 0x17 (RC4) |
| 4770 | TGT продлён |
| 4771 | предварительная аутентификация не прошла: неправильный пароль, Failure Code 0x18 |
| 4776 | контроллер проверил учётные данные по NTLM; каждое такое событие — соединение, которое не стало Kerberos |
Смотрим руками
klist на рабочей станции, разбор по полям:
PS C:\> klist
Current LogonId is 0:0x3e7a1
Cached Tickets: (2)
#0> Client: alice @ CORP.EXAMPLE.COM
Server: krbtgt/CORP.EXAMPLE.COM @ CORP.EXAMPLE.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
Start Time: 10/15/2026 9:02:11 (local)
End Time: 10/15/2026 19:02:11 (local)
Renew Time: 10/22/2026 9:02:11 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0x1 -> PRIMARY
Kdc Called: dc1.corp.example.com
#1> Client: alice @ CORP.EXAMPLE.COM
Server: cifs/srv1.corp.example.com @ CORP.EXAMPLE.COM
KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
Ticket Flags 0x40a10000 -> forwardable renewable pre_authent name_canonicalize
Start Time: 10/15/2026 9:05:40 (local)
End Time: 10/15/2026 19:02:11 (local)
Renew Time: 10/22/2026 9:02:11 (local)
Session Key Type: AES-256-CTS-HMAC-SHA1-96
Cache Flags: 0
Kdc Called: dc1.corp.example.com
LogonId — сеанс входа, у каждого сеанса свой кеш билетов (служба и пользователь на одной машине их не делят). KerbTicket Encryption Type — чем зашифрован сам билет, то есть тип ключа службы: у TGT это ключ krbtgt, у #1 — ключ SRV1$. Session Key Type — тип сеансового ключа; при 0x17 здесь у современного клиента стоит задуматься, кто попросил RC4. У сервисного билета End Time совпадает с TGT: билет на службу не может жить дольше TGT, из которого получен. Kdc Called — какой контроллер ответил.
Полезные подкоманды: klist purge — сбросить кеш (пересоздать TGT с новым набором групп без выхода из системы), klist get cifs/srv1.corp.example.com — запросить билет сейчас и увидеть ошибку, если она есть, klist tgt — подробности TGT, klist sessions — все сеансы входа на машине, klist -li 0x3e7 — билеты учётной записи SYSTEM (компьютера), чтобы увидеть, как сам компьютер аутентифицируется в домене.
Обмен в пакетах. Снимаем pktmon с фильтром на порт 88, выполняем klist purge и dir \\srv1\c$, открываем в Wireshark:
No. Source Destination Protocol Info
1 192.168.1.100 192.168.1.10 KRB5 AS-REQ
2 192.168.1.10 192.168.1.100 KRB5 KRB Error: KRB5KDC_ERR_PREAUTH_REQUIRED
3 192.168.1.100 192.168.1.10 KRB5 AS-REQ
4 192.168.1.10 192.168.1.100 KRB5 AS-REP
5 192.168.1.100 192.168.1.10 KRB5 TGS-REQ
6 192.168.1.10 192.168.1.100 KRB5 TGS-REP
В третьем пакете, развернув padata, видно PA-ENC-TIMESTAMP с etype: eTYPE-AES256-CTS-HMAC-SHA1-96 (18) и зашифрованным блоком; в req-body — cname: alice, sname: krbtgt/CORP.EXAMPLE.COM, till, nonce, список etype клиента. В AS-REP — ticket с открытым sname и enc-part, и отдельный enc-part для клиента. В TGS-REQ — padata типа PA-TGS-REQ с AP-REQ внутри (TGT плюс аутентификатор) и sname: cifs/srv1.corp.example.com. Сам AP-REQ к srv1 в этом захвате искать нужно на порту 445, внутри SMB2 Session Setup, в поле Security Blob — SPNEGO с krb5_blob внутри.
Что знает о своих ключах каталог:
PS C:\> Get-ADUser krbtgt -Properties PasswordLastSet, msDS-KeyVersionNumber, msDS-SupportedEncryptionTypes | Select-Object PasswordLastSet, msDS-KeyVersionNumber, msDS-SupportedEncryptionTypes
PasswordLastSet msDS-KeyVersionNumber msDS-SupportedEncryptionTypes
--------------- --------------------- -----------------------------
01.10.2026 11:58:02 2
PS C:\> Get-ADComputer srv1 -Properties msDS-SupportedEncryptionTypes, PasswordLastSet, servicePrincipalName | Select-Object Name, PasswordLastSet, msDS-SupportedEncryptionTypes
Name PasswordLastSet msDS-SupportedEncryptionTypes
---- --------------- -----------------------------
SRV1 10.10.2026 8:14:33 28
msDS-KeyVersionNumber — номер версии ключа (kvno): билеты несут его в заголовке, и служба по нему понимает, каким из своих ключей расшифровывать. У krbtgt kvno 2 означает, что пароль со дня установки не менялся (первая версия — при создании, вторая — при повышении). У компьютера 28 = 0x1C — RC4 плюс AES128 плюс AES256: это умолчание для учётных записей компьютеров, и именно по нему KDC решает, что srv1 умеет AES.
Кто в домене ещё пользуется RC4, прежде чем его выключать:
PS C:\> Get-WinEvent -ComputerName dc1 -FilterHashtable @{LogName='Security'; Id=4769; StartTime=(Get-Date).AddDays(-7)} |
Where-Object { $_.Properties[5].Value -eq '0x17' } |
Group-Object { $_.Properties[0].Value }, { $_.Properties[2].Value } |
Select-Object Count, Name | Sort-Object Count -Descending
Count Name
----- ----
42 CORP\scanner$, MSSQLSvc/sql1.corp.example.com:1433
Свойство 5 события 4769 — тип шифрования билета, 0 — имя клиента, 2 — служба. Здесь RC4 просит старый сетевой сканер, и пока он не заменён или не обновлён, у учётной записи svc-sql придётся оставить RC4 в msDS-SupportedEncryptionTypes. Когда список пуст, RC4 отключается на уровне домена политикой «Network security: Configure encryption types allowed for Kerberos» в Default Domain Policy и значением msDS-SupportedEncryptionTypes = 24 на учётных записях служб.
И последнее. Журнал Kerberos на клиенте по умолчанию почти пуст; его включает ключ реестра:
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Lsa\Kerberos\Parameters' -Name LogLevel -Value 1 -Type DWord
Get-WinEvent -LogName System -FilterHashtable @{ProviderName='Microsoft-Windows-Security-Kerberos'} -MaxEvents 10
После этого каждая ошибка KDC попадает в системный журнал с кодом из таблицы выше и именем службы, к которой обращался клиент. Это первое, что включают, когда «не подключается, а почему — непонятно», и первое, что выключают после, потому что журнал быстро заполняется ошибками 25, которые ошибками не являются.
Kerberos держится на двух внешних вещах: клиент должен найти KDC и правильно назвать службу — это DNS, — и часы всех участников должны совпадать с точностью до пяти минут. Следующие части — о первом и о втором.
Дальше — часть 7: DNS в домене. Зоны, интегрированные в каталог, и их области репликации; безопасные динамические обновления и кто имеет право менять запись; форвардеры, условные форвардеры и stub-зоны; обратные зоны; очистка устаревших записей; и как держать внутреннюю копию публичной зоны, не ломая сайт.
Серия «Windows Server для самых маленьких»
- Windows Server с нуля — редакции, Server Core, установка, первые команды PowerShell, имя, сеть, время, обновления, роли.
- Диски и сеть: diskpart, netsh и их PowerShell-замены — разметка дисков и сетевой стек через старые утилиты и модули Storage, NetTCPIP, NetSecurity, и что умеют только утилиты.
- Как устроен Active Directory — лес, домен, OU, объекты, разделы каталога, глобальный каталог, SYSVOL, DC Locator и протоколы домена.
- Первый контроллер домена — имя домена, роль AD DS,
Install-ADDSForestи что происходит при повышении,dcdiag, первые члены домена и первая учётная запись администратора. - LDAP изнутри — операции протокола, имена и атрибуты, схема, RootDSE, фильтры,
ldp.exeи ADSI Edit, и что в каталоге нельзя трогать. - Kerberos изнутри (эта статья) — ключи и
krbtgt, обмены AS и TGS, билет и PAC, SPN, делегирование, ошибки иklist.
Оставить комментарий могут только зарегистрированные пользователи.
Войдите на сайт или зарегистрируйтесь, чтобы оставить комментарий.