惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

W
WeLiveSecurity
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
Stack Overflow Blog
Stack Overflow Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
IT之家
IT之家
Cloudbric
Cloudbric
The Register - Security
The Register - Security
小众软件
小众软件
PCI Perspectives
PCI Perspectives
G
Google Developers Blog
AI
AI
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
Google DeepMind News
Google DeepMind News
宝玉的分享
宝玉的分享
Recent Commits to openclaw:main
Recent Commits to openclaw:main
量子位
TaoSecurity Blog
TaoSecurity Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
F
Full Disclosure
N
Netflix TechBlog - Medium
博客园_首页
Last Week in AI
Last Week in AI
A
Arctic Wolf
B
Blog RSS Feed
J
Java Code Geeks
C
Cybersecurity and Infrastructure Security Agency CISA
I
InfoQ
aimingoo的专栏
aimingoo的专栏
云风的 BLOG
云风的 BLOG
NISL@THU
NISL@THU
MyScale Blog
MyScale Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Jina AI
Jina AI
有赞技术团队
有赞技术团队
S
Schneier on Security
L
Lohrmann on Cybersecurity
P
Privacy & Cybersecurity Law Blog
T
Threat Research - Cisco Blogs
P
Palo Alto Networks Blog
S
Security @ Cisco Blogs
Security Archives - TechRepublic
Security Archives - TechRepublic
Security Latest
Security Latest
Vercel News
Vercel News
博客园 - 司徒正美
Webroot Blog
Webroot Blog
Hacker News: Ask HN
Hacker News: Ask HN
A
About on SuperTechFans

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
Самое подробное руководство по использованию утилиты ktpass в среде Active Directory
gotch · 2026-04-30 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение15 мин

Охват и читатели505

Туториал

Давайте разберем как с помощью утилиты ktpass.exe создавать гарантированно рабочие файлы keytab. Подробно, с примерами рассмотрим каждый параметр ktpass.exe. А самое интересное - вы узнаете неочевидные факты о принципах использовании salt при генерации ключей Kerberos, из-за которой получаются нерабочие ключи AES. Об этом нам расскажет инспекция базы ntds.dit командлетами DSInternals.

Разбор формата файла key table (keytab)

Сначала разберемся с форматом файла keytab. Это файл используется в open source реализациях Kerberos для хранения ключей шифрования. Ключи хранятся в открытом виде и используются для шифрования Kerberos. Ключ является производным от пароля учетной записи.
Упрощенно таблица выглядит следующим образом:

principal

KVNO

enctype

key length

key contents

key version

HTTP/myproxy.habr.test

4

aes128-cts-hmac-sha1-96)

0xff8ecfc8b1e112e619257d8675bfab21

Получить таблицу ключей в читаемом представлении можно утилитойklist -kteK
В Windows для этого понадобится пакет MIT Kerberos.

Если у учётной записи есть необходимые SPN, то зная пароль и текущий KVNO можно создать корректный keytab не обращаясь к Active Directory. А сама утилита ktpass.exe умеет вносить в AD только пароль учетной записи, SPN, UPN.

Разбор параметров утилиты ktpass.exe

Теперь детально разберем каждый параметр утилиты ktpass

[- /] out : Keytab to produce

-out c:\temp\svc-proxy01.keytab

Имя выходного файла keytab.

[- /] princ : Principal name (user@REALM)

-princ HTTP/proxy01.habr.test@HABR.TEST

Как правило, в этом поле указывают Service Principal Name (SPN), имеющий формат <SERVICE>/<fqdn>@<REALM>

[- /] pass : password to use, use '*' to prompt for password

-pass *
Пароль будет запрошен интерактивно при запуске утилиты.

-pass ABCDF@password
-pass "ABCDF@password"
Пароль учетной записи, из которого будет рассчитан ключ. Равнозначные конструкции, кавычки не будут включены в пароль.
-pass 'ABCDF@password'
Неправильный вариант, кавычки будут включены в пароль.

Если использовать параметр -pass вместе с -setpass, пароль будет использован для расчета ключа, но не будет записан в AD.

[- +] rndPass : ... or use +rndPass to generate a random password
[- /] minPass : minimum length for random password (def:15)
[- /] maxPass : maximum length for random password (def:256)

-rndPass
Отключает установку случайного пароля. Ничего не делает.

+rndPass
Устанавливает случайный пароль. Длина пароля устанавливается ключами -minPass и-maxPass (по умолчанию - от 15 до 256 символов). Обратите внимание, что максимальное значение этих двух параметров на самом деле составляет 255.
+rndpass является приоритетным по отношению к параметру -pass и отменяет действие последнего.

[- /] mapuser : map princ (above) to this user account (default: don't)

-mapuser svc-proxy
-mapuser HABR\proxy01$
Записать SPN в атрибут servicePrincipalName учетной записи. Рекомендуется использовать в большинстве сценариев. Не обязателен для автономной генерации keytab, если SPN уже задан и не планируется сброс пароля учетной записи.

Утилита проверяет не назначен ли SPN на другую учетную запись (аналогично setspn -Q) и если он уже используется, то не будет его назначать.

[- /] mapOp : how to set the mapping attribute (default: add it) is one of: add : add value (default), set : set value
-mapOp add
Добавить SPN в атрибут servicePrincipalName (дубликаты не добавляются)
-mapOp set
Задать значение атрибута servicePrincipalName равным -princ. Следует использовать осторожностью.

[- +] DesOnly : Set account for des-only encryption (default:don't)

-DesOnly
Ничего не делает.
+DesOnly
Устанавливает атрибут Using only Kerberos DES encryption types for this account. Заставляет KDC согласовывать с клиентом только алгоритмы шифрования des-cbc-crc и des-cbc-md5. Не стоит использовать ни в каких ситуациях.

[- /] in : Keytab to read/digest

-in c:\temp\svc-proxy01.keytab
Утилита ktpass позволяет формировать keytab файлы только для одного SPN. В случае необходимости использования нескольких SPN, ключ -in позволяет добавить в выходной -out файл помимо генерируемых новых записей содержимое файла -in

[- /] crypto : Cryptosystem to use is one of: DES-CBC-CRC : for compatibility, DES-CBC-MD5 : for compatibility, RC4-HMAC-NT : default 128-bit encryption, AES256-SHA1 : AES256-CTS-HMAC-SHA1-96, AES128-SHA1,AES128-CTS-HMAC-SHA1-96, All : All supported types

-crypto AES128-SHA1
Сформировать строку keytab только для алгоритма AES128-SHA1.
-crypto All
Сформировать строки keytab для всех алгоритмов.
Особенности использования различных алгоритмов будут рассмотрены далее.

[- /] IterCount : Iteration Count used for AES encryption. Default: ignored for non-AES, 4096 for AES
Важный параметр, непосредственно влияющий на значение ключей шифрования алгоритмов группы AES. Значение по-умолчанию совпадает с числом итераций в AD.

[- /] ptype : principal type in question is one of: KRB5_NT_PRINCIPAL : The general ptype-- recommended, KRB5_NT_SRV_INST : user service instance, KRB5_NT_SRV_HST : host service instance, KRB5_NT_SRV_XHST :

В соответствии с RFC 4120:

NT_PRINCIPAL - рекомендуемый универсальный principal, поддерживающий как service principal name вида http/fqdn@REALM, так и user principal name вида user@REALM
NT-SRV-INST - используется для службы krbtgt с SPN вида service/REALM@REALM, например krbtgt/HABR.TEST@HABR.TEST
NT-SRV-HST - principal только с service principal name вида http/fqdn@REALM
KRB5_NT_SRV_XHST - principal для каталогов X500 с SPN вида http/О=habr/OU=Servers/CN=myproxy/@REALM В жизни не встречается.

[- /] kvno : Override Key Version Number. Default: query DC for kvno. Use /kvno 1 for Win2K compat.

-kvno 4
Задать key version number, не принимая во внимание значение атрибута msDS-KeyVersionNumber. Без использования параметра -mapuser значение kvno по умолчанию равно 1. Необходим для offline генерации keytab, или вы можете сначала сгенерировать keytab для нового пароля с KVNO +1, дополнить keytab на сервере, и только потом сменить пароль в AD.

[- +] Answer : +Answer answers YES to prompts. -Answer answers NO.
Подавление интерактивного запроса ответа.
+answer
Согласиться. Актуально для сброса паролей компьютера.
-answer
Отказаться.

[- /] Target : Which DC to use. Default:detect
-target my-dc01
При обращении к AD использовать контроллер my-dc01. Полезно, если администрируемый сервис находится на удаленной площадке, и вы хотите избежать задержки репликации.

[- /] RawSalt : raw salt to use when generating key (not needed)

-rawsalt HABR.TESTsvc-proxy
При генерации ключей использовать соль HABR.TESTsvc-proxy.
Используется только для ключей группы AES. Алгоритм RC4-HMAC-NT не использует соль, а для группы DES используется фиксированная соль <REALM><upn>, для DES значение соли будет проигнорировано.

Очень важный параметр, из разбора которого появилась эта статья. Важно, чтобы ключи AD и keytab использовали одну соль. Замечено, что при задании соли утилита ktpass может "глючить" с параметром -crypto all. Поэтому при использовании -rawsalt, в параметре -crypto нужно задать протокол группы AES.

[- +] DumpSalt : show us the MIT salt being used to generate the key

-dumpsalt
Подавляет вывод значения соли в консоль.
+dumpsalt
Выводит использованную при генерации AES ключа соль, либо заданную параметром -rawsalt, либо использованную по умолчанию для MIT Kerberos.

[- +] SetUpn : Set the UPN in addition to the SPN. Default DO.
Критически важный параметр, так как UPN влияет на вход в систему, на него выдается TGT. Так же для пользовательских учетных записей влияет на используемую соль для ключей AES.
+setupn
Установить UPN равный значению -princ.
-setupn
Не менять UPN.

[- +] SetPass : Set the user's password if supplied.
+setpass
Установить пароль учетной записи в AD пароль, заданный в параметрах -pass, +rndpass. Увеличивает KVNO.
-setpass
Не менять пароль учетной записи. Приводит к генерации нерабочего keytab при совместном использовании с +rndpass.

Разбор алгоритмов шифрования Kerberos, поддерживаемых ktpass

Предупреждение

Я не криптограф и не имею практических навыков в реализации криптографических алгоритмов. Текст ниже - результат чтения wikipedia, https://datatracker.ietf.org/doc/html/rfc4757 и объяснений нейросетей.

Билеты Kerberos зашифрованы ключом, при это для зашифрованного или расшифрованного текста так же вычисляется подпись и/или хеш. Последнее важно потому, что, например в AES, не зная ключа, можно скомбинировать зашифрованный текст из нескольких блоков, и успешно изменить расшифрованное содержимое, подменив, допустим, время жизни билета.

AES256-CTS-HMAC-SHA1-96, AES128-CTS-HMAC-SHA1-96
Для шифрования билета используется алгоритм AES с ключом 256 или 128 бит в режиме CTS.
Для хеша билета используются 96 bit хеша SHA1 зашифрованного сообщения.
Подпись сформирована алгоритмом HMAC.

Ключа шифрования формируется из трёх компонентов:
Ключ = (Пароль пользователя + Соль ) * число итераций (параметр IterCount ktpass)
Изменение любого из трех параметров приводит к формированию различных криптографических ключей.

DES-CBC-CRC, DES-CBC-MD5

Для шифрования билета используется DES с ключом 56bit в режиме CBC.
Для хеша билета используется MD5 или CRC от текста до шифрования.
Из-за низкой криптографической стойкости в настоящий момент эти алгоритмы не используются.

Соль является фиксированной - <REALM><upn>, например HABR.TESTsvc-proxy. Задать другую соль нельзя.

RC4-HMAC-NT

Достаточно часто используемый алгоритм в системах Windows, от которого Microsoft с переменным успехом старается избавиться, как и от NTLM. Так же известен под именем RC4-HMAC-MD5.

Для шифрования билета используется RC4 с ключом в 128bit.
Из-за того, что RC4 является торговой маркой RSA Security, в open source реализациях этот же алгоритм имеет название "arcfour".
Для хеша билета используется MD5 от зашифрованного билета.
Подпись сформирована алгоритмом HMAC.

Ключом шифрования является NTLM хэш пароля. Соль не используется. Поскольку длина хеша NTLM составляет 128 bit, это позволяет использовать его в RC4 без преобразований.

Процитируем RFC:

RFC 4757

RFC 4757

Здесь особенно тонко ощущается безопасность. Получается, что получив NTLM хеш, можно использовать его без расшифровки для аутентификации Kerberos. Взяв хэш из keytab для учетной записи с несложным паролем типа "p@ssw0rd111", вы его за секунду восстановите в plain text, например на этом сайте NTLM.PW - Hash to password lookup.

Подведём итог - никогда не используйте простые пароли и алгоритм RC4-HMAC-NT.

Как используется соль в ключах Kerberos

Сведем одну таблицу то, что мы знаем об использовании соли в ключах Kerberos:

Алгоритм

Использование соли в ключе

Поддержка параметра
-rawsalt

AES256-CTS-HMAC-SHA1-96

Да

Да

AES128-CTS-HMAC-SHA1-96

Да

Да

DES-CBC-CRC

Да

Нет

DES-CBC-MD5

Да

Нет

RC4-HMAC-NT

Нет

Нет

Если отбросить устаревшие алгоритмы DES, из трех актуальных используемых алгоритмов только RC4-HMAC-NT не чувствителен к значению соли. Что бы вы не указали в параметрах ktpass, вы всегда получите корректные ключи для RC4-HMAC-NT.

Но верно ли это утверждение для ключей AES? И именно здесь начинаются нюансы.

Для примера, посмотрим как компания Kaspersky рекомендует формировать keytab файлы для одного из своих продуктов:

Например, вам нужно создать keytab-файл, содержащий SPN-имена 3 узлов: control-01.test.localsecondary-01.test.local и secondary-02.test.local.

Чтобы создать в папке C:\keytabs\ файл под названием filename1.keytab, содержащий SPN Управляющего узла, требуется выполнить команду:

C:\Windows\system32\ktpass.exe -princ HTTP/control-01.test.local@TEST.LOCAL -mapuser control-user@TEST.LOCAL -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL -pass * +dumpsalt -out C:\keytabs\filename1.keytab

Допустим, вы получили соль "TEST.LOCALHTTPcontrol-01.test.local".

Для добавления еще одного SPN необходимо выполнить следующую команду:

C:\Windows\system32\ktpass.exe -princ HTTP/secondary-01.test.local@TEST.LOCAL -mapuser control-user@TEST.LOCAL -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL -pass * -in C:\keytabs\filename1.keytab -out C:\keytabs\filename2.keytab -setupn -setpass -rawsalt "TEST.LOCALHTTPcontrol-01.test.local"

Для добавления третьего SPN необходимо выполнить следующую команду:

C:\Windows\system32\ktpass.exe -princ HTTP/secondary-02.test.local@TEST.LOCAL -mapuser control-user@TEST.LOCAL -crypto AES256-SHA1 -ptype KRB5_NT_PRINCIPAL -pass * -in C:\keytabs\filename2.keytab -out C:\keytabs\filename3.keytab -setupn -setpass -rawsalt "TEST.LOCALHTTPcontrol-01.test.local"

В результате будет создан файл с именем filename3.keytab, содержащий все три добавленные SPN.

Выполнив эти действия точь-в-точь, вы действительно получите рабочий файл.
Но стоит вам:
- в первой команде использовать параметр -setupn
- удалить -setupn из второй и третьей команды
... и вы получите нерабочие ключи.

А для учетной записи компьютера вы получите нерабочие ключи в случае несовпадения REALM у SPN и компьютера.

Но если вы установите -crypto all и при этом, по желанию, уберете -rawsalt то всё вполне может заработать.

В чём здесь соль? Вот сейчас и разберемся.

Предупреждение

Многие дальнейшие выводы сделаны в результате наблюдения за изменениями в базе Active Directory ntds.dit с набором командлетов DSInternals.

Логично, что ключи шифрования Kerberos в Active Directory и в keytab должны совпадать.

Active Directory хранит готовые Kerberos ключи в зашифрованном атрибуте SupplementalCredentials (кроме RC4-HMAC-NT, этот ключ просто берется из атрибута LM Hash). SupplementalCredentials недоступен ни для чтения, ни для записи. Но для анализа его значение можно получить командлетами DSInternals.

Важно - в одной учетной записи AD есть ровно по одному ключу на каждый алгоритм шифрования (если не принимать во внимание историю ключей), а не как в keytab, по отдельному ключу на SPN. Если вы использовали ktpass с параметром -in, чтобы добавить в keytab ещё один SPN, и получили в выводе консоли другие значения ключей AES - Хьюстон, у вас проблемы. Либо первый набор не рабочий, либо второй. Какой - скоро поймете.

А почему вы получили разные ключи? Да потому что для другого SPN утилита ktpass.exe использовала другую соль.

Еще раз повторим, что в RC4-HMAC-NT ключом является не зависящий от соли хэш LM, запомним этот факт и вернемся к нему в самом конце.

Давайте разберемся, как формируется соль, совместимая с MIT Kerberos утилитой ktpass.exe

ktpass.exe -setupn +rndpass +setpass +dumpsalt -crypto AES256-SHA1 -princ "HTTP/proxy01.habr.test@HABR.TEST" /mapuser test@HABR.TEST -ptype KRB5_NT_PRINCIPAL -out krb5.keytab

Building salt with principalname HTTP/proxy01.habr.test and domain HABR.TEST (encryption type 18)
Hashing password with salt "HABR.TESTHTTPproxy01.habr.test".

Principal Name? Но для нас это ведь service principal name, не user principal name (test@HABR.TEST)

Давайте поменяем REALM для SPN

ktpass.exe -setupn +rndpass +setpass +dumpsalt -crypto AES256-SHA1 -princ "HTTP/proxy01.habr.test@HABR.COM" /mapuser test@habr.test -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Building salt with principalname HTTP/proxy01.habr.test and domain HABR.COM (encryption type 18)...
Hashing password with salt "HABR.COMHTTPproxy01.habr.test".

Проверим на чувствительность к регистру, и заодно зафиксируем пароль (на будущее)

ktpass.exe -setupn -pass "p@ssw0rd" +dumpsalt -crypto AES256-SHA1 -princ "HttP/PROxy01.habT.Test@HaBR.CoM" /mapuser test@habr.test -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Building salt with principalname HttP/PROxy01.habT.Test and domain HaBR.CoM (encryption type 18)...
Hashing password with salt "HaBR.CoMHttPPROxy01.habT.Test".
keysize 82 HttP/PROxy01.habT.Test@HaBR.CoM ptype 1 (KRB5_NT_PRINCIPAL) vno 7 etype 0x12 (AES256-SHA1) keylength 32 (0xca56f717be5c5db881af3db90710019010880a941c5e8f1b7adabc15d1a517a0)

Делаем вывод, что соль формируется по следующему правилу:

<princ REALM><princ SERVICE><princ fqdn>

При этом регистр совпадает с регистром значения ключа /princ.

Заглянем в Active Directory и сравним ключи:

Ключ другой. Но обратите внимание, что в AD и другая соль! Давайте повторим генерацию с солью из AD:

ktpass.exe -setupn -pass "p@ssw0rd" +dumpsalt -rawsalt "HABR.TESTtest" -crypto AES256-SHA1 -princ "HttP/PROxy01.habT.Test@HaBR.CoM" /mapuser test@habr.test -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Using supplied salt.
Hashing password with salt "HABR.TESTtest".
keysize 82 HttP/PROxy01.habT.Test@HaBR.CoM ptype 1 (KRB5_NT_PRINCIPAL) vno 8 etype 0x12 (AES256-SHA1) keylength 32 (0xcc51a06d24dd0726da1092434caf05f2dce7af05f27c828ebafb9542631528ab)

Теперь ключ совпал.

Почему же ktpass.exe сгенерировала нерабочий ключ?
Всё дело в том, что ktpass в некоторых случаях неправильно формирует соль. В Active Directory соль формируется в соответствии с RFC 4120:

The default salt string, if none is provided via pre-authentication data, is the concatenation of the principal's realm and name components, in order, with no separators.

На практике это значит:

User:
<REALM><UserLogonName>
Соль меняется при смене UPN. AD всегда приводит значение UserLogonName к нижнему регистру.
Computer:
<REALM>host<fqdn>
Соль не меняется при смене UPN.

Вспомним, что ktpass в качестве соли использует SPN из ключа -princ. Таким образом, правильная соль формируется при одновременном соблюдении следующих условий:
- SPN строго, с соблюдением регистра задан в формате <SERVICE>/fqdn@<REALM>
- не используется ключ -setupn, и в результате UPN пользователя совпадает с SPN
- REALM SPN совпадает с REALM UPN

Давайте используем этот принцип на практике:

ktpass.exe -pass "p@ssw0rd" +dumpsalt  -crypto AES256-SHA1 -princ "HTTP/proxy01.habr.test@HABR.TEST" /mapuser test@habr.test -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Hashing password with salt "HABR.TESTHTTPproxy01.habr.test".
keysize 83 HTTP/proxy01.habr.test@HABR.TEST ptype 1 (KRB5_NT_PRINCIPAL) vno 9 etype 0x12 (AES256-SHA1) keylength 32 (0xbf5c40efe907d70a2f3e0956edb4b1dbe9166d4d7436c5eab89ad86493aa98ac)

В AD:

Ключ совпал. А что произошло с учетной записью?

UPN изменился на заданный SPN. Теперь для интерактивного входа в систему необходимо использовать имя пользователя "HTTP/proxy01.habr.test". Сомнительно, но ОК. )

А что если у учетной записи несколько SPN? SPN много, а UPN - один.
Поэтому, добавляя новые SPN в keytab важно:
- при добавлении первого SPN указать +setupn (или опустить его, что приведет к такому же результату)
- при добавлении следующих SPN не менять UPN, то есть обязательно использовать ключ -setupn, а в качестве -rawsalt указывать соль из первого SPN

Альтернативный вариант, если вы не хотите менять UPN - при добавлении первого и последующих SPN указывать -setupn, а в качестве -rawsalt задать значение <REALM><UserLogonName>

Вернемся к примеру Kaspersky. Они в точности следуют первому варианту. Но теперь вы знаете, что происходит "под капотом".

Зачем вообще делать UPN совпадающий с SPN? Формируя keytab таким образом, вы убиваете двух зайцев: с помощью одной записи вы можете как расшифровывать билеты, так и аутентифицироваться в домене (запрашивать TGT). В противном случае нам бы понадобилась вторая запись с principal name <username>@<REALM> (test@HABR.TEST или testpc$@HABR.TEST).

В каких случаях получается некорректный keytab файл, если вместо учетной записи пользователя использовать компьютер?

ktpass.exe -pass "p@ssw0rd" +dumpsalt  -crypto AES256-SHA1 -princ "HTTP/proxy01.habr.test@HABR.TEST" /mapuser HABR\testpc -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Hashing password with salt "HABR.TESThosttestpc.habr.test".
keysize 83 HTTP/proxy01.habr.test@HABR.TEST ptype 1 (KRB5_NT_PRINCIPAL) vno 3 etype 0x12 (AES256-SHA1) keylength 32 (0x9875a93d1094abc1c7e57e4d2af72b11d3a272c9ac10225dc3474600ab2c50eb)

Обратите внимание на формат соли. Как упоминалось выше, для компьютеров де-факто используется формат <REALM>host<fqdn>.

Ключи совпали. Отлично!

Но стоит вам..
Поменять REALM SPN

C:\Scripts>ktpass.exe +setpass -pass "p@ssw0rd" +dumpsalt +answer -crypto AES256-SHA1 -princ "HTTP/proxy01.habr.test@HABR.COM" /mapuser HABR\testpc$ -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Hashing password with salt "HABR.COMhosttestpc.habr.com".
keysize 82 HTTP/proxy01.habr.test@HABR.COM ptype 1 (KRB5_NT_PRINCIPAL) vno 5 etype 0x12 (AES256-SHA1) keylength 32 (0xc52d1e33b2c835634ae98565564681b37cfcf2c57cdb7a3f4bb0c5a82c223c54)

или указать REALM в другом регистре

ktpass.exe +setpass -pass "p@ssw0rd" +dumpsalt +answer -crypto AES256-SHA1 -princ "HTTP/proxy01.habr.test@habr.test" /mapuser HABR\testpc$ -ptype KRB5_NT_PRINCIPAL -out krb5.keytab
Hashing password with salt "habr.testhosttestpc.habr.test".
keysize 83 HTTP/proxy01.habr.test@habr.test ptype 1 (KRB5_NT_PRINCIPAL) vno 7 etype 0x12 (AES256-SHA1) keylength 32 (0x5d5984448ad60c5808e1a20442bb12824edcaea9f89abaeb77a1d257676557a1)

как будет сформирован некорректный ключ.

Почему же некоторых случаях всё сделано не так, но всё работает? Всё дело в согласовании протокола шифрования. Если согласовался RC4-HMAC-NT, всё и так заработает.

Так мы переходим к следующей теме.

Как согласуется протокол шифрования Kerberos

Выбор протокола шифрования зависит от протоколов, поддерживаемых клиентом и значения атрибута msDS-SupportedEncryptionTypes в свойствах учетной записи пользователя или компьютера.

Для пользователя
При создании пользователя значение атрибута msDS-SupportedEncryptionTypes = 0
В этом случае единственный доступный протокол - RC4-HMAC-NT.

После установки галочек:

атрибут принимает значение 24 и будет согласован наиболее стойкий алгоритм.

Для компьютера
При создании компьютера значение атрибута msDS-SupportedEncryptionTypes = 0
До обновления November 8, 2022 это ограничивало использование AES на учетных записях компьютеров, созданных вручную и не введенных в домен (например Linux).
После обновления, у контроллеров домена появилась возможность игнорировать значение атрибута компьютера и согласовывать более современные протоколы.

Также заслуживает прочтение следующая статья: Linux accounts cannot get AES tickets - Windows Server | Microsoft Learn

После ввода компьютера в домена атрибут как правило принимает значение 24 и согласуется наиболее стойкий алгоритм.
Заметим, что последней из версий Windows, которая не поддерживала AES-SHA1, была Windows Server 2003.

На примере.
Клиент в запросе перечислил поддерживаемые алгоритмы:

Сервер вернул билет:

Роль KVNO в строке keytab

Атрибут KVNO (key version number) увеличивается на единицу при каждом изменении пароля учетной записи. В AD его значение хранится в атрибуте msDS-KeyVersionNumber. При выдаче билета, KDC указывает и номер KVNO:

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

Простое правило - номер KVNO в keytab должен соответствовать номеру msDS-KeyVersionNumber в AD.
В keytab могут храниться записи и для старых KVNO, они обеспечивают расшифровку билетов выданных KDC с задержкой репликации.
Аналогично ведет себя и Active Directory, сохраняя историю трех последних ключей.

Поэтому когда говорят, что пароль учетной записи krbtgt надо сбрасывать два раза, возможно это упрощение, и речь идет не о пароле, а о смене ключей Kerberos, которые рассчитываются из пароля.

Как сверить значение ключей в AD и в keytab

Для этого нам понадобится модуль PowerShell DSInternals.

Установите его любым удобным для вас способом по инструкции из README (например, распаковав в каталог C:\Windows\system32\WindowsPowerShell\v1.0\Modules\DSInternals).
После этого на контроллере домена создайте набор Install From Media.

ntdsutil
activate instance ntds
ifm
create full c:\temp

Сохраните ключ шифрования защищенных атрибутов

$key = Get-BootKey C:\Temp\registry\SYSTEM

Посмотрите значение ключей учетной записи

Get-ADDBAccount -SamAccountName test -DatabasePath 'C:\Temp\Active Directory\ntds.dit' -BootKey $key

Итог

Для алгоритмов AES утилита ktpass формирует правильную соль только в том случае, если синтаксис параметра -princ соответствует RFC, а UPN устанавливается равным SPN. При генерации записей для следующих SPN необходимо использовать соль от первого (UPN) и ключ -setupn.

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

Примечание для старой гвардии

Если вы ожидали срывов покровов и ТЗ (тайного знания) - надеюсь, что не разочаровал.

Если дочитали или пролистали до этой строки - вы человек железной выдержки.