Аутентификация в распределенных системах схема kerberos применение схемы kerberos в доменах windows

Киберпреступность — это печальная реальность современности, затрагивающая как частных пользователей, так и бизнес. Ни одна компания или организация не застрахована, и ситуация вряд ли улучшится в ближайшее время. Эксперты прогнозируют, что убытки от киберпреступлений достигнут $25 трлн к 2025 году. Forbes также предупреждает об увеличении угроз для мобильных устройств.

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

В этой статье мы рассмотрим протокол аутентификации Kerberos и узнаем, как он работает.

Что такое Kerberos?

Kerberos — это протокол безопасности компьютерных сетей, который аутентифицирует запросы между двумя или несколькими доверенными хостами в ненадежной сети, такой как интернет. Разработанный MIT для проекта Athena в конце 1980-х, он теперь используется по умолчанию в Microsoft Windows и реализован в других операционных системах, таких как Apple OS, FreeBSD, UNIX и Linux.

Как работает Kerberos

Kerberos использует криптографию с секретным ключом и доверенное третье лицо — Центр Распределения Ключей (KDC) — для аутентификации клиент-серверных приложений и проверки идентичности пользователей. KDC предоставляет услуги аутентификации и выдачи билетов, которые обеспечивают безопасную проверку идентичности, защищая от прослушивания и повторных атак.

Для чего используется Kerberos

Kerberos широко применяется в цифровом мире, особенно в системах, требующих надежного аудита и аутентификации. Он используется в аутентификации Posix, Active Directory, NFS и Samba, а также как альтернатива системам аутентификации SSH, POP и SMTP.

Основные применения Kerberos

Единый вход (SSO). Kerberos позволяет пользователям аутентифицироваться один раз и получить билет, известный как Kerberos ticket-granting ticket (TGT). Этот TGT можно использовать для запроса билетов на доступ к различным ресурсам без повторного ввода учетных данных, что упрощает работу пользователей и снижает необходимость управления множеством паролей.

Сетевая аутентификация. Kerberos предоставляет безопасный механизм для проверки подлинности сетевых служб, таких как серверы и приложения. Клиенты могут запросить билет на службу у Центра Распределения Ключей (KDC) с использованием своего TGT, а этот билет используется для аутентификации и установления защищенной сессии с запрашиваемой службой.

Взаимная аутентификация. Kerberos обеспечивает взаимную аутентификацию, что означает, что и клиент, и сервер аутентифицируют друг друга в процессе начальной аутентификации. Это предотвращает impersonation и атаки «человек посередине» путем проверки подлинности обеих сторон в коммуникации.

Авторизация. Kerberos также может использоваться для реализации политик контроля доступа. После аутентификации клиента Kerberos билет содержит информацию о его идентичности и правах доступа. Серверы могут использовать эту информацию для применения правил авторизации и предоставления или отказа в доступе к конкретным ресурсам в зависимости от привилегий клиента.

Что делает протокол аутентификации Kerberos?

MIT разработал протокол для проекта под названием Athena. Название происходит от трехголового пса Адеса из греческой мифологии, который охранял ад. Имя было выбрано, потому что протокол Kerberos представляет собой три компонента:

  • Клиент
  • Сетевой ресурс (сервер приложений)
  • Центр распределения ключей (KDC)

Эти три компонента позволяют Kerberos обеспечивать аутентификацию доверенных хостов в ненадежных сетях. Kerberos гарантирует, что доступ к сетевым ресурсам имеют только авторизованные пользователи. Также он обеспечивает AAA безопасность: Аутентификацию, Авторизацию и Учет.

Разработчики MIT создали Kerberos для безопасной аутентификации к требуемым системам и авторизации пользователей. В то время большинство систем передавали незашифрованные пароли, что позволяло хакерам получить несанкционированный доступ. Поэтому разработка Kerberos была необходима.

Проектом занимались S.P. Miller, B.C. Neuman, J.I. Schiller и J.H. Saltzer.

В Kerberos KDC выдает билеты, которые позволяют различным хостам подтверждать свою личность. Также разработчики предусмотрели, что аутентификация Kerberos поддерживает авторизацию. Это значит, что клиент, аутентифицированный Kerberos, также получает доступ к ресурсам.

Преимущества аутентификации Kerberos

Kerberos приносит множество преимуществ в любую настройку кибербезопасности:

  • Эффективный контроль доступа. Kerberos позволяет пользователям отслеживать входы и применять политику безопасности через единую точку.
  • Ограниченный срок действия ключевых билетов. Каждый билет Kerberos имеет метку времени, данные о сроке действия и продолжительность аутентификации, контролируемую администратором.
  • Взаимная аутентификация. Системы и пользователи могут аутентифицировать друг друга.
  • Повторное использование аутентификации. Аутентификация пользователей Kerberos повторно используется и долговечна; каждый пользователь должен быть проверен системой только один раз. Пока билет действителен, пользователю не нужно повторно вводить свои данные для аутентификации.
  • Сильные и разнообразные меры безопасности. Протоколы безопасности Kerberos используют криптографию, несколько секретных ключей и авторизацию третьих сторон, создавая надежную защиту. Пароли не передаются по сетям, и все секретные ключи зашифрованы.

Как работают протоколы аутентификации Kerberos?

Ниже представлена упрощенная схема работы протоколов аутентификации Kerberos:

  1. Запрос к серверу аутентификации. Клиент запрашивает аутентификацию у KDC. Этот запрос передается в открытом виде.
  2. Ответ сервера аутентификации. KDC отправляет TGT и сеансовый ключ, если клиент есть в базе данных. Если клиента нет в базе, аутентификация не проходит.
  3. Запрос билета на службу. Клиент запрашивает билет на службу вместе с TGT, выданным ранее KDC.
  4. Ответ на запрос билета. KDC отправляет билет, зашифрованный сеансовым ключом. Клиент может использовать сеансовый ключ, отправленный ранее KDC, для расшифровки билета на службу.
  5. Запрос к серверу приложений. Клиент запрашивает доступ к серверу приложений, используя билет на службу.
  6. Ответ сервера приложений: Сервер приложений аутентифицирует клиента и отправляет билет, который предоставляет доступ к конкретной услуге.

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

Обзор потока протокола Kerberos

Давайте подробнее рассмотрим, что такое аутентификация Kerberos, и разберем, как она работает, разделив ее на основные компоненты.

Основные участники типичного процесса Kerberos:

  • Клиент действует от имени пользователя и инициирует запрос на услугу.
  • Сервер предоставляет услугу, к которой пользователь хочет получить доступ.
  • Сервер аутентификации (AS) выполняет аутентификацию клиента. Если аутентификация успешна, AS выдает клиенту билет, называемый TGT (Ticket Granting Ticket). Этот билет подтверждает другим серверам, что клиент аутентифицирован.
  • Центр распределения ключей (KDC): в среде Kerberos сервер аутентификации логически разделен на три части: базу данных (db), сервер аутентификации (AS) и сервер выдачи билетов (TGS). Эти три части объединены в одном сервере, называемом Центром распределения ключей (KDC).
  • Сервер выдачи билетов (TGS) — это сервер приложений, который выдает билеты на услуги.

Теперь разберем процесс протокола.

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

  • Ключ клиента/пользователя: хэш, полученный из пароля пользователя.
  • Секретный ключ TGS: хэш пароля, использованный для определения TGS.
  • Секретный ключ сервера: хэш пароля, использованный для определения сервера, предоставляющего услугу.

Процесс протокола включает следующие шаги:

Шаг 1. Начальный запрос аутентификации клиента: Пользователь запрашивает у сервера аутентификации (AS) билет TGT. Этот запрос включает идентификатор клиента.

Шаг 2. KDC проверяет учетные данные клиента. AS проверяет базу данных на наличие клиента и доступность TGS. Если AS находит оба значения, он генерирует секретный ключ клиента/пользователя, используя хэш пароля пользователя.

AS затем вычисляет секретный ключ TGS и создает сеансовый ключ (SK1), зашифрованный секретным ключом клиента/пользователя. AS генерирует TGT, содержащий идентификатор клиента, сетевой адрес клиента, метку времени, срок действия и SK1. Тicket TGS секретный ключ затем шифрует билет.

Шаг 3. Клиент расшифровывает сообщение. Клиент использует секретный ключ клиента/пользователя для расшифровки сообщения и извлечения SK1 и TGT, создавая аутентификатор, который подтверждает клиента TGS.

Шаг 4. Клиент использует TGT для запроса доступа. Клиент запрашивает билет у сервера, предоставляющего услугу, отправляя извлеченный TGT и созданный аутентификатор в TGS.

Шаг 5. KDC создает билет для файлового сервера. TGS использует секретный ключ TGS для расшифровки TGT, полученного от клиента, и извлечения SK1. TGS расшифровывает аутентификатор и проверяет, соответствует ли он идентификатору клиента и сетевому адресу клиента. TGS также проверяет метку времени, чтобы убедиться, что TGT не истек.

Если все проверки пройдены успешно, KDC генерирует сеансовый ключ услуги (SK2), который делится между клиентом и целевым сервером.

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

Шаг 6. Клиент использует билет услуги для аутентификации. Клиент расшифровывает сообщение с помощью SK1 и извлекает SK2. Этот процесс создает новый аутентификатор, содержащий сетевой адрес клиента, идентификатор клиента и метку времени, зашифрованный с помощью SK2, и отправляет его вместе с билетом услуги на целевой сервер.

Шаг 7. Целевой сервер принимает расшифровку и аутентификацию. Целевой сервер использует секретный ключ сервера для расшифровки билета услуги и извлечения SK2. Сервер использует SK2 для расшифровки аутентификатора, проверяя, совпадают ли идентификатор клиента и сетевой адрес клиента из аутентификатора и билета услуги. Сервер также проверяет билет услуги на предмет его истечения.

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

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

Понятия и термины объектов Kerberos

Большинство целей Kerberos связаны с управлением паролями. Он обеспечивает, чтобы пароли не передавались по сети и не хранились на клиентских системах; система удаляет их сразу после использования. Пароли не должны храниться в открытом виде, и каждая сессия должна использовать только один пароль.

Кроме того, вся информация об аутентификации хранится на централизованном сервере, что означает:

  • Администратор может ограничить доступ любого клиента из централизованного сервера.
  • Один пароль пользователя может обеспечить доступ ко всем службам.
  • Защита информации пользователя становится менее сложной, так как нужно защищать только один сервер.
  • В Kerberos все сущности должны аутентифицироваться друг у друга по запросу.

Следующие сущности используют протоколы Kerberos:

  • Принципы Kerberos — это уникальный идентификатор, назначаемый билету. Для большинства пользователей это тот же идентификатор, что и имя пользователя. Kerberos идентифицирует принципала по следующей информации:
    • Для пользователей: это имя пользователя; для хостов: слово «host». Для служб принципал — это название службы.
    • Дополнительный идентификатор, указывающий имя хоста.
    • Имя области Kerberos, в которой работает сервер Kerberos.
  • Серверы приложений Kerberos предоставляют доступ к ресурсам, которые нужны клиентам.
  • KDC Kerberos предоставляет доступ к ресурсам, таким как эмуляция терминалов и удаленные вычисления.
  • База данных Kerberos содержит записи о каждом принципале. Это централизованное хранилище Kerberos, содержащее идентификацию клиентов и их доступ.
  • Служба аутентификации Kerberos выдает билет TGT (Ticket Granting Ticket) клиентам.
  • Служба выдачи билетов Kerberos аутентифицирует клиентов на основе TGT.

После аутентификации пользователь получает билет аутентификации. Клиент может использовать этот билет для получения билетов на доступ к сервисам приложений.

Kerberos против других протоколов аутентификации сети

Существуют и другие протоколы аутентификации помимо Kerberos. Рассмотрим их:

  • Kerberos vs. Microsoft New Technology LAN Manager (NTLM): NTLM был предыдущей технологией, используемой Windows. С Windows 2000 все версии используют Kerberos. NTLM использует аутентификацию по принципу вызова-ответа: сервер задает вопрос, на который клиент должен ответить.
  • Kerberos vs. Lightweight Directory Access Protocol (LDAP): LDAP позволяет поддерживать информацию о пользователях. LDAP и Kerberos могут использоваться в одной сети: LDAP предоставляет службу авторизации, а Kerberos — аутентификацию.
  • Kerberos vs. Remote Authentication Dial-in User Service (RADIUS): RADIUS был предназначен для удаленного доступа пользователей через модемные соединения. Однако сетевые службы используют его для учета и аутентификации наряду с Kerberos.

Является ли Kerberos безопасным?

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

Специалисты по безопасности по всему миру считают Kerberos безопасным. Он использует сильное шифрование для защиты данных. Тем не менее, исследователи безопасности обнаружили несколько способов обхода Kerberos:

  • Атака «Pass-the-key»: хакеры подделывают клиентов, используя их учетные данные.
  • Атака «Pass-the-ticket»: хакеры используют билет, когда KDC отправляет сеансовый билет.
  • Атака «Golden ticket»:  хакеры используют контроллеры домена Windows для создания учетных данных клиента.

Может ли Kerberos быть взломан?

Ни одна мера безопасности не является на 100% неприступной, и Kerberos не является исключением. Поскольку он существует уже долго, хакеры имели возможность найти способы обойти его, обычно подделывая билеты, делая повторные попытки угадывания паролей (грубая сила/наполнение учетных данных) и используя вредоносное ПО для понижения уровня шифрования.

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

Является ли Kerberos устаревшей системой?

Долговечность не обязательно означает устаревание. Несмотря на некоторые случаи, когда киберпреступники обходили Kerberos (и мы уже установили, что ни одна система безопасности не является на 100% неприступной), Kerberos по-прежнему активно используется и пользуется хорошей репутацией.

Часто задаваемые вопросы

Что такое Kerberos и как он работает? 

Kerberos — это протокол сетевой аутентификации, который обеспечивает безопасную аутентификацию в распределенных вычислительных средах. Он использует доверенную третью сторону, называемую Центром распределения ключей (KDC), для аутентификации клиентов и серверов. KDC выдает билеты, которые подтверждают личность клиентов и серверов, позволяя безопасное общение и предотвращая несанкционированный доступ.

Как применяется Kerberos? 

Один из примеров применения Kerberos — это система аутентификации, используемая в Microsoft Active Directory. Kerberos является основным протоколом для аутентификации в доменах Windows, позволяя пользователям безопасно получать доступ к сетевым ресурсам и службам.

Какие преимущества есть у Kerberos? 

Некоторые преимущества использования Kerberos для аутентификации включают:

  • Сильная безопасность. Kerberos использует шифрование и взаимную аутентификацию для обеспечения целостности и конфиденциальности обмена аутентификацией.
  • Единая точка входа. После аутентификации пользователи могут получить доступ к нескольким службам и ресурсам без повторного ввода учетных данных, что повышает удобство и продуктивность.
  • Централизованная аутентификация. Kerberos предоставляет централизованную систему аутентификации, уменьшая необходимость в управлении отдельными учетными данными для каждой службы или системы.
  • Масштабируемость. Kerberos может обрабатывать крупные масштабные среды и поддерживает эффективную аутентификацию для большого количества пользователей и служб.

В чем разница между Kerberos и KDC? 

Kerberos относится к самому протоколу сетевой аутентификации, тогда как KDC (Key Distribution Center) представляет собой централизованный сервер, который реализует протокол Kerberos. Он состоит из двух основных компонентов: Службы аутентификации (AS) и Службы выдачи билетов (TGS). AS отвечает за начальную аутентификацию и выдачу билетов TGT (Ticket-Granting Tickets), в то время как TGS выдает билеты на доступ к конкретным службам. В общем, Kerberos — это протокол, а KDC — серверная реализация этого протокола.

Вступление

На мой взгляд специалисту по тестированию на проникновение инфраструктуры на базе Active Directory важно понимать общее устройство протокола Kerberos. Вот лишь несколько причин почему:

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

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

В этом цикле статей буду пытаться разобрать, как в теории устроен протокол Kerberos и какие атаки с его использованием можно осуществить на практике в Active Directory. Также будут приведены некоторые рекомендации по противодействию рассматриваемым атакам.

В первой части будет рассмотрено устройство Kerberos в общем случае, а также реализация Kerberos в Active Directory.

К материалу не стоит относится как к истине в последней инстанции. Только дураки не сомневаются.

Экскурс. Краткий и исторический

Протокол Kerberos был разработан в MIT, как часть научно-исследовательского проекта Афина, предназначенного для создания распределенной образовательной среды. К 1988 году проект достиг поставленных целей. В частности, было опубликовано описание протокола Kerberos v4, являющегося основой системы единого входа в разработанную среду. Предыдущие версии 1-3 были ранними прототипами и не использовались за пределами MIT.

В 1989 году состоялся официальный релиз Kerberos v4.

Однако протоколу было куда развиваться. Например, можно выделить следующие недостатки Kerberos v4:

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

C целью устранения приведенных недостатков в 1993 году вышел новый протокол Kerberos v5.

В 1999 году Microsoft объявила о поддержке Kerberos v5 в своей будущей операционной системе Windows 2000, что было впоследствии реализовано в качестве соответствующего компонента Active Directory. До этого для аутентификации в рабочих группах на базе операционной системы Windows использовался протокол NT LAN Manager (NTLM), одна из версий которого (NTLM v2) применяется для локальной аутентификации в современных системах до сих пор. Подробное рассмотрение протокола NTLM v2 выходит за рамки статьи. Важно отметить, что указанный протокол также обладает рядом недостатков, которые было решено избежать при внедрении Kerberos v5 в Windows 2000.

В настоящее время Kerberos v5 можно считать довольно возрастным протоколом, тем не менее он используется во множестве различных систем, а не только в Active Directory. Вот неполный перечень:

  • Amazon Web Services
  • Apple macOS
  • Google Cloud
  • Microsoft Azure
  • Oracle Solaris
  • Red Hat Linux

Всюду далее речь будет идти именно о Kerberos v5. Для читаемости Kerberos v5 будет называться просто Kerberos.

Разобраться с принципом работы протокола Kerberos поначалу не просто. Постоянно приходится перечитывать ранее изученный материал и держать в голове множество деталей. Периодически возникает вопрос: почему все так сложно устроено?

Чтобы корректно ответить на заданный вопрос и, что не менее важно, понять ответ, требуется обладать познаниями в устройстве криптографических протоколов, а также смежных дисциплинах. Полагаю, что копать настолько глубоко смысла нет. Все же чтобы понимать, чем обусловлены навороты Kerberos приведу ряд требований, которым протокол должен был отвечать:

  • Подразумевается, что обмен сообщений осуществляется с доверенных устройств, но в открытой недоверенной среде. Сетевой трафик может быть прослушан злоумышленником, а передаваемые сообщения могут быть подменены или перенаправлены. Таким образом секреты участников протокола ни при каких условиях не должны передаваться по сети в открытом виде.

    Любопытный факт: Kerberos разрабатывался до появления SSL.

  • Информация о пользователях и их секретах должна хранится в выделенном месте. Это ограничение обусловлено следующими соображениями:

    • Необходимо минимизировать количество критических объектов, которые требуется защищать.
    • Добавление нового, удаление старого, изменение текущего секрета у клиента или сервиса не должно требовать уведомления всех остальных участников протокола. Думаю, полезной будет следующая иллюстрация:
topology

Варианты сетей без и c выделенным доверенным центром

  • Должна поддерживаться технология единого входа (Single Sign-On). Это ограничение обусловлено тем, что пользователю неудобно каждый раз при обращении к ресурсу заново вводить пароль.
  • Успешное окончание работы протокола должно означать успешную взаимную аутентификацию сторон.
  • В результате работы протокола между клиентом и сервисом должен быть сформирован секретный сессионный ключ. Знание сессионного ключа позволяет злоумышленнику расшифровать некоторые старые сообщения, но организовать новую сессию с использованием уже известного сессионного ключа не получится.

Список терминов

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

Kerberos – в первую очередь протокол аутентификации, но при этом предусматривающий возможность транспортировки информации необходимой для авторизации.

Важно не путать:

Аутентификация – процесс проверки подлинности. То есть проверка того, что пользователь, пытающийся получить доступ к системе именно тот, за кого себя выдает.
Авторизация – процесс проверки прав доступа. Авторизация может быть применена только к аутентифицированному пользователю, так как перед тем, как проверять права доступа, необходимо выяснить личность объекта, которому указанные права планируется предоставить.

Сервер – сетевой объект, обеспечивающий функционирование одного или нескольких сервисов. Примеры серверов: файловый сервер, почтовый сервер.

Клиент – объект, обращающийся к сервису с целью получения доступа к ресурсам. Примеры клиентов: учетная запись или рабочая станция пользователя.

Область действия (Realm) – совокупность клиентов, серверов и сервисов, участвующих в протоколе Kerberos.

Принципал (Principal) – это строка, полностью идентифицирующая участника протокола Kerberos.

Принципал может быть именем сервиса (Service Principal Name), или именем клиента (User Principal Name). Форматы принципалов для клиентов и сервисов различаются.

Принципал клиента имеет следующую форму: principal-name[/instance-name]@REALM
Пример: имя пользователя — Ivan, а область действия - DOMAIN.LOCAL, то полный принципал будет Ivan@DOMAIN.LOCAL.

Расширение instance-name является опциональным и позволяет любому пользователю иметь более одного принципала. Так, если Ivan является администратором области DOMAIN.LOCAL, имя принципала будет Ivan/admin@DOMAIN.LOCAL, и у этого принципала будут другие права (и удостоверяющие данные).

Принципал сервиса имеет следующую форму:
service-name/host[:port]@REALM, где

  • service-name – это специфичная для приложения строка, идентифицирующая сервис на этом хосте.
  • host – это доменное имя хоста, на котором работает сервис
  • port — порт на котором запущена служба.

Пример: для сервиса ftp, работающего на хосте с именем fileserver.example.com в области @EXAMPLE.COM, имя принципала сервиса будет ftp/fileserver.example.com@EXAMPLE.COM.

Почему такое внимание уделяется этим именам? В дальнейшем будет понятнее, но уже сейчас можно отметить, что в Kerberos для идентификации сервера требуется именно принципал (имя), тогда как в NTLM может использоваться IP-адрес.

Примечание: возможность использования IP-адресов была добавлена в новых клиентах Windows.

Рассмотрим пример: есть рабочая станция (DNS-имя: station.domain.local,
IP-адрес: 192.168.10.12) с общедоступной сетевой папкой scan. При открытии проводника и переходу по UNC-пути \\station.domain.local\scan будет использоваться Kerberos, но при указании UNC-пути \\192.168.10.12\scan будет использоваться NTLM, так как принципал отсутствует. В частности, поэтому администраторы не любят отключать NTLM, так как устаревшее сетевое оборудование (принтеры, роутеры и пр.) может быть настроено со статическими IP-адресами или вовсе не поддерживать Kerberos.

Центр распределения ключей (Key Distribution Center, далее – KDC) является доверенным центром аутентификации для всех участников протокола Kerberos в рамках определенной области действия.

KDC включает в себя следующие компоненты:

  • База данных Kerberos, предназначенная для хранения информации о всех принципалах и их секретах.
  • Сервер аутентификации (Authentication Server, AS), обрабатывающий запросы на аутентификацию клиентов к области действия протокола Kerberos;
  • Сервер выдачи разрешений (Ticket Granting Server, TGS), обрабатывающий запросы на аутентификацию к определенному сервису, функционирующего в составе указанной области действия.

Проиллюстрируем вышесказанное следующей зарисовкой:

realm_members

Участники протокола Kerberos

Аутентификация с использованием Kerberos

matreshki

Иллюстрация порядка изложения материала

Начнем от общего и перейдем к частному.

Житейская аналогия

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

  1. Посетитель приходит на вход и показывает охраннику свой паспорт.
  2. Охранник проверяет наличие посетителя в базе данных.
  3. Охранник выдает посетителю суточный билет на посещение парка.
  4. Посетитель выбирает понравившийся ему аттракцион и идет на кассу, чтобы получить билет.
  5. На кассе проверяют суточный билет посетителя и выдают билет на аттракцион.
  6. Посетитель идет на выбранный аттракцион и показывает смотрителю аттракциона, полученный на кассе билет.
  7. Смотритель проверяет билет и пропускает посетителя.
  8. Посетитель при желании может посмотреть бейджик смотрителя, чтобы убедиться, что он действительно сотрудник парка.

Если посетитель захотел пойти на другой аттракцион, он снова идет на кассу и показывает суточный билет. Далее повторяется процесс из шагов 5, 6, 7 только с другим смотрителем и другим аттракционом.

По верхам в общем виде

Теперь по аналогии рассмотрим упрощенную схему аутентификации с использованием Kerberos:

scheme

Общая схема обмена запросами в Kerberos

  1. Клиент отправляет запрос на аутентификацию к области действия.
  2. Сервер аутентификации проверяет подлинность Клиента с использованием Базы данных Kerberos.
  3. Сервер выдает Клиенту разрешение (пока просто назовем его TGT) на получение отдельных разрешений (далее – ST), требующимся для доступа к сервисам, входящим в область действия.
  4. С использованием полученного на шаге №3 разрешения (TGT) Клиент запрашивает разрешение на доступ к Сервису А («ST для А»).
  5. Сервер выдачи разрешений проверяет TGT и выдает Клиенту ST для доступа к сервису А.
  6. Клиент с использованием «ST для А» запрашивает у Сервиса А доступ к его ресурсам.
  7. Сервис А проверяет «ST для А» и предоставляет Клиенту доступ к своим ресурсам. При необходимости сервис также проходит аутентификацию перед клиентом.

В дальнейшем при необходимости доступа к другому сервису:

  1. С использованием полученного на шаге №3 разрешения (TGT) Клиент запрашивает разрешение на доступ к Сервису Б («ST для Б»).
  2. Сервер выдачи разрешений проверяет TGT и выдает Клиенту ST для доступа к сервису Б.
  3. Клиент с использованием «ST для Б» запрашивает у Сервиса Б доступ к его ресурсам.
  4. Сервис Б проверяет «ST для Б» и предоставляет Клиенту доступ к своим ресурсам.

Видно, что стороны обмениваются сообщениями, содержащими запросы и ответы с разрешениями. Официально форматы указанных сообщений задокументированы в RFC 4120.

Теперь переназовем передаваемые сообщения в соответствие с RFC:

  • Запрос на аутентификацию к области действия (шаг 1) — сообщение KRB_AS_REQ.
  • Ответ сервера на запрос аутентификации клиента (шаг 3) – сообщение KRB_AS_REP.
  • Разрешение на получение разрешений – TGT (Ticket Granting Ticket).

Другие встречающиеся в литературе названия: мандат / билет на получение разрешений, первичное удостоверение пользователя.

Примечание: в различных источниках часто встречается словосочетание «TGT билет», но в аббревиатуре TGT уже заложено слово «билет» — Ticket Granting Ticket, поэтому правильнее говорить просто «TGT».

  • Запрос на доступ к сервису (шаг 4) – сообщение KRB_TGS_REQ.

  • Ответ сервера выдачи разрешений (шаг 5) – сообщение KRB_TGS_REP.

  • Разрешение на доступ к сервису – ST (Service Ticket)
    Другие встречающиеся названия: TGS билет, билет сервиса, мандат сервиса.

  • Запрос клиента на аутентификацию к сервису (шаг 6) – сообщение KRB_AP_REQ.

  • Опциональный ответ с аутентификацией сервиса перед клиентом (шаг 7) – сообщение KRB_AP_REP.

Чтобы проще было запомнить:

  • KRB ~ KeRBeros
  • AS ~ Authentication Server
  • REP ~ REsPonse
  • REQ ~ REQuest
  • AP ~ APplication server

Далее каждый запрос будет разобран подробнее.

Разбор аутентификации в Kerberos согласно RFC

В начале имеются три участника протокола Kerberos:

  1. Клиент
  2. Сервис
  3. Центр распределения ключей

Каждый из участников обладает своим долговременным секретом (ключом). Кроме того, центр распределения ключей обладает секретами всех участников.

secrets_distribution

Рис. 3 — Первоначальное распределение секретов

Алгоритм формирования ключа

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

Название алгоритма (etype) Способ вычисления ключа
RC4_HMAC_MD5 NT-хэш пароля участника
AES128_CTS_HMAC_SHA1_96 PBKDF2(пароль, соль*, kvno**, 128)
AES256_CTS_HMAC_SHA1_96 PBKDF2(пароль, соль*, kvno**, 256)

В последних версиях Windows по умолчанию используется шифрование AES. Но для совместимости с системами ниже Windows Vista и Windows 2008 Server необходима поддержка алгоритма RC4.

Соль формируется следующим образом:

  • Для доменных пользователей: полностью определенное имя домена заглавными буквами (FQDN) + регистр зависимое имя пользователя.

    Пример: DOMAIN.LOCALuser

  • Для компьютеров: FQDN + host + регистр зависимое имя компьютера без $ в конце.

    Пример: DOMAIN.LOCALhostcomputer.domain.local

kvno — key version number (в переводе — номер версии ключа). kvno представляет собой счетчик, увеличивающий значение каждый раз при смене пароля.

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

Источники:

  • Kerberos from Hacker recipes
  • A Note on Calculating Kerberos Keys for AD Accounts (snovvcrash)

KRB_AS_REQ

KRB_AS_REQ_NO_PRE

Клиент отправляет серверу аутентификации запрос, содержащий:

  • Принципал клиента
  • Срок жизни билета

Примечание: если это не первый материал по Kerberos, который вы читаете и возникает вопрос, почему отсутствует предварительная аутентификации, то поясню – это дополнительная настройка протокола, которая в «классической» реализации по умолчанию отключена. В реализации Kerberos для Active Directory, указанная настройка напротив по умолчанию активна и этот случай будет рассмотрен чуть позже.

KRB_AS_REP

KRB_AS_REP

Сервер аутентификации по полученному принципалу находит в базе Kerberos секрет клиента. Кроме того, для дальнейшего общения с KDC сервер аутентификации случайным образом генерирует сессионный ключ. В итоге в ответ клиенту отправляются два сообщения.

Первое сообщение зашифровано с использованием секрета клиента и содержит:

  • Сессионный ключ для KDC
  • Метка времени
  • Срок жизни TGT

Второе сообщение (TGT) зашифровано уже с использованием (!) секрета KDC и включает в себя те же самые данные, что и первое сообщение, но вместе с принципалом клиента.

Примечание: время жизни TGT определяется, как наименьшее время среди запрошенного клиентом и хранящегося в настройках центра распределения ключей.

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

KRB_TGS_REQ

KRB_TGS_REQ

Теперь, пройдя аутентификацию, клиент желает получить доступ к какому-то сервису. Для этого он отправляет серверу выдачи разрешений запрос, содержащий:

  • Принципал сервиса
  • Аутентификатор, состоящий из принципала клиента и метки времени, зашифрованных с использованием извлеченного ранее сессионного ключа для общения с KDC.
  • Сохраненный TGT

Приняв запрос, сервер выдачи разрешений прежде всего выполняет проверку полученных данных. Сначала с использованием секрета KDC сервер расшифровывает TGT (1) и по метке времени со сроком действия убеждается, что TGT не протух (2).

Далее сервер извлекает сессионный ключ для KDC. Несмотря на то, что указанный ключ был создан в KDC, нужды хранить его в базе Kerberos нет. Действительно, TGT не может быть изменен кем-либо кроме KDC, поэтому полученным из него данным можно доверять.

Возникает важный вопрос — почему можно быть уверенным, что TGT не отправлен злоумышленником, перехватившим его при прослушивании сетевого трафика?
Для этого в запросе прилагается аутентификатор. Аутентификатор зашифрован с использованием сессионного ключа KDC, который мог быть извлечен из KRB_AS_REP запроса только определенным клиентом. Метка времени добавляется с целью предотвращения атак методом повтора, чтобы злоумышленник не смог вставить в свой запрос старый аутентификатор клиента, перехваченный из прошлых сообщений.

Сервер выдачи разрешений сравнивает принципалы пользователя из TGT и аутентификатора, а также убеждается, что аутентификатор был сформирован не более двух минут назад.

KRB_TGS_REP

KRB_TGS_REP

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

  • Сессионный ключ для общения с сервисом
  • Метка времени
  • Срок жизни TGS билета
  • Принципал сервиса

Второе сообщение (TGS билет) зашифровано с использованием секрета сервиса и включает в себя те же самые данные, что и первое сообщение, а также принципал клиента.

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

KRB_AP_REQ

KRB_AP_REQ

Клиент отправляет сервису запрос на получение доступа, содержащий:

  • Аутентификатор, состоящий из принципала клиента и метки времени, зашифрованных с использованием извлеченного ранее сессионного ключа для общения с сервисом.
  • Сохраненный TGS билет
  • Флаг взаимной аутентификации

Приняв запрос, сервис прежде всего выполняет проверку полученных данных. Сначала с использованием своего секрета сервис расшифровывает TGS (1) и по метке времени со сроком действия убеждается, что TGS не протух (2). Далее сервис извлекает сессионный ключ.

TGS билет не может быть изменен кем-либо кроме того, кто знает секрет сервиса, а это KDC и сам сервис. Сервис доверяет KDC, таким образом извлеченным из TGS билета данным сервис также может доверять.

Аналогично KRB_TGS_REQ расшифровывается аутентификатор и выполняются другие проверки.
Обратите внимание, что сервис удостоверяется в подлинности клиента, не обращаясь к KDC.

KRB_AP_REP

KRB_AP_REP

Опционально, в случае если активен флаг взаимной аутентификации, сервис также подтверждает перед клиентом свою подлинность, отправив ответ с меткой времени, зашифрованной с использованием сессионного ключа.

Kerberos в Active Directory

«Чтобы донести идею её надо рассказать три раза, но разными словами» (с)

Рассмотрим реализацию Kerberos в Active Directory. Уточним терминологию, теперь:

Область действия – домен.

Центр распределения ключей – контроллер домена.

Сервер аутентификации и сервер выдачи разрешений – оба объединены в рамках одного компонента, функционирующего на контроллере домена.

База данных Kerberos – в Active Directory информация о секретах пользователей хранится на контроллерах домена в файле ntds.dit.

krbtgt – название учетной записи, по умолчанию создаваемой вместе с доменом и обладающей секретом контроллера домена.

В итоге с учетом переименований получается следующая структура:

ad_realm

В целом в Active Directory Kerberos работает согласно RFC, но есть ряд особенностей. Рассмотрим указанные особенности на следующем примере.

Доменная аутентификация пользователя к рабочей станции в Active Directory

Изначально на рабочей станции активно следующее диалоговое окно:

logon_screen

Пользователь вводит свои учетные данные (название домена, имя учетной записи, пароль) и жмет «OK». Далее компонент, ответственный за отображение диалогового окна, передает запрос на аутентификацию пользователя с использованием введенных данных в локальный центр безопасности (Local Security Authority, LSA). Центр содержит различные динамические библиотеки, предоставляющие функции для процедур аутентификации, смены паролей, а также выдачи токенов. Указанные библиотеки вызываются и работают в контексте процесса lsass.exe (Local Security Authority Subsystem Service).

В зависимости от запроса для его обработки согласовывается соответствующая библиотека.
Примеры библиотек и протоколов:

  • msv1_0.dll (NTLM)
  • kerberos.dll (Kerberos)
  • SChannel.dll (TLS/SSL)
  • WDigest.dll (digest аутентификация)

По умолчанию для обработки запросов на проверку подлинности пользователя при входе в домен выбирается библиотека kerberos.dll, реализующая одноименный протокол.

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

В итоге имеем следующую картину:

KRB_Worstation_Start

Секрет системы (ключ) присваивается рабочей станции при ее добавлении в домен. Важно отметить, что введенный пользователем пароль не хранится в памяти рабочей станции. Ключ пользователя формируется при помощи ранее рассмотренной хэш-функции string2key.

Далее процесс, обеспечивающий аутентификацию пользователя, обращается к контроллеру домена с использованием сформированного ключа. Здесь проявляется одна из особенностей реализации Kerberos в Active Directory – предварительная аутентификация по умолчанию включена.

KRB_AS_REQ с предварительной аутентификацией

KRB_AS_REP_AD

В этом случае клиент отправляет серверу аутентификации запрос, содержащий:

  • Принципал клиента
  • Метку времени, зашифрованную с использованием секрета клиента

Получив запрос, контроллер домена с помощью секрета клиента расшифровывает метку времени и сравнивает её с текущим значением. Если переданное время расходится с текущим меньше чем на пять минут, то значит предварительная аутентификация клиента успешно пройдена. В противном случае контроллер отправляет сообщение об ошибке.

KRB_AS_REP (AD)

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

KRB_ASREP_PAC

В ответе появилась еще одна особенность, а именно новое поле «PAC» в содержимом TGT.

PAC (Privilege Attribute Certificate) это данные, предназначенные для авторизации пользователя. Ранее уже отмечалось, что кроме аутентификации Kerberos может использоваться при авторизации, но не пояснялось как. Поле PAC изначально было предусмотрено в RFC без конкретного описания содержимого. Какая информация передается в PAC и как она обрабатывается зависит от конкретной реализации Kerberos.

В Active Directory PAC среди прочего содержит следующую информацию:

  • Идентификатор безопасности (SID) учетной записи пользователя
  • Идентификаторы групп, в которых состоит пользователь

Указанная информация дважды подписывается. Одна подпись принадлежит krbtgt, а вторая сервису, к которому обращался клиент (в случае KRB_AS_REP тоже krbtgt).

KRB_TGS_REQ (AD)

Запрос производится аналогично рассмотренному ранее в RFC.

AUTH_TGS_REQ

KRB_TGS_REP (AD)

PAC из TGT, полученный в предыдущем сообщении, помещается в TGS билет. В этот раз PAC подписывается не только с использованием секрета krbtgt, но и секрета системы.

AUTH_TGS_REP

LOGON

С использованием сессионного ключа LSA извлекает подписанный PAC из TGS билета. LSA проверяет подпись PAC при помощи секрета системы и далее с учетом добытых из PAC доменных групп безопасности формирует процесс Winlogon c соответствующим токеном доступа клиента.

AUTH_Logon

Опционально система может запросить контроллер домена выполнить дополнительную проверку подписи с PAC с помощью секрета krbtgt.

Итог

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

Ссылки на используемые источники

  • Kerberos Protocol Tutorial (Fulvio Ricciardi)
  • Kerberos and Windows Security Series (Robert Broeckelmann)
  • Статья с pro-ldap.ru
  • Блог Pixis
  • Фундаментальная статья c tarlogic.com (Eloy Pérez)
  • Документация Microsoft
  • How to Kerberos? its components and function (Sheeraz Ali)
  • Windows authentication attacks part 2 – kerberos (Ahmed Sultan)

Картинка для обложки взята отсюда.

Сегодня мы с вами рассмотрим протокол аутентификации Kerberos. Пройдемся по самому протоколу и рассмотрим его работу в рамках Microsoft Active Directory.

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

История

Самая первая версия протокола была разработана в далеком 1988 году в MIT для проекта «Афина». Версии с 1 по 3 использовались исключительно внутри MIT.

4 версия была разработана Стивеном Миллером и Клиффордом Нейманном, она хоть и была публичной, но для очень ограниченного количества компаний, включая проект «Афина». И только 5 версия протокола Kerberos, которая вышла в 1993 году уже стала по настоящему публичной и была описана в RFC 1510.  

Microsoft Windows Server и Active Directory используют расширенный протокол Kerberos 5 версии, описанный в RFC 4120.

Kerberos в Active Directory

Kerberos сейчас считается основным протоколом при работе в домене Microsoft Windows и состоит из набора компонентов:

Компонент

Описание

Область Kerberos

Сеть, в которой расположен наш KDC. Если мы говорим про Active Directory – то в качестве области может восприниматься домен.

KDC (Key Distribution Centre)

Центр выдачи ключей. Роль состоит из AS и TGS и занимается выдачей билетов. KDC располагается на контроллере домена.

AS (Authentication Server)

Выполняет авторизацию пользователя и затем передает данные в KDC для выдачи билета.

TGS (Ticket Granting Service)

Билет сервиса. Данный билет клиент предоставляет сервису для проверки. Он зашифрован сервисным ключом.

TGT (Ticket Granting Ticket)

Билет клиента, предоставленный KDC после успешной аутентификации.

Описание работы протокола Kerberos

 Для общего понимания для начала нарисуем схему и потом пройдем по всем пунктам. Схема работы протокола представлена ниже:

Рассмотрим каждый шаг более подробно:

1. AS_REQ (Preauthentication Request). Данный этап мы проходим, когда авторизуемся на нашей рабочей станции в домене (вводим наш логин и пароль). Формат отправляемого запроса выглядит следующим образом:

Client Name – имя пользователя;

Service Name – обращение к сервису krbtgt на стороне контроллера домена;

Client Time – метка времени с рабочей станции, откуда мы пытаемся авторизоваться. Метка шифруется хэшем пароля пользователя для предотвращения атак с повторной передачей.

По умолчанию, разница во времени между клиентом и KDC должна быть не более 5 минут, иначе запрос будет отклонен;

2. AS_REP. После того, как контроллер домена получит наш пакет – он сразу же попытается расшифровать присланную метку времени используя локальную копию хэша пароля пользователя из базы Active Directory. Если провести операцию не получается, то такой запрос будет отклонен, а клиенту возвращена ошибка. Если же все проходит успешно, то формируется сообщение AS_REP. Формат данного сообщения приведен ниже:

Client Name – имя пользователя;

Session Key – случайно сгенерированный криптографический ключ, который в дальнейшем будет использоваться для взаимодействия между пользователем и AD;

Token Information – токен пользователя, содержащий все данные по пользователю – состав групп, права и т.д.;

Lifetime/Expiry – время жизни TGT;

По умолчанию время жизни TGT составляет 10 часов.

В сообщении AS_REP у нас 2 блока – один шифруется хэшем пароля пользователя, второй – шифруется секретом KDC. Секрет KDC хранится в AD на контроллере. Клиент расшифровывает свою часть сообщения, а TGT просто сохраняется в памяти. Именно внутри блока TGT у нас хранится Token Information.

После успешно принятого сообщения AS_REP нам уже не требуется пароль, поскольку дальнейшее взаимодействие между клиентом и контроллером AD будет происходит посредством защищенного Session Key;

3. TGS_REQ. Вот и настал момент, когда нам необходимо обратиться к какому – либо сервису по Kerberos. В случае с AD это практически любой сервис (Exchange, SharePoint, файловые серверы и т.д.). Для того, чтобы мы смогли запросить доступ к сервису, данный сервис должен иметь свой SPN.

Итак, мы хотим обратиться к сервису через Kerberos – для этого мы посылаем на KDC сообщение TGS_REQ следующего содержания:

Service Principal – SPN запрашиваемого сервиса;

Client Name – имя пользователя;

Time Stamp – метка времени;

Как видно по изображению выше – имя пользователя и метка времени у нас зашифрованы сессионным ключом, который мы получили еще на этапе аутентификации. Блок TGT, который мы получили ранее, также передается на сервер KDC для обработки;

4. TGS_REP. Если на предыдущем этапе у нас все прошло хорошо, то в ответ KDC формирует нам TGS_REP пакет со следующим содержимым:

Service Principal – SPN сервиса;

Time Stamp – метка времени;

Service Session Key – это сессионный ключ, который будет использоваться уже при общении со службой;

Client Name – имя пользователя.

Здесь у нас также ответ представлен из двух блоков: первый блок – шифруется сессионным ключом клиента, который был получен на этапе AS_REP, второй блок – шифруется хэшем пароля службы;

5. AP_REQ. После того, как клиент получит ответ TGS_REP, он «идет» с ним к целевому сервису уже с запросом AP_REQ следующего содержания:

Client Name – имя пользователя;

Time Stamp – метка времени;

Service Principal – SPN запрашиваемого сервиса;

Service Session Key – это сессионный ключ, который будет использоваться уже при общении со службой;

Token Information – токен пользователя, содержащий все данные по пользователю – состав групп, права и т.д.;   

Здесь у нас также представлены 2 блока – один блок шифруется сессионным ключом службы, второй – секретом службы;

6. После поступления запроса AP_REQ служба дешифрует свой блок, получая Service Session Key, которым затем дешифрует первый блок, обеспечивая проверку подлинности;

7. AP_REP. Данный пакет у нас на рисунке выше помечен пунктирной стрелкой. По сути, после получения AP_REQ и его расшифровки у службы нет обязательного требования отправки данного пакета. Он может быть отправлен в случае, например, возникшей ошибки или если была запрошена взаимная проверка подлинности.

Итог

В этой статье мы с вами расмотрели, как происходит взаимодействие по протоколу Kerberos в среде Active Directory. Естественно, сам протокол не ограничивается только этими пакетами. Гораздо больше технической информации можно найти в RFC 1510 и RFC 4120.

Введение

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

Данную статью я написал после того, как сделал собственную библиотеку, генерирующую сообщения протокола Kerberos, а также после того, как я протестировал «стандартный клиент» Kerberos в Windows — набор функций SSPI. Я научился тестировать произвольные конфигурации сервисов при всех возможных видах делегирования. Я нашёл способ, как выполнять пре‑аутентификацию в Windows как с применением имени пользователя и пароля, так и с помощью PKINIT. Я также сделал библиотеку, которая умещает «стандартный» код для запроса к SSPI в 3–5 строк вместо, скажем, 50-ти.

Хотя в названии статьи фигурирует «простыми словами» однако эта статья предполагает, что читатель уже имеет какое‑то представление о Kerberos.

Что есть в данной статье

  • Простое объяснение основ работы Kerberos;

  • Простое объяснение аутентификации между доменами;

  • Описание реализации передачи сообщений Kerberos как по UDP, так и по TCP;

  • Объяснение что такое «сервис» в понятии Kerberos и почему у «сервиса» нет пароля;

  • Объяснение почему в абсолютном большинстве случаев SPN служит просто для идентификации пользователя, из‑под которого запущен «сервис»;

  • Как система понимает, к какому типу относить то или иное имя принципала;

  • Рабочий код на С++, реализующий алгоритм шифрования Kerberos с AES (код реализован с применением CNG);

  • Как передать X.509 сертификат в качестве credentials в функцию AcquireCredentialsHandle (PKINIT);

  • Как сделать так, чтобы «сервис» понимал чужие SPNs (одновременная работа с credentials от нескольких пользователей);

  • Почему GSS‑API является основой для всего процесса аутентификации в Windows (да и в других ОС тоже);

  • Описание (со скриншотами из Wireshark) того, как именно передаётся AP‑REQ внутри различных протоколов (LDAP, HTTP, SMB, RPC);

  • Простое описание для каждого из типов делегирования Kerberos;

  • Код для тестирования каждого из типов делегирования, который может быть выполнен на единственной рабочей станции, без какой‑либо конфигурации кучи вспомогательных сервисов;

  • Описание User‑To‑User (U2U), а также код с возможностью протестировать U2U;

  • Ссылки на различный мой код, как то: реализация «whoami на S4U», реализация klist, библиотеки XKERB для запросов к SSPI и прочее;

Для чего нужен Kerberos

Для начала представим, что на компьютере (любом) в сети запущена программа. Эта программа может общаться с другими программами в сети с помощью какого‑то произвольного протокола. Представим также, что эта программа может предоставлять какой‑то «сервис» другим программам: например, выполнить сложение «2+2» и затем переслать результат обратно. Пока «сервис», предоставляемый этой командой, ограничивается только контекстом самой программы, то всё просто. Однако теперь представим, что в качестве «сервиса» эта программа позволяет считывать какой‑то локальный файл и затем передать содержимое этого файла по сети. В этом случае эта программа уже столкнётся с понятием доступа к необходимому файлу. Как известно, в Windows доступ к файлу определяется на основе security descriptor, где прописаны какие именно пользователи и группы имеют возможность выполнять определённые операции над данным файлом. Информация же о текущем конкретном пользователе и его группах содержится в так называемом access token (далее просто «токен»), который присваивается каждому отдельному процессу и потоку. Обычно такой токен получается пользователем при первичном логине на рабочую станцию. И все процессы, которые будут запущены от имени залогиненного пользователя, будут «наследовать» этот токен.

Теперь вернёмся обратно к той самой программе, которая запущена на локальном компьютере и предоставляет «сервис» по чтению контекста локального файла. Предположим, что ей поступил запрос на чтение локального файла А. Сама программа выполняется из‑под пользователя, который находится, например, в группе «Users» на данном компьютере. Однако доступ к файлу А возможен только для пользователей из группы «Administrators». То есть в том случае, если эта программа будет использовать свой «базовый» токен, то для неё доступ к файлу А будет закрыт. Но ведь эта программа предоставляет «сервис» каким‑то другим программам, которые, в свою очередь, могут быть запущены уже под пользователями, входящими в группу «Administrators». То есть вроде как логично, что если «сервис» запрашивается от имени пользователя, которому разрешён доступ к удалённому файлу, то он ему должен быть предоставлен. Что же нужно для того, чтобы это стало возможным?

На самом деле всё, что нужно — это сделать новый access token на имя того пользователя, от которого пришёл внешний запрос на этот «сервис». Далее программа, предоставляющая данный «сервис», должна просто сделать новый поток и присвоить этому новому потоку вновь сделанный access token. Теперь для локального компьютера всё, что будет сделано в рамках работы данного потока будет сделано от имени удалённого пользователя, который первично сделал запрос на «сервис». Но так или иначе для создания нового access token на «сервис» в качестве входных данных должна прийти вся информация, необходимая для этого.

Теперь рассмотрим ещё более сложную ситуацию. Допустим, на «сервис», который запущен на компьютере А пришёл запрос «запроси сервис на компьютере Б». В этом случае, опять же, есть две возможности: либо запросить сервис Б от имени пользователя, под которым запущен сервис А, или запросить сервис Б от имени пользователя, который сформировал первичный удалённый запрос к сервису А. Если мы хотим, чтобы был реализован второй вариант, то получается, что мы должны «делегировать» сервису А возможность представляться пользователем, который сформировал к нему запрос. Конечно, и в ранее рассмотренном случае с доступом к локальному файлу также был факт «делегирования», но там был случай «локального делегирования», только в рамках локального компьютера. Здесь же сервису А должно быть делегировано полномочие представлять какого‑то пользователя в рамках взаимодействия с другими сервисами по сети. Так что для возможности «делегирования» в протоколе «сервиса» также должны быть какие‑то данные.

Kerberos является протоколом аутентификации. Есть три различных понятия: идентификация, аутентификация и авторизация. Идентификация — это когда ты подходишь к какому‑то пропускному пункту и говоришь охраннику «я Вася Пупкин». Аутентификация — это когда кто‑то «авторитетный» заверяет вашу идентификацию, например рядом стоящий другой охранник говорит первому «да, я знаю этого парня, это точно Вася Пупкин». Авторизация — это когда этот самый охранник посмотрит твои документы, потом сверится со своим личным списком лиц, которым разрешён проход, и скажет «Васи Пупкина нет в списке, вы не проходите». То есть в данном примере идентификация прошла успешно, аутентификация также была выполнена, а при авторизации произошёл отказ.

В Kerberos для аутентификации (подтверждения идентификационной информации) используется передача зашифрованных сообщений. Если конечный получатель сообщения смог корректно расшифровать это сообщение, то однозначно считается, что информация, которую содержит сообщение, является верной. Существуют механизмы дополнительной проверки корректности этой информации в виде нескольких типов «подписей», но для текущего повествования это маловажно. Для шифрования идентификационных сообщений используются ключи шифрования, которые формируются специальным образом на основе текстовых паролей конечных получателей. Предполагается, что эти пароли известны только конечным получателям идентификационных сообщений, а также некоторому общему для домена центру хранения паролей. Таким образом, для того, чтобы пользователь А был идентифицирован пользователем Б пользователь А просит центр хранения паролей сформировать идентификационное сообщений, которое было бы зашифровано на шифровальном ключе пользователя Б. Центр хранения паролей формирует такое сообщение, и пересылает его обратно пользователю А. Пользователь А не может расшифровать или изменить это сообщение (оно зашифровано на ключе пользователя Б). Далее пользователь А может переслать это идентификационное сообщение пользователю Б, он его сможет успешно расшифровать и прочитать хранящуюся в данном сообщении идентификационную информацию.

В качестве «идентификационной информации» вполне достаточно передавать только уникальное имя пользователя. Однако в Windows пользователь идентифицируется не только своим именем, а также набором групп пользователей и набором привилегий. Можно было бы сделать так, чтобы сервис после расшифровки идентификационного сообщения сам посылал куда‑то запросы, на которые бы ему возвращались все дополнительные данные пользователя. Однако был выбран путь включения в идентификационное сообщение полной информации о «предмете идентификации»: полный список групп, а также другой вспомогательной информации. Привилегии «выдаются» каждому пользователю или группе на каждом компьютере отдельно, так что добавление привилегий в access token происходит уже в процессе формирования access token на машине «сервиса». Кстати, в Active Directory «предмет идентификации» называется «принципал» (principal).

В Active Directory пользователями идентификационных сообщений могут быть любые сущности, у которых возможно существование пароля. К таким сущностям относятся как пользователи домена, так и компьютеры, которые в данный домен входят. Использование компьютеров как пользователей идентификационных сообщений удобно так как нужно, чтобы «сервисы» работали даже тогда, когда ни один пользователь не работает за компьютером.

Также в Active Directory возможна аутентификация между пользователями из «дружественных» доменов. Технически это реализуется путём добавления в каждый из доменов специальных пользователей, имена которых совпадают с именем дружественного домена. При необходимости пользователя из домена А получить доступ к сервисам из домена Б пользователь сначала посылает запрос к своему контроллеру домена. Там формируется аутентификационная информация, однако она шифруется не на ключе начального контроллера домена, а на ключе того пользователя, имя которого совпадает с именем «дружественного» домена. Далее пользователь просто пересылает полученную аутентификационную информацию уже контроллеру домена Б и процесс аутентификации продолжается стандартным образом.

Техническая реализация Kerberos

Теперь опишем реальную структуру, которая обслуживает протокол идентификации Kerberos в Windows Active Directory. В Active Directory для каждого домена существует Key Distribution Center (KDC). Именно эта сущность отвечает за хранение паролей всех пользователей и компьютеров в данном домене. В документе RFC 4120 применяется также разделение на Authentication Service (AS) и Ticket‑Granting Service (TGS), однако в Active Directory все эти сущности объединены. Для простоты будем считать, что все коммуникации осуществляются с KDC.

Все сообщения в Kerberos кодируются с помощью ASN.1. Описание схем ASN.1 для различных видов сообщений можно найти в RFC 4120 и других документах. Коммуникации с KDC в Active Directory осуществляются либо с использованием протокола TCP (KDC слушает на порту 88), либо с использованием протокола UDP (и опять KDC слушает на порту 88). Найти на каком именно адресе работает сервис Kerberos можно с помощью команды «nslookup ‑type=SRV _kerberos._tcp.<имя_домена>» или для UPD с помощью команды «nslookup ‑type=SRV _kerberos._udp.<имя_домена>». Если сообщения передаются по протоколу TCP, то перед каждым сообщением передаётся 4 байта, содержащие общую длину сообщения. Если передача происходит по UDP, то передаётся просто чистое сообщение, без информации о длине.

Все коммуникации с KDC начинаются с посылки сообщения KDC‑AS‑REQ. В данном сообщении присутствует информация о различных флагах (об этом позже), имени принципала, имени домена, имени принципала, который является специальным и отвечает за выдачу идентификационной информации (оно всегда имеет значение «krbtgt»), а также о списке поддерживаемых схем шифрования. Насчёт «схем шифрования» необходимо дать дополнительное пояснение. Дело в том, что в KDC‑AS‑REQ передаётся набор тех схем шифрования, которые может поддержать (зашифровать/расшифровать) данный конкретный клиент. На KDC, в свою очередь, может быть какой‑то другой набор поддерживаемых схем шифрования, и, потенциально, они могут не совпасть со схемами на клиенте. В этом случае коммуникации между таким клиентом и KDC будут невозможны.

В ответ на получение сообщения KDC‑AS‑REQ KDC может возвратить как зашифрованную идентификационную информацию для упомянутого в запросе принципала (сообщение KDC‑AS‑REP), так и ошибку (KRB‑ERROR). В KRB‑ERROR будет передаваться, прежде всего, код ошибки, а также возможна передача дополнительной информации. Обычно в современных системах код ошибки будет 25: требуется пре‑идентификация. Под пре‑идентификацией подразумевается процесс, в ходе которого запрашивающая сторона проверяется на то, что она действительно знает ключ шифрования того принципала, для которого запрашивается идентификационная информация. Также в случае кода ошибки 25 в KRB‑ERROR передаётся дополнительная информация, как то: 1) специальное текстовое сообщение, которое используется при генерации ключа шифрования (salt); 2) идентификатор предпочтительной схемы шифрования; 3) перечень способов пре‑идентификации, которые поддерживаются данным KDC. Необходимо заметить, что обычно KDC поддерживает несколько способов пре‑идентификации, таких как пре‑идентификация по паролю, пре‑идентификация по сертификату (PKINIT), пре‑идентификация с использованием расширения FAST (RFC 6113) и так далее. Однако базовым способом пре‑идентификации является идентификация по паролю. Для того, чтобы клиент прошёл эту пре‑идентификацию, он должен зашифровать специально сформированные данные, содержащие текущую временную метку. То есть клиент просто должен каким‑то образом получить текущее время, затем сформировать специальное сообщение, и затем зашифровать его с использованием пароля того принципала, для которого он запрашивает у KDC идентификационную информацию. В случае с использованием пре‑идентификации по сертификату (PKINIT) процесс практически такой же за исключением того, что шифрование производится с использованием закрытого ключа сертификата принципала.

После формирования пре‑идентификационного сообщения формируется новый вариант сообщения KDC‑AS‑REQ, который содержит всю информацию из первого варианта сообщения плюс информацию о зашифрованном текущем времени на клиенте. Эта информация располагается внутри массива PA‑DATA (pre‑authentication data).

В ответ на KDC‑AS‑REQ в котором содержится пре‑идентификационная информация KDC, присылает KDC‑AS‑REP, который содержит идентификационную информацию по запрошенному принципалу. Эта идентификационная информация зашифрована на ключе KDC и служит для реализации функционала Single Sign‑On (SSO). В большинстве случаев эту идентификационную информацию называют «Ticket‑Granting Ticket» (TGT). То есть для всех дальнейших запросов к KDC пользователю не нужно будет всегда использовать пароль: он будет просто посылать свою идентификационную информацию KDC, затем KDC сможет её расшифровать и использовать эту информацию во вторичных запросах. Нужно заметить, что в KDC‑AS‑REP присылается как идентификационная информация, которую клиент не может расшифровать, так и дополнительная информация, зашифрованная на ключе клиента и к которой он имеет доступ. В этой дополнительной информации, в частности, находится случайно сгенерированный сессионный ключ, который клиенту теперь будет необходимо использовать в дальнейших коммуникациях с KDC. Использование сессионного ключа вместо заранее известного ключа, генерируемого из пароля пользователя, потенциально повышает безопасность коммуникаций. Кстати, на самом деле KDC нигде не хранит этот сессионный ключ. Вместо этого он просто добавляет его в ту идентификационную информацию, которую присылает в KDC‑AS‑REP. Когда клиент выполнит следующий запрос к KDC он пошлёт эту же идентификационную информацию, которую KDC сможет расшифровать и достать оттуда нужный сессионный ключ.

Флаги в KDC options

Основные флаги, поддерживаемые в Windows, описаны в документе по следующей ссылке. Здесь я расскажу о наиболее используемых флагах.

Начнём с флага CANONICALIZE. Если данный флаг установлен в запросе от клиента, то это означает, что клиент ожидает (и может обработать) изменение имени клиента и сервиса, а также изменение типа этого имени в ответном сообщении. То есть при посылке TGS‑REQ с именем клиента «client@server» в TGS‑REP может быть уже «server\client».

Флаг RENEWABLE устанавливается на KDC при формировании первичных TGT. Если это флаг установлен, то клиент может обновлять свой TGT, без полного прохождения процедуры пре‑аутентификации. Делается это путём повторной посылки сообщения TGS‑REQ к сервису «krbtgt», установленным флагом RENEWABLE в запросе и первичным TGT в PA‑DATA. Далее KDC просто декодирует старый TGT, скопирует его содержимое в новый TGT, обновить время действия нового TGT, а также сформирует новый сессионный ключ.

Флаг OK‑AS‑DELEGATE находится в поле «flags» зашифрованной части TGS‑REP (не в kdc_options). Флаг OK‑AS‑DELEGATE формируется на стороне KDC, и приходит в TGS‑REP когда выполняется запрос к сервису, для которого включён режим «неограниченного делегирования» (более подробно про данный режим далее в статье). При получении TGS‑REP с установленным OK‑AS‑DELEGATE стандартный Kerberos клиент Windows автоматически формирует TGS‑REQ к сервису «krbtgt» с установленными флагами FORWARDABLE и FORWARDED. В этом новом TGS‑REQ также прикладывается первичный TGT клиента. В ответ KDC формирует TGS‑REP, в котором содержится TGT с установленным флагом FORWARDED и именно этот новый TGT используется далее для формирования AP‑REQ к необходимому сервису. Таким образом, если у вас есть TGT с установленным флагом FORWARDABLE и есть сессионный ключ, соответствующий данному TGT, то можно сформировать запрос, который возвратит вам новый TGT с установленным FORWARDABLE. Флаг FORWARDABLE необходим при реализации делегирования на сервисах, без этого флага KDC будет отвергать запросы от сервисов на получение билетов на имя клиента.

Далее для продолжения рассказа о технических аспектах реализации Kerberos необходимо прерваться и рассказать о том, как реализованы «сервисы» в Active Directory.

Сервисы

Под «сервисом» понимается какая‑то программа, предоставляющая какой‑то функционал удалённым или локальным (по отношению к компьютеру, на котором этот «сервис» запущен) пользователям. Нужно заметить, что в Windows есть даже отдельная оснастка для MMC, которая показывает «Сервисы». Но на самом деле те «сервисы», которые отображаются в этой оснастке, не относятся к «сервисам» в понятии Kerberos. Для Kerberos сервисом будет считаться любая программа, даже запущенная из‑под обычного пользователя. То есть «сервис» из оснастки MMC может быть также «сервисом» для Kerberos, однако это не является обязательным условием.

Как я описал ранее, для аутентификации в Kerberos используются зашифрованные сообщения. Для шифрования в адрес какого‑то принципала необходимо, чтобы у этого принципала был какой‑то пароль. Пароли в домене Active Directory могут быть только у пользователей или компьютеров. «Сервисы» сами по себе паролей не имеют. Вместо этого «сервис» использует идентификационную информацию (имя пользователя и пароль) того пользователя, из‑под которого этот «сервис» в настоящий момент запущен. И, как следствие, все «сервисы», которые запущены из‑под одного и того же пользователя, будут использовать один и тот же пароль. Если «сервис А» запущен из‑под пользователя А на компьютере 1, то если запустить «сервис Б» на компьютере 2 и запустить его опять из‑под пользователя А, то оба сервиса будут использовать один и тот же пароль. Для более «продвинутых» читателей приведу ещё пример: все сервисы, запущенные на любом компьютере из‑под одного и того же аккаунта gMSA используют один и тот же пароль.

Для Kerberos «сервис» тоже является принципалом. То есть «сервис» может использовать идентификационную информацию других принципалов, а также передавать свою идентификационную информацию. Однако так как «сервис» использует идентификационную информацию того пользователя, из‑под которого он запущен, то фактически «сервис» можно назвать «фантомным» принципалом. В первичных стандартах Kerberos «сервис» имеет собственное имя (Service Principal Name, SPN), однако в Active Directory это имя, фактически, используется только для поиска пользователя, который в настоящий момент владеет данным SPN и вместо имени «сервиса» может быть использовано имя того принципала, из‑под которого данный сервис запущен.

В Active Directory имя «сервиса» (SPN) также используется, но только для того, чтобы найти имя того принципала, из‑под которого данный «сервис» запущен. Для того, чтобы это было возможно SPN должно быть уникальным в рамках всего домена. Так как обычно «сервисы» запускаются из‑под учётных записей компьютеров, то имя SPN для любого такого «сервиса» должно (по правилам Microsoft) содержать имя компьютера, на котором этот «сервис» запускается. Но если вы для компьютера COMP1 добавите новый «сервис» и зададите ему SPN вида «service1/COMP2», то Active Directory это тоже пропустит. Главное, чтобы такого имени ранее в домене не существовало. Возможно, кто‑то подумает, что если SPN=service1/COMP2, то теперь KDC при запросах также будет использовать и пароль для COMP2 — нет, KDC будет использовать пароль того пользователя, у которого в атрибуте servicePrincipalName находится искомое SPN. Кстати, не смотря на официальную документацию, в которой описывается как именно должны именоваться SPN в Active Directory (ссылка) у меня получалось добавлять (и в дальнейшем использовать) SPN вида «S1/S1». Повторюсь — главное, чтобы имя «сервиса» было уникальным в масштабе текущего домена.

Любой «сервис» может быть запущен как из‑под системной учётной записи (записи компьютера), так и из‑под учётной записи произвольного пользователя. Но если меняется пользователь, из‑под которого запускается какой‑то «сервис», то для корректной работы Kerberos необходимо просто удалить SPN этого сервиса из атрибута servicePrincipalName у одного пользователя/компьютера и добавить этот SPN в аналогичный атрибут другого пользователя/компьютера. Отличием между запуском из‑под системной учётной записью и записью обычного пользователя будет только набор привилегий, которыми обладает пользователь: для полноценной работы «сервисам» зачастую необходимо, чтобы пользователь, в контексте которого выполняются «сервисы», имел такие привилегии как SeTcbPrivilege и SeImpersonatePrivilege. Однако если выдать права на эти привилегии какому‑то другому пользователю на данном компьютере, то «сервис», выполняемый от его имени, будет иметь точно такие же возможности, как если бы он выполнялся от имени системной учётной записи.

Также необходимо заметить, что некоторые имена «сервисов» являютс предопределёнными, и другие «сервисы» ожидают, что «сервис» с таким именем будет предоставлять определённые функции. Так «сервис» с именем «krbtgt/<имя домена>» будет предоставлять сервисы KDC, «сервис» с именем «host/<имя компьютера>» предоставляет возможность логина на компьютер, «сервис» с именем «cifs/<имя компьютера>» предоставляет услуги доступа к файловой системе на определённом компьютере по протоколу SMB и так далее. Список таких «предопределённых имён» можно посмотреть тут. Посмотреть, какие «сервисы» зарегистрированы для определённого компьютера можно с помощью команды «setspn.exe ‑L <ServerName>». Посмотреть, какие «сервисы» зарегистрированы для определённого пользователя можно с помощью команды «setspn.exe ‑L <domain\user>».

Общие правила составления имён принципалов

Перед правилами именования принципалов необходимо пояснить какие же типы имён принципалов бывают в Active Directory. В файле «NTSecAPI.h» объявлены следующие типы имён принципалов:

  • KRB_NT_UNKNOWN

  • KRB_NT_PRINCIPAL

  • KRB_NT_PRINCIPAL_AND_ID

  • KRB_NT_SRV_INST

  • KRB_NT_SRV_INST_AND_ID

  • KRB_NT_SRV_HST

  • KRB_NT_SRV_XHST

  • KRB_NT_UID

  • KRB_NT_ENTERPRISE_PRINCIPAL

  • KRB_NT_ENT_PRINCIPAL_AND_ID

  • KRB_NT_MS_PRINCIPAL

  • KRB_NT_MS_PRINCIPAL_AND_ID

Если в имени присутствует «@», то всё, что находится после «@» считается именем домена (realm name). Имя перед «@» делится по группам на основе присутствия символа «/». Если этих групп 1 (то есть нет символа «/»), то общему имени присваивается тип KRB_NT_PRINCIPAL. Если таких групп 2, то общему имени присваивается тип KRB_NT_SRV_INSTANCE. Если таких групп 3 и более, то вроде как общему имени должен присваиваться тип KRB_NT_SRV_XHST, однако на деле присваивается также KRB_NT_SRV_INSTANCE. Если в общем имени присутствует символ «\», то имени присваивается тип KRB_NT_MS_PRINCIPAL_NAME. Если в имени нет ни одного из символов «@», «\» или «/», то этому имени назначается тип KRB_NT_PRINCIPAL и имя домена берётся из текущих значений. Таким образом, если хотите запросить билет для пользователя, то формируйте имя в виде «name@domain» или «domain\name». Если хотите запросить билет для сервиса, то формируйте имя в виде «part1/[part N]@domain» или просто «part 1/[part N]». Всё решает прямой или обратный backslash.

Все типы имён, кончающихся на «_ID» представляют собой обычный тип (без «_ID»), но с добавленным SID в качестве последнего элемента массива имён в виде строки. Данный SID должен быть в стандартной форме, вроде «S-1–5–500».

Описание алгоритма шифрования Kerberos

На самом деле, как я и писал ранее, Kerberos поддерживает множество различных схем шифрования. Также Kerberos может использовать CMS (Cryptographic Message Syntax, RFC5652), как минимум на этапе пре‑идентификации. Однако в настоящее время наиболее используемыми схемами шифрования являются схемы на основе использования стандарта шифрования AES. Само по себе шифрование применяется с использованием стандартного алгоритма AES. Однако формирование ключа шифрования в Kerberos выполняется по достаточно сложной схеме. Реализацию на языке С++ с использованием CNG (Cryptography API: Next Generation) можно найти по этой ссылке. Для общего понимания необходимо знать, что для дополнительного усложнения Kerberos использует так называемые key usage numbers: 4-байтовые значения, которые специфичны для каждой фазы передачи сообщений. Значения для этих key usage numbers приведены в RFC4120, item 7.5.1. Таким образом, для фазы посылки первичного запроса AS‑REQ с encrypted timestamp значение для key usage number будет равно 1 (или если писать в виде 4-х байтов, то 0×00 000 001), для фазы передачи AS‑REP значение key usage number будет уже 2, и так далее. Знание key usage number критически важно для взлома ключей Kerberos — если указать неверный номер, то ключ никогда не будет взломан, или будет получено ошибочное выходное значение.

Обратно к процессу получения идентификационной информации

Итак, раннее я остановился на том, что клиент Kerberos получил от KDC зашифрованную идентификационную информацию. Но всё, что возможно сделать имея эту идентификационную информацию, это идентифицироваться на KDC. Что же делать, чтобы наш клиент смог идентифицироваться на других принципалах, доступных в домене? Для этого KDC предоставляет сервис, формирующий идентификационную информацию, зашифрованную на ключах необходимых принципалов. То есть процесс аутентификации для данного клиента на произвольном принципале в домене состоит в следующем. Изначально клиент идентифицируется на KDC. Полученная на данном этапе идентификационная информация зашифрована на ключе KDC. Далее «прикладывая» к сообщению эту аутентификационную информацию клиент формирует дополнительный запрос к KDC, в котором указывает имя того принципала, к которому ему необходимо получить идентификационную информацию. Всё, что далее делает KDC это расшифровывает аутентификационную информацию, которую «приложил» клиент, достаёт оттуда идентификационные данные клиент и затем зашифровывает эту же идентификационную информацию, но уже на ключе того принципала, идентификацию для которого запросил клиент. То есть процесс крайне прост: расшифровал данные на одном ключе, скопировал их и зашифровал на другом ключе. Далее вновь зашифрованная идентификационная информация пересылается обратно клиенту, и теперь клиент может переслать её (произвести процесс аутентификации) другому принципалу. Это принципал, в свою очередь, сможет эту аутентификационную информацию расшифровать. Теперь для этого принципала наш клиент считается аутентифицированным.

Нужно также понимать одну особенность KDC: он выдаёт аутентификационную информацию для любого принципала в системе, вне зависимости от того имеет ли конкретный клиент Kerberos туда доступ или нет. Это происходит потому, что Kerberos является протоколом аутентификации, а вопрос доступа уже относится к понятию авторизации.

Технически запрос к KDC на предоставление аутентификационной информации для другого принципала формируется с помощью сообщения KDC‑TGS‑REQ. Идентификационная информация, которую ранее получил клиент в сообщении KDC‑AS‑REP, сохраняется в KDC‑TGS‑REQ в поле «additional‑tickets». Также для Active Directory возможно передать эту идентификационную информацию в PA‑DATA используя тип PA‑TGS‑REQ. Имя принципала, для которого клиент хочет получить идентификационную информацию, сохраняется в поле «sname» (service name). Также в KDC‑TGS‑REQ пересылается ещё одна внутренняя структура, которая имеет тип Authenticator. Эта структура имеет в своём составе время формирования KDC‑TGS‑REQ, а также продублированное имя принципала из другой части KDC‑TGS‑REQ. Также Authenticator шифруется на сессионном ключе, который клиент получает вместе с KDC‑AS‑REP. Использование Authenticator позволяет в какой‑то мере противостоять атакам, связанным с повторной передачей данных. Для этого на KDC ведётся учёт всех ранее полученных данных из Authenticator, и если приходит сообщение, в котором все значения совпадают с ранее полученными, то KDC возвращает в ответ ошибку.

В ответ на KDC‑TGS‑REQ сервис KDC присылает сообщение KDC‑TGS‑REP, в котором содержится идентификационная информация для нужного принципала. Далее будем обозначать эту идентификационную информацию как «Service Ticket» (ST).

Теперь необходимо пояснить, как же именно происходит передача ST на сторону нужного принципала (сервиса).

Передача service ticket для идентификации на сервисе

Как я уже говорил, «сервисом» может был любая программа, предоставляющая возможность по запросу выполнять заранее известный функционал. Любой «сервис» может осуществлять коммуникации по любым протоколам. Один сервис «слушает» запросы только по HTTP, другой только по SMB, третий — по какому‑то собственному проприетарному протоколу. Однако хотелось бы, чтобы можно было выполнять аутентификацию клиента как можно проще и унифицировано. Одним из способов такой унификации является использование Generic Security Service Application Program Interface (GSS‑API, RFC 2743, RFC 4121). На самом деле в GSS‑API описан просто набор общих функций, их параметров, а также некие общие заголовки передаваемых сообщений. Также описывается, какой именно результат должен быть достигнут от выполнения определённой функции с определёнными параметрами. То есть вроде «если выполнишь сначала такую, а потом вот такую функции, то аутентифицируешь клиента». Всё максимально просто. Собственно внутренняя реализация функций GSS‑API остаётся за производителем операционной системы. В Windows реализация GSS‑API известна под названием Security Support Provider Interface (SSPI). С помощью SSPI можно работать не только с Kerberos (и GSS‑API изначально сделан с возможностью поддержки множества протоколов аутентификации). Можно даже писать свои собственные «провайдеры», обслуживающие аутентификацию по произвольным протоколам.

Однако вернёмся к работе с Kerberos с помощью SSPI. Сам по себе SSPI является неким набором стандартных функций, реализация же этих функций называется SSP (Security Support Provider). По сути, в операционной системе Windows SSP реализует функционал «стандартного клиента Kerberos», а также «стандартного сервера/сервиса Kerberos», и в Windows больше нет никаких других API, которые бы работали с Kerberos. Для «стандартного клиента» достаточно использовать только две функции: AcquireCredentialsHandle (реализация GSS_Acquire_cred из RFC 2743) и InitializeSecurityContext (реализация функции GSS_Init_sec_context из RFC 2743). Для «стандартного сервиса» достаточно также только двух функций: ранее упомянутой AcquireCredentialsHandle, и AcceptSecurityContext (реализация GSS_Accept_sec_context из RFC 2743). Функции InitializeSecurityContext и AcceptSecurityContext реализованы так, чтобы воспринимать выходную информацию друг друга. То есть на клиенте вызывается InitializeSecurityContext, затем сама эта функция внутри, если нужно, запрашивает TGT для нужного пользователя, затем запрашивается ST (service ticket) для нужного принципала, из‑под которого выполняется нужный «сервис». Далее выходная информация из функции InitializeSecurityContext каким‑то образом (безразлично каким конкретно, позже я покажу реальные реализации такой коммуникации) попадает на сторону «сервиса». Внутри «сервиса» выполняется вызов функции AcceptSecurityContext, в которую без изменений передаётся весь бинарный массив данных, ранее сформированный на клиенте с помощью InitializeSecurityContext. В качестве результата работы функции AcceptSecurityContext возвращаются различные флаги. С помощью этих флагов можно определить, смогли ли внутренние алгоритмы AcceptSecurityContext идентифицировать клиента или нет. Также есть специальная функция QueryContextAttributes с помощью которой можно получить различные переменные «контекста», как то SPN того ST, который поступил на вход, имя клиента, которое существует в данном ST и так далее. В некоторых случаях может случиться так, что AcceptSecurityContext потребуется дополнительная информация со стороны клиента. В этом случае AcceptSecurityContext формирует свой выходной бинарный буфер, который также должен быть переслан обратно на сторону клиенте (безразлично каким именно способом). Ну и далее по кругу: InitializeSecurityContext — AcceptSecurityContext, до тех пор, пока AcceptSecurityContext не возвратит флаг ошибки или успешно идентифицирует клиента.

На самом деле все «выходные бинарные буфера» для обеих функций реализуют стандартное кодирование информации, принятое в GSS‑API. Опишу заголовок данных при передаче сообщений Kerberos. Заранее упомяну, что обычно стандартные клиенты Kerberos использует SPNEGO (RFC4178), реализация которого есть в Windows в SSP (Security Support Provider) с именем «Negotiate». Однако SPNEGO это просто «надстройка», позволяющая выбрать при авторизации NTLM или Kerberos. В реальности можно вместо SPNEGO применять напрямую SSP Kerberos. Итак, в GSS‑API все внутренние сообщения протокола сначала идентифицируются OID (Object Identifier) в формате ASN.1. Для Kerberos данный OID имеет значение «1.2.840.113 554.1.2.2». После OID идёт 2 байта типа внутреннего сообщения Kerberos. Эти байты могут иметь следующие значения:

  • 0×0001 = KERB‑AP‑REQUEST

  • 0×0002 = KERB‑AP‑REPLY

  • 0×0003 = KERB‑ERROR

  • 0×0004 = KERB‑TGT‑REQUEST

  • 0×0104 = KERB‑TGT‑REPLY

Последние два типа сообщений могут применяться только в том случае, когда «сервис» работает по схеме U2U (сервис не имеет имени и пароля пользователя и может обмениваться запросами только по предварительно согласованным сессионным ключам). Более подробно про U2U я напишу позже в статье.

За двумя байтами типа идут собственно данные Kerberos. То есть если тип GSS‑API сообщения равен 0×0001 (KERB‑AP‑REQUEST), то далее хранится обычный AP‑REQ. Если тип GSS‑API сообщения равен 0×0003 (KERB‑ERROR), то далее хранится обычное сообщение KRB‑ERROR, кодированное в ASN.1. В случае использования GSS‑API (а в Windows всегда используется GSS‑API) внутри AP‑REQ будет формироваться специальным образом сформированный authenticator. Особенным является поле checksum. Вместо использования стандартного алгоритма Kerberos для формирования checksum, в GSS‑API применяется набор дополнительных флагов. Именно эти флаги регулируют, будет ли информация из AP‑REQ использована для делегирования, ожидает ли клиент каких‑то дополнительных сообщений (mutual authentication), информацию по channel binding. С полным перечнем этих флагов можно ознакомиться в RFC4121, item 4.1.1.

Разберём теперь более подробно параметры, которые необходимо передавать для каждой из упомянутых функций. Первая функция в нашем списке AcquireCredentialsHandle. Функция служит для последующей передачи в «security context» (контекст безопасности) информации по используемым реквизитам для входа (credentials). В качестве реквизитов для входа может использоваться как пустые значения, имя пользователя и пароль, или специальным образом кодированный идентификатор сертификата пользователя.

В случае пустых значений реквизиты для входа берутся из уже объявленных в текущей «logon session» (сессии входа в систему). Нужно заметить, что все данные, с которыми работают функции SSPI, а также все артефакты, которые они сохраняют на локальном компьютере, сохраняются в разрезе «logon sessions». На компьютере таких сессий может быть множество, для множества различных пользователей. Идентифицируются «logon sessions» по специальному идентификатору «Logon Unique IDentifier» (LUID), полный список существующих на компьютере сессий можно получить с помощью функции LsaEnumerateLogonSessions. Для того, чтобы в текущей logon session существовали реквизиты для входа необходимо, чтобы до этого они были явно в эту сессию добавлены. Это делается либо через вызов AcquireCredentialsHandle, либо с помощью вызова функции LsaLogonUser (которая, в свою очередь, неявно вызывает всё ту же AcquireCredentialsHandle). Если в текущей сессии уже есть реквизиты для входа, то можно реализовать «фантастический хак» — вызвать AcquireCredentialsHandle без указания пользователя и пароля и всё заработает.

Использование AcquireCredentialsHandle с указанием имени пользователя и пароля является тривиальным, и я пропущу объяснение этого варианта.

Гораздо более интересным является вариант указания реквизитов для входа с помощью идентификатора сертификата пользователя. Для реализации этого варианта необходимо, чтобы в хранилище сертификатов «Personal» (MY) текущего пользователя существовал сертификат, выданный центром сертификации текущего домена, в котором в качестве SAN (Subject Alternative Name) был бы указан UPN (User Principal Name) в формате «user@domain». Этот сертификат также должен иметь связанный закрытый ключ. Для формирования идентификатора сертификата, который можно передать в функцию AcquireCredentialsHandle, понадобится использовать функцию CredMarshalCredentialW, в которую должна быть передана структура типа CERT_CREDENTIAL_INFO. Основной информацией, которую содержит CERT_CREDENTIAL_INFO, является SHA-1 хэш необходимого нам сертификата. Такой хэш можно получить, например, с помощью функции CryptHashCertificate. Как результат вызова CredMarshalCredentialW мы получим строку, подобную этой: «@@BRi6zZsVIijBXbuYDYub3SKfcO7H». Пример программы, формирующей подобную строку из произвольного сертификата, можно найти по этой ссылке.

Эту строку можно передать в значение имени пользователя для функции AcquireCredentialsHandle. Если у используемого сертификата установлен PIN для доступа к закрытому ключу, то его также будет необходимо указать в значении «пароль пользователя». После указания подобного идентификатора сертификата ближайший вызов InitializeSecurityContext или AcceptSecurityContext будет формировать запрос на получение TGT с использованием PKINIT, а не с использованием стандартного способа шифрования на пароле. В результате использования сертификата для реквизитов входа можно получить сессию, в которой отсутствуют имя пользователя и пароль. Однако, как я уже писал ранее, Kerberos базируется на том, что для успешной коммуникации с такой сессией необходимо, чтобы была возможность использования пароля. Как же всё работает при использовании сертификатов (PKINIT)? В этом случае используется специальное расширение протокола, называемое «User‑To‑User» (U2U). При использовании этого расширения коммуникации производятся без помощи шифрования на пароле, а только с использованием согласованных сессионных ключей. Более подробно про это расширение я напишу позднее.

Как оказалось, результат вызова CredMarshalCredentialW можно передавать во многих случаях, когда требуется информация о реквизитах доступа. То есть, например, возможно указать строковый идентификатор сертификата при указании имени пользователя, из‑под которого запуститься произвольный сервис. Или можно локально зайти в систему, вообще не зная имени пользователя и пароля. Однако, как я уже ранее писал, в этих случаях необходимо, чтобы используемый сертификат содержался в хранилище «Personal» для текущего пользователя. И в случае логина сервиса (здесь под «сервисом» понимается программа, запускаемая в оснастке «Services»), или выполнения первичного входа в систему, таким текущим пользователем будет SYSTEM. Для того, чтобы добавить произвольный сертификат в «Personal» для SYSTEM понадобится использовать любой «token stealer» и с его помощью запустить «mmc.exe». Там добавить оснастку «Certificates» и выполнить импорт сертификата. После этого будет доступен как бы функционал смарт‑карт, но без использования самих смарт‑карт, просто с использованием чистых сертификатов: вводите в поле «User name» строку, которую получили с помощью CredMarshalCredentialW и нажимаете Enter. Кстати, запуск сервисов без использования паролей полностью исключает использование атаки вида «Silver Ticket» так как даже если злоумышленник узнал пароль учётной записи для данного «сервиса» всё равно все коммуникации с этим сервисом будут проведены с помощью сессионного ключа и PAC всё равно будет сформирован на KDC.

Использование сертификата для интерактивного входа в систему

Использование сертификата для интерактивного входа в систему

Перейдём к следующей функции: InitializeSecurityContext. Данная функция предназначена для создания первичного запроса к удалённому «сервису» и, если необходимо, передачи дополнительной информации, необходимой для окончательной идентификации клиента на удалённой системе. Как я уже писал ранее, все функции из SSPI работают с данными из текущей «logon session». Если в текущей сессии нет ранее полученного TGT, то первый вызов InitializeSecurityContext попытается этот TGT получить. Если же в сессии уже есть TGT, то будет просто сформирован запрос KDC‑TGS‑REQ, содержащий этот TGT и информацию о сервисе, ST (service ticket) для которого необходимо получить. После получения требуемого ST он сохраняется во внутренних структурах текущей «logon session». Если в дальнейшем любой программе, запускаемой в рамках той же «logon session», понадобится ST для того же сервиса, и этот ST будет иметь корректный временной интервал использования, то этот ST будет получен из «кэша», без запроса к KDC вообще. После получения требуемого ST функция InitializeSecurityContext формирует выходной бинарный буфер (его формат я уже ранее описывал) и ожидает, что этот буфер будет каким‑то образом передан на сторону «сервиса». Примеры передачи подобного буфера представлены ниже.

Последний скриншот взят из этой презентации

Последний скриншот взят из этой презентации

Если при первом запуске для InitializeSecurityContext был использован флаг ISC_REQ_MUTUAL_AUTH, то функция будет ожидать ответный буфер, сформированный на стороне «сервиса» с помощью AcceptSecurityContext. Со своей стороны я рекомендую всегда использовать флаг ISC_REQ_MUTUAL_AUTH так как сервис может вернуть какую‑то ошибку, которую на клиенте можно обработать. Например, «сервис» может вернуть ошибку с кодом, указывающим на то, что требуется прохождение идентификации на основе сессионного ключа (U2U). И если клиент не ожидает входящего сообщения, то коммуникация с приходом этой ошибки будет полностью прекращена. Значение всех используемых в SSPI флагов можно найти по этой ссылке.

Работа функции AcceptSecurityContext в начале аналогична работе InitializeSecurityContext: функция AcceptSecurityContext также может получить TGT для «сервисной» части, если это будет нужно. В этой функции также можно инициализировать контекст безопасности с использованием явно заданных имени пользователя, пароля или сертификата. Однако в отличие от InitializeSecurityContext функция AcceptSecurityContext просто ждёт входящих сообщений. После получения входящего сообщения (в виде бинарного буфера, сформированного на клиенте с помощью InitializeSecurityContext) функция AcceptSecurityContext может либо вернуть какой‑то свой бинарный буфер, который подлежит отправке на сторону клиента, либо завершается с кодом, соответствующим успешному прохождению идентификации для удалённого клиента. В последнем случае «сервис» может, например, выделить отдельный процесс и в нём вызвать функцию ImpersonateSecurityContext — в этом случае этот новый процесс будет использовать «access token» (токен безопасности) в котором будут представлены все данные по идентификационной информации удалённого клиента (все его группы, привилегии и так далее). Важно заметить, что если функция AcceptSecurityContext смогла успешно идентифицировать удалённого клиента, то это автоматически приводит к тому, что на локальном для «сервиса» компьютере появляется новая «logon session» для удалённого пользователя. Это необходимо, в частности, для того, чтобы «сервис» в дальнейшем мог организовать «делегирование» идентификационной информации (об этом позже в статье). В этой новой «logon session» по умолчанию будет отсутствовать какая‑либо информация по реквизитам доступа: там не будет TGT, не будет сохранённого имени пользователя и пароля. Всё, что будет в этой новой сессии это «access token», который можно использовать, например, для проверки прохождения авторизации на локальных ресурсах. Таким образом, в общем случае функция AcceptSecurityContext в качестве своей конечной выходной информация позволяет создавать на локальной системе новую «logon session», а также новый «access token», содержащий всю идентификационную информацию для удалённого клиента. Необходимо сказать, что AcceptSecurityContext создаёт такой «access token» используя исключительно только ту идентификационную информацию, которая поступила этой функции на вход. То есть AcceptSecurityContext самостоятельно не выполняет никаких обращений к KDC, за исключением вызова функций проверки «подписей» внутри PAC. Ещё одной особенностью AcceptSecurityContext является тот факт, что у этой функции нет никакого параметра, в который бы передавалось имя того «сервиса», от имени которого эта функция в настоящий момент работает. То есть этой функции нет разницы работает она от имени сервиса «host/server», или «cifs/server» — всё, что ей нужно это реквизиты входа (credentials) текущего «сервиса». Вот здесь можно почитать про то, как человек переписывался с Microsoft по этому вопросу, и ему подтвердили, что фактически имя сервиса не является каким‑то влияющим на аутентификацию параметром.

Дополнительной особенностью «сервисного контекста» в SSPI является то, что в этом контексте может существовать одновременно несколько credentials. То есть на самом деле один «сервис» может корректно обрабатывать запросы, направляемые в адрес нескольких различных пользователей/сервисов. Например, если у «user_1» сконфигурирован SPN_1, а у user_2 сконфигурирован SPN_2, то можно сделать так, что «сервисный контекст» (посредством функции AcceptSecurityContext) сможет корректно обработать входящие service tickets как для SPN_1, так и для SPN_2. Реализуется подобный функционал с помощью вызовов функции LsaCallAuthenticationPackage с типами сообщений KerbAddExtraCredentialsMessage или KerbAddExtraCredentialsExMessage. Добавление дополнительных идентификационных данных будет работать только в текущей logon session, в других сессиях дополнительные идентификационные данные будут отсутствовать.

Теперь, когда я описал основные функции, которые создают изменения в «контексте безопасности» (security context) необходимо также рассказать о функциях получения информации из «контекста безопасности». Таких функций всего две: QueryContextAttributes и LsaCallAuthenticationPackage. Описание первой функции можно найти здесь. С её помощью можно получить крайне ограниченную информацию из контекста безопасности. Например, на стороне «сервиса» после успешной идентификации с помощью AcceptSecurityContext функция QueryContextAttributes может получить непосредственное значение «access token», получить значение SPN из ST, или имя пользователя из ST. Функция LsaCallAuthenticationPackage является гораздо более интересной. Данная функция служит неким общим интерфейсом для вызова внутреннего функционала произвольного SSP. Реализуется подобная универсальность посредством существования у каждого «security provider» собственных наборов входных и выходных параметров, которые приводятся к нейтральным общим типам и передаются в LsaCallAuthenticationPackage. Перечень входных параметров для Kerberos можно найти по этой ссылке. Однако в официальном описании отсутствуют описания типов входных и выходных структур, передаваемых вместе с каждым из типов сообщений. Ниже я привожу собственную таблицу таких соответствий. Для более прозрачной работы я реализовал специализированные функции и типы внутри библиотеки XKERB.

Тип

Тип структуры входных данных

Тип структуры выходных данных

Реализовано в XKERB

KerbDebugRequestMessage

?

?

Нет

KerbQueryTicketCacheMessage

KERB_QUERY_TKT_CACHE_REQUEST

KERB_QUERY_TKT_CACHE_RESPONSE

Да

KerbChangeMachinePasswordMessage

?

?

Нет

KerbVerifyPacMessage

?

?

Нет

KerbRetrieveTicketMessage

KERB_RETRIEVE_TKT_REQUEST

KERB_RETRIEVE_TKT_RESPONSE

Да

KerbUpdateAddressesMessage

?

?

Нет

KerbPurgeTicketCacheMessage

KERB_PURGE_TKT_CACHE_REQUEST

null

Да

KerbChangePasswordMessage

KERB_CHANGEPASSWORD_REQUEST

null

Да

KerbRetrieveEncodedTicketMessage

KERB_RETRIEVE_TKT_REQUEST

KERB_RETRIEVE_TKT_RESPONSE

Да

KerbDecryptDataMessage

KERB_DECRYPT_REQUEST

KERB_DECRYPT_RESPONSE

Нет

KerbAddBindingCacheEntryMessage

KERB_ADD_BINDING_CACHE_ENTRY_REQUEST

null

Да

KerbSetPasswordMessage

KERB_SETPASSWORD_REQUEST

null

Да

KerbSetPasswordExMessage

KERB_SETPASSWORD_EX_REQUEST

null

Нет

KerbAddExtraCredentialsMessage

KERB_ADD_CREDENTIALS_REQUEST

null

Да

KerbVerifyCredentialsMessage

?

?

Нет

KerbQueryTicketCacheExMessage

KERB_QUERY_TKT_CACHE_REQUEST

KERB_QUERY_TKT_CACHE_EX_RESPONSE

Да

KerbPurgeTicketCacheExMessage

KERB_PURGE_TKT_CACHE_EX_REQUEST

null

Нет

KerbRefreshSmartcardCredentialsMessage

KERB_REFRESH_SCCRED_REQUEST

null

Нет

KerbQuerySupplementalCredentialsMessage

?

?

Нет

KerbTransferCredentialsMessage

KERB_TRANSFER_CRED_REQUEST

null

Нет

KerbQueryTicketCacheEx2Message

KERB_QUERY_TKT_CACHE_REQUEST

KERB_QUERY_TKT_CACHE_EX2_RESPONSE

Да

KerbSubmitTicketMessage

KERB_SUBMIT_TKT_REQUEST

null

Да

KerbAddExtraCredentialsExMessage

KERB_ADD_CREDENTIALS_REQUEST_EX

null

Да

KerbQueryKdcProxyCacheMessage

KERB_QUERY_KDC_PROXY_CACHE_REQUEST

KERB_QUERY_KDC_PROXY_CACHE_RESPONSE

Да

KerbPurgeKdcProxyCacheMessage

KERB_PURGE_KDC_PROXY_CACHE_REQUEST

KERB_PURGE_KDC_PROXY_CACHE_RESPONSE

Да

KerbQueryTicketCacheEx3Message

KERB_QUERY_TKT_CACHE_REQUEST

KERB_QUERY_TKT_CACHE_EX3_RESPONSE

Да

KerbCleanupMachinePkinitCredsMessage

KERB_CLEANUP_MACHINE_PKINIT_CREDS_REQUEST

null

Нет

KerbAddBindingCacheEntryExMessage

KERB_ADD_BINDING_CACHE_ENTRY_EX_REQUEST

null

Да

KerbQueryBindingCacheMessage

KERB_QUERY_BINDING_CACHE_REQUEST

KERB_QUERY_BINDING_CACHE_RESPONSE

Да

KerbPurgeBindingCacheMessage

KERB_PURGE_BINDING_CACHE_REQUEST

null

Да

KerbPinKdcMessage

KERB_PIN_KDC_REQUEST

null

Да

KerbUnpinAllKdcsMessage

KERB_UNPIN_ALL_KDCS_REQUEST

null

Да

KerbQueryDomainExtendedPoliciesMessage

KERB_QUERY_DOMAIN_EXTENDED_POLICIES_REQUEST

KERB_QUERY_DOMAIN_EXTENDED_POLICIES_RESPONSE

Да

KerbQueryS4U2ProxyCacheMessage

KERB_QUERY_S4U2PROXY_CACHE_REQUEST

KERB_QUERY_S4U2PROXY_CACHE_RESPONSE

Да

KerbRetrieveKeyTabMessage

KERB_RETRIEVE_KEY_TAB_REQUEST

KERB_RETRIEVE_KEY_TAB_RESPONSE

Да

KerbRefreshPolicyMessage

KERB_REFRESH_POLICY_REQUEST

KERB_REFRESH_POLICY_RESPONSE

Да

KerbPrintCloudKerberosDebugMessage

KERB_CLOUD_KERBEROS_DEBUG_REQUEST

KERB_CLOUD_KERBEROS_DEBUG_RESPONSE

Нет

Как можно заметить, с помощью LsaCallAuthenticationPackage можно как просто получать информацию, так и запрашивать действия со стороны «security provider». Для автоматизации определённых вызовов LsaCallAuthenticationPackage я написал вспомогательный код, который можно найти здесь.

Также здесь можно упомянуть, что в Windows существует стандартная утилита «klist», с помощью которой можно посмотреть все существующие в текущей «logon session» TGT и service tickets. С помощью LsaCallAuthenticationPackage я реализовал аналог функциональности программы «klist», выводящий информацию по кэшированным тикетам Kerberos, код приведён здесь.

Ещё одной, играющей вспомогательную роль, является функция LsaLogonUser. Эта функция также запрашивает новый TGT для пользователя по его реквизитам для входа. Напомню, что в этой функции также можно использовать текстовое представление идентификатора сертификата. Однако в отличие от ранее рассмотренных функций LsaLogonUser после успешного получения TGT автоматически создаёт новую «logon session». Как я ранее писал, такой функциональностью из ранее рассмотренных функций обладает только AcceptSecurityContext. Так как все действия в SSPI так или иначе привязаны к «logon session», то лично я считаю, что если необходимо в программе реализовать какой‑то «сервис» имея предопределённые реквизиты для входа, то крайне полезным будет сначала явно сделать «logon session», и уже потом в рамках этой новой сессии вызывать функции InitializeSecurityContext/AcceptSecurityContext. С использованием данного подхода я реализовал некий «универсальный клиент‑сервисный код»: в одной функции вызываются как клиентские, так и сервисные функции. Это позволяет протестировать клиент‑сервисное взаимодействие без использования каких‑либо коммуникаций. Данный код находится здесь.

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

Делегирование

Под «делегированием» в Kerberos понимается процесс, когда клиент каким‑либо образом передаёт «сервису» возможность действовать, используя идентификационную информацию клиента. Это бывает необходимо в тех случаях, когда клиент поручает «сервису» выполнить операцию, которая, в свою очередь, требует обращения к другим «сервисам». В этом случае первичному «сервису» будет необходимо получить возможность самостоятельно получать Service Ticket (ST) от имени клиента к другим «сервисам». Конечно, можно было бы как‑то организовать обратную коммуникацию с клиентом, запрос у него ST для другого «сервиса», передача этого ST обратно и так далее. Однако технически это зачастую сложно реализуемо. Например, если «сервис» является HTTP сервисом, то у него очень ограниченная возможность обратной коммуникации с клиентом по своей инициативе. Поэтому Kerberos предоставляет функционал, позволяющий делегировать идентификационную информацию клиентов на определённые «сервисы».

Существуют следующие виды делегирования:

  1. Неограниченное делегирование;

  2. Ограниченное делегирование с использование только протокола Kerberos;

  3. Ограниченное делегирование с использование произвольного протокола;

Перед описание каждого вида делегирования подробно приведу одно общее замечание. Чтобы «сервис» мог кешировать (и в дальнейшем использовать) TGT от других пользователей данный «сервис» должен исполняться из‑под пользователя, у которого активна привилегия SeEnableDelegationPrivilege (SE_ENABLE_DELEGATION_NAME).

Неограниченное делегирование

В случае неограниченного делегирования клиент передаёт на сервис свой TGT вместе с его текущим сессионным ключом. Имея эту информацию «сервис» в дальнейшем может самостоятельно запросить Service Ticket (ST) к любому существующему «сервису». Коммуникации никак не ограничены.

Ограниченное делегирование с использованием только Kerberos

В случае ограниченного делегирования вместо TGT на сторону «сервиса» передаётся только ST. Далее «сервис» может, используя расширение S4U2Proxy, запросить от имени пользователя ST к другому «сервису». Набор «сервисов», к которым данный «сервис» может получить ST от имени пользователя, заранее определён и ограничен.

Несмотря на то, что механизм ограниченного делегирования с использованием только Kerberos реализован в Windows уже очень давно, и, вроде как, должен быть полностью отлажен у меня в тестовых сервисах не получилось реализовать делегирование с использованием этого режима. После аутентификации клиента на сервисе 1 в сессии возникал соответствующий service ticket от этого клиента к сервису 1. И этот service ticket даже имел установленный FORWARDABLE флаг. Однако если я пытался из этой сессии выполнить запрос к сервису 2, то функции SSPI не включали уже имеющийся service ticket и вместо этого пытались заново запросить TGT для клиента с использованием S4U2Self. В ответ формировался TGT, однако без флага FORWARDABLE. И, как результат, запрос на получение service ticket для сервиса 2 отклонялся.

Ограниченное делегирование с использованием произвольного протокола

Здесь клиент может присылать на сервис только service ticket, однако «сервис» имеет дополнительную возможность самостоятельно, вообще без какого‑либо участия клиента запрашивать его идентификационную информацию. Повторюсь, что в случае «делегирование без ограничения протоколов» пользователь всё также может передать ST с на сторону «сервиса», эта функциональность в данном виде делегирования осталась без изменений.

Для реализации запроса «сервисом» идентификационной информации для произвольного клиента было реализовано расширение Service for User to Self (S4U2self). Представим, что есть какой‑то «сервис», который выполняет идентификацию пользователей по биометрии, скажем на основании анализа лица пользователя. И для этого «сервис» использует специфическое оборудование, специальные вызовы драйверов и так далее. База данных лиц пользователей также будет какой‑то специализированной. Также предположим, что этот «сервис» должен выполнять аутентификацию пользователей домена, и использовать для этого Kerberos. В случае подобной задачи внутри «сервиса» будет нужна дополнительная база, сопоставляющая имена пользователей домена с их идентификационными данными, специфичными для данного «сервиса» (в нашем случае — с изображениями их лиц). Таким образом, после успешной идентификации пользователя по его лицу «сервис» теперь может получить имя пользователя в домене. Далее, используя расширение S4U2Self, данный «сервис» сможет запросить аутентификационную информацию пользователя по протоколу Kerberos зная только его имя и далее получить возможность аутентификации данного пользователя на других «сервисах» (логин на рабочую станцию, доступ к файлам по сети и так далее).

На самом деле использовать S4U2Self может абсолютно любой пользователь, который уже прошёл идентификацию в домене. То есть если у пользователя есть TGT, то он может запросить идентификационную информацию по любому другому пользователю, машине или даже «сервису» (по имени «сервиса»). Нет никаких ограничений на то, от имени кого будут приходить запросы S4U2Self, запросы может делать как полноценный «сервис», так и обычный пользователь.

Расширение S4U2Self реализуется с помощью всего двух дополнительных структур: PA‑FOR‑USER и PA‑S4U‑X509-USER. Использование этих двух структур является взаимоисключающим (можно использовать только один из двух типов в одном запросе). При использовании PA‑FOR‑USER можно запрашивать информацию только на основе имени пользователя. При использовании PA‑S4U‑X509-USER можно запрашивать информацию как на основе имени пользователя, так и на основе X.509 сертификата пользователя. В MS‑SFU также упоминается, что если текущий домен поддерживает схемы шифрования с использованием AES-128 и выше, то рекомендуется всегда использовать PA‑S4U‑X509-USER.

Реализация SSP Kerberos в Windows поддерживает использование S4U2Self, но только опосредованно, через вызов LsaLogonUser с параметрами KERB_S4U_LOGON или KERB_CERTIFICATE_S4U_LOGON. На основании использования этой функция я создал некий «whoami на S4U», позволяющий выводить всю информацию любого пользователя — как то его группы, SID, набор привилегий. Код данного проекта доступ по этой ссылке.

Использование S4U2Self позволяет получить идентификационную информацию для любого пользователя, однако это позволяет идентифицировать пользователя только локально на той машине, на которой запущен «сервис». Для того, чтобы реализовать возможность делегирования идентификационных данных пользователей на других «сервисах» было реализовано другое расширение Kerberos — S4U2Proxy.

Расширение S4U2Proxy позволяет запрашивать у KDC service ticket от имени любого пользователя к ограниченному набору сервисов. Внутри расширение S4U2Proxy реализовано просто в виде двух дополнительных флагов: флага «resource‑based constrained delegation» внутри PA‑PAC‑OPTIONS, и флага «cname‑in‑addl‑tkt» внутри KDC_OPTIONS. Использование флага CNAME‑IN‑ADDL‑TKT позволяет запросить ST для того пользователя, имя которого содержится в «additional tickets». Использование флага «resource‑based constrained delegation» позволяет использовать возможности RBCD (Resource‑Based Constrained Delegation).

Как ни странно, несмотря на официальную документацию Microsoft (MS‑SFU), флаг CNAME‑IN‑ADDL‑TKT на самом деле не используется. То есть ни одна функция SSPI не выставляет данный флаг и не учитывает его при приёме сообщений. Как минимум так было у меня во всех возможных проводимых тестах. Вместо этого, похоже, имя клиента автоматически берётся из additional ticket если это поле содержит какое‑то значение.

Использование RBCD позволяет более тонко конфигурировать получение service tickets для каждого из «сервисов». При использовании RBCD каждый пользователь, из‑под которого запускается какой‑либо «сервис», может сконфигурировать свой список других пользователей, которым доступна возможность делегирования на этот «сервис». То есть в атрибуте msDS‑AllowedToActOnBehalfOfOtherIdentity для данного пользователя может содержаться полноценный security descriptor (SD), в котором будут прописаны полноценные Access Control Lists (ACLs). Представим, что клиент сформировал запрос для «сервиса 1». В процессе деятельности «сервис 1» должен выполнить какие‑то действия на «сервис 2» используя аутентификационную информацию для клиента. При использовании RBCD «сервис 2» должен иметь в msDS‑AllowedToActOnBehalfOfOtherIdentity такой security descriptor, который бы позволял доступ для пользователя, из‑под которого запускается «сервис 1». Также необходимо понимать крайне важную особенность RBCD: если для какого‑то пользователя сконфигурирован SD, который позволяет выполнить делегирование для «сервис 1», то режим делегирования для «сервис 1» не учитывается. То есть если «сервис 1» сконфигурирован так, чтобы не позволять делегирование (режим «Do not trust this user for delegation»), то он всё равно сможет выполнить делегирование к «сервис 2», если у «сервис 2» сконфигурирован security descriptor, позволяющий доступ для «сервис 1». Также KDC не учитывает ограничения делегирования по именам. То есть если для «сервис 1» задано ограниченное делегирование, и «сервис 2» не присутствует в списке, то делегирование на «сервис 2» всё равно будет выполнено, если на «сервис 2» задан корректный security descriptor, позволяющий доступ для «сервис 1».

User-To-User (U2U)

Как уже было сказано, протокол Kerberos использует шифрование на заранее известных ключах, генерируемых на основе текстовых паролей. Однако существуют варианты, когда пользователь будет запускать какой‑либо «сервис», не обладая знанием о собственном пароле. Это может быть, например, в случае использования X.509 сертификата для первичной аутентификации. В этом случае необходимо иметь возможность так или иначе обмениваться аутентификационной информацией между клиентами и подобным «сервисом». Для реализации подобного функционала была придумана схема U2U.

При использовании U2U работа с «сервисом» для клиента начинается с посылки стандартного сообщения AP‑REQ. Однако, так как «сервис» не имеет информации о собственном пароле, то «сервис» в ответ формирует ошибку с кодом KRB_AP_ERR_USER_TO_USER_REQUIRED (0×45). Для того, чтобы клиент смог получить эту ошибку на «сервисе» должен быть использован флаг ASC_REQ_EXTENDED_ERROR, а на клиенте должен быть использован флаг ISC_REQ_MUTUAL_AUTH чтобы клиент ожидал какой‑то информации со стороны «сервиса». Можно также явно задать флаги ISC_REQ_USE_SESSION_KEY и ASC_REQ_USE_SESSION_KEY, но в этом случае общая система теряет универсальность: клиент сразу начинает с запроса TGT для «сервиса».

Итак, после получения ошибки клиент понимает, что необходимо реализовать общение с использованием не постоянных, а сессионных ключей. Для этого клиент сперва формирует запрос на «сервис» для получения TGT этого сервиса. Данный запрос формируется на уровне GSS‑API, и представляет собой, по сути, специальный Object Identificator (OID). В ответ «сервис» возвращает свой TGT. Передача TGT в данном случае условно безопасна, так как вместе с TGT не передаётся его сессионный ключ. После получения этого TGT клиент формирует специальный запрос к KDC на получение service ticket, в котором устанавливается флаг ENC‑TKT‑IN‑SKEY, а также в поле additional tickets добавляется TGT, полученный со стороны «сервиса». В свою очередь KDC расшифровывает TGT из additional ticket, получает оттуда session key, а затем формирует новый service ticket, шифруя его уже на этом session key. После получения нового service ticket (ST) клиент далее может переслать этот ST заново необходимому «сервису». Теперь «сервис» может расшифровать этот полученный ST и провести аутентификацию клиента стандартным образом.

Тестирование Kerberos

Теперь, когда я описал все основные возможности стандартных клиента и серверной части Kerberos в Windows, можно перейти к описанию схемы тестирования этого функционала. Так как в Windows только в SSPI реализована возможность работы с Kerberos, то естественно, что для тестирования будут использоваться только стандартные функции SSPI. Например, вот здесь приведены ссылки на тестовые примеры по SSPI от Microsoft. В этих примерах существует однозначное разделение на программу, выполняющую клиентскую часть, и программу, которая реализует функции «сервиса». Однако всё можно упростить, если убрать передачу между «клиентом» и «сервисом» по какому‑либо стороннему каналу (вроде pipe, как в примерах от Microsoft). Вместо этого достаточно, чтобы выходной массив из функции InitializeSecurityContext был передан на вход функции AcceptSecurityContext. Для реализации полноценных «клиента» и «сервиса» на самом деле достаточно использовать двух обычных пользователей домена, у одного из которых будет непустой атрибут servicePrincipalNames (то есть будут SPNs). Изменяя параметры делегирования для «сервисного» пользователя, можно изучать различные виды этого делегирования, а также иметь возможность проконтролировать каждый из параметров как на стороне «клиента», так и «сервиса». Можно инициализировать «сервис» через сертификат (PKINIT) и получить сервисный контекст, в котором будут отсутствовать данные о логине и пароле, а обмен с таким «сервисом» будет возможен только через U2U. Можно добавлять дополнительные credentials в «сервисный» контекст и получить возможность корректно принимать «не свои» билеты: то есть если у нас в тестовом окружении будут два «сервисных» пользователя, и мы добавим credentials от второго пользователя в контекст первого, то теперь сервисный контекст первого пользователя сможет корректно обработать все AP‑REQ к SPNs от второго пользователя, абсолютно прозрачно. Можно добавлять tickets в «клиентский» или «сервисный» контекст (Push The Ticket, PTT). Можно получать какие‑то дополнительные данные из любого контекста, и так далее.

Для более удобной работы со всем этим функционалом я реализовал библиотеку XKERB, а также набор тестовых функций, позволяющий тестировать произвольный функционал SSPI. Библиотека написана на чистом С++ с использованием функционала последнего стандарта С++ 23. При работе применяются «умные указатели» и, как следствие, пользователю библиотеки нет необходимости заботиться о менеджменте памяти: все необходимые функции будут вызваны в нужное время и память будет корректно освобождена. Также в библиотеке применяется «Aggregate initialization», позволяющая передавать в функции параметры по их имени, а также прозрачно использовать опциональные параметры. Реализация библиотеки находится по этой ссылке.

В прошлой части нашего цикла мы рассмотрели работу протоколов семейства NTLM, отметив ряд их существенных недостатков, которые невозможно решить в рамках протокола. Поэтому вместе с Active Directory на смену им пришел более совершенный протокол Kerberos, который продолжает успешно применяться до сих пор. В данном материале мы рассмотрим общие принципы функционирования данного протокола, что позволит получить начальные знания в этой области самым широким массам читателей.

Онлайн-курс по устройству компьютерных сетей
На углубленном курсе «Архитектура современных компьютерных сетей» вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.

Протокол Kerberos был разработан в Массачусетском технологическом институте (MIT) в рамках проекта «Афина» в 1983 году и долгое время использовался в качестве образовательного, пока версия 4 не была сделана общедоступной. В настоящий момент принята в качестве стандарта и широко используется следующая версия протокола Kerberos 5.

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

В доменных сетях протоколы NTLM вызывают повышенную нагрузку на контроллеры домена, так как всегда обращаются к ним для аутентификации пользователя. При этом также отсутствует взаимная идентификация узлов и существует возможность накопления пакетов для последующего анализа и атаки с их помощью.

В отличии от NTLM Kerberos изначально разрабатывался с условием, что первичная передача информации будет производиться в открытых сетях, где она может быть перехвачена и модифицирована. Также протокол предусматривает обязательную взаимную аутентификацию клиента и сервера, а взаимное доверие обеспечивает единый удостоверяющий центр, который обеспечивает централизованную выдачу ключей.

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

Основой инфраструктуры Kerberos является Центр распространения ключей (Key Distribution Center, KDC), который является доверенным центром аутентификации для всех участников сети (принципалов). Область Kerberos (Realm) — пространство имен для которых данный KDC является доверенным, как правило это область ограниченная пространством имен домена DNS, в Active Directory область Kerberos совпадает с доменом AD. Область Kerberos записывается в виде соответствующего ему доменного имени DNS, но в верхнем регистре. Принципалом или учетной записью Kerberos является любой участник отношений безопасности: учетная запись пользователя, компьютер, сетевая служба и т.д.

Центр распространения ключей содержит долговременные ключи для всех принципалов, в большинстве практических реализаций Kerberos долговременные ключи формируются на основе пароля и являются так называемым «секретом для двоих». С помощью такого секрета каждый из его хранителей может легко удостовериться, что имеет дело со своим напарником. При этом долговременные ключи не при каких обстоятельствах не передаются по сети и располагаются в защищенных хранилищах (KDC), либо сохраняются только на время сеанса.

Для принципалов, которые не являются членами домена AD, могут использоваться специальные keytab-файлы, которые содержат сведения о клиенте, домене и его долговременный ключ. В целях безопасности keytab-файл нельзя передавать по незащищенным каналам, а также следует обеспечить его безопасное хранение у принципала.

В структуре Active Directory центр распространения ключей располагается на контроллере домена, но не следует путать эти две сущности, каждая из них является самостоятельной и выполняет свои функции. Так Kerberos отвечает только за аутентификацию клиентов, т.е. удостоверяет, что некто является именно тем, за кого себя выдает. Авторизацией, т.е. контролем прав доступа, занимается контроллер домена, в свою очередь разрешая или ограничивая доступ клиента к тому или иному ресурсу.

Рассмотрим каким образом происходит аутентификация клиента по протоколу Kerberos.

windows-authentication-2-002.png

Желая пройти проверку подлинности в сети, клиент передает KDC открытым текстом свое имя, имя домена и метку времени (текущее время клиента), зашифрованное долговременным ключом клиента. Метка времени в данном случае выступает в роли аутентификатора — определенной последовательности данных, при помощи которой узлы могут подтвердить свою подлинность.

Получив эти данные KDC извлекает долговременный ключ данного пользователя и расшифровывает метку времени, которую сравнивает с собственным текущим временем, если оно отличается не более чем на 5 минут (значение по умолчанию), то метка считается действительной. Эта проверка является дополнительной защитой, так как не позволяет использовать для атаки перехваченные и сохраненные данные.

Убедившись, что метка времени действительна KDC выдает клиенту сеансовый ключ и билет (тикет) на получение билета (ticket granting ticket, TGT), который содержит копию сеансового ключа и сведения о клиенте, TGT шифруется с помощью долговременного ключа KDC и никто кроме него билет расшифровать не может. Сеансовый ключ шифруется с помощью долговременного ключа клиента, а полученная от клиента метка времени возвращается обратно, зашифрованная уже сеансовым ключом. Билет на получение билета является действительным в течении 8 часов или до завершения сеанса пользователя.

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

Чтобы лучше понять этот механизм приведем небольшой пример. Если злоумышленник перехватил посланный KDC запрос, то он может на основе открытых данных послать клиенту поддельный сеансовый ключ и TGT, но не сможет расшифровать метку времени, так как не обладает долговременным ключом. Точно также, он может перехватить отправленные клиенту TGT и сеансовый ключ, но также не сможет расшифровать последний, не имея долговременного ключа. Перехватить долговременный ключ он не может, так как они по сети не передаются.

Успешно пройдя аутентификацию, клиент будет располагать сеансовым ключом, которым впоследствии он будет шифровать все сообщения для KDC и билетом на получение билета (TGT).

Теперь рассмотрим ситуацию, когда клиент хочет обратиться к серверу.

windows-authentication-2-003.png

Для этого он снова обращается к KDC и посылает ему билет на получение билета, зашифрованную сеансовым ключом метку времени и имя сервера. Прежде всего KDC расшифровывает предоставленный ему TGT и извлекает оттуда данные о клиенте и его сеансовый ключ, обратите внимание, что сам KDC сеансовые ключи не хранит. Затем сеансовым ключом он расшифровывает данные от клиента и сравнивает метку времени с текущим. Если расхождения нет, то KDC формирует общий сеансовый ключ для клиента и сервера.

Теоретически теперь данный ключ следует передать как клиенту, так и серверу. Но KDC имеет защищенный канал и установленные доверительные отношения только с клиентом, поэтому он поступает по-другому. Экземпляр сеансового ключа для клиента он шифрует сессионным ключом, а копию сеансового ключа для сервера он объединяет с информацией о клиенте в сеансовый билет (session ticket), который шифрует закрытым ключом сервера, после чего также отправляет клиенту, дополнительно зашифровав сессионным ключом.

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

Теперь, имея новый ключ и билет, клиент обращается непосредственно к серверу:

windows-authentication-2-004.png

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

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

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

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

Онлайн-курс по устройству компьютерных сетей
На углубленном курсе «Архитектура современных компьютерных сетей» вы с нуля научитесь работать с Wireshark и «под микроскопом» изучите работу сетевых протоколов. На протяжении курса надо будет выполнить более пятидесяти лабораторных работ в Wireshark.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Сколько весит гта 5 на ноутбук windows 10
  • Стабильная версия windows 10 ltsc
  • Нету вкладки совместимость на windows 10
  • Как настроить сглаживание шрифтов в windows 11
  • Intel graphics driver for windows 10 x64