Привет, Хабр!
Меня зовут Всеволод Саломадин, я ведущий аналитик-исследователь угроз кибербезопасности в компании R-Vision. Сегодня мы поговорим о системе FreeIPA, которая является одной из немногих альтернатив такого «комбайна», как Microsoft Active Directory (AD).
Учитывая закон о переходе на отечественное ПО на объектах КИИ к 2025 году, эта тема становится актуальной для многих компаний. Вместе с активным переходом на FreeIPA, у пользователей стали возникать вопросы о механизмах атак и стратегиях защиты от них. В этой статье мы рассмотрим некоторые примеры атак на инфраструктуру FreeIPA и предложим варианты их детекта с помощью SIEM-системы.
Устройство FreeIPA
FreeIPA — это набор компонентов для централизованного управления учетными записями, группами и политиками безопасности. Система включает в себя веб‑интерфейс и инструменты администрирования через командную строку. FreeIPA предоставляет централизованную аутентификацию, авторизацию и информацию об учетных записях, храня данные о пользователях, группах, хостах и других объектах, необходимых для управления аспектами безопасности локальной сети. Это решение построено на основе Red Hat Identity Management (IdM) из известных компонентов с открытым исходным кодом и стандартных протоколов с сильным акцентом на простоту управления и автоматизацию задач по установке и конфигурации.
Для лучшего понимания возможных атак в инфраструктуре FreeIPA, давайте познакомимся с ее компонентами и технологиями.
Компоненты FreeIPA
FreeIPA (и её производные, такие как ALD Pro от Astra Linux) включает в себя несколько ключевых компонентов:
-
Веб-сервер:
используется для настройки политик и управления учетными записями;
реализован на основе Apache HTTP Server.
-
Сервер каталогов 389:
обеспечивает централизованное хранение данных о пользователях и ресурсах;
использует LDAP (Lightweight Directory Access Protocol).
-
MIT Kerberos:
отвечает за аутентификацию и управление тикетами доступа (используются стандартные, как в AD, TGT и TGS, а для хранения тикета локально используется файл CCACHE);
позволяет безопасно аутентифицировать пользователей и службы в сети.
-
NTP (Network Time Protocol):
синхронизирует время между всеми компонентами системы;
обеспечивает точное время, что критично для аутентификации и безопасности.
-
DNS:
управляет доменными именами и их разрешением в IP-адреса;
включает поддержку SRV-записей для Kerberos и LDAP.
-
Система сертификатов Dogtag:
управляет цифровыми сертификатами для шифрования и аутентификации;
обеспечивает инфраструктуру открытых ключей (PKI).
Эти компоненты интегрированы для обеспечения безопасного и централизованного управления идентификацией, аутентификацией и авторизацией в доменной инфраструктуре. Подробнее с архитектурой можно ознакомиться в документации.
Логирование событий
Во FreeIPA предусмотрены следующие журналы для логирования:
/var/log/httpd/error_log
: FreeIPA API call logs (and Apache errors) — анализирует обращения к API FreeIPA и ошибки Apache сервера, на котором крутится веб FreeIPA;/var/log/krb5kdc.log
: FreeIPA KDC utilization — логирует действия KDC FreeIPA;/var/log/dirsrv/slapd-$REALM/access
: Directory Server utilization – логирует обращения по протоколу LDAP;/var/log/dirsrv/slapd-$REALM/errors
: Directory Server errors (including mentioned replication errors) — отвечает за ошибки, которые происходят в системе во время ее работы.
Некоторые журналы мы рассмотрим подробнее во время анализа событий при разборе атак.
Атаки на FreeIPA
В ходе анализа атак мы будем опираться на матрицу MITRE ATT&CK.
Сначала рассмотрим, какие методы может использовать злоумышленник для получения учётных данных (тактика Credential Access). Один из возможных вариантов — это попытка украсть TGT и TGS билеты (подробнее о них мы рассказывали в одной из наших предыдущих статей), чтобы затем повторно их использовать.
Кража билетов Kerberos
Рассмотрим ситуацию, когда билеты настроены на сохранение в виде файла на диске. В этом случае мы можем провести атаку по типу Steal or Forge Kerberos Tickets (T1558). Стандартным форматом для хранения билетов является файл CCACHE. CCACHE (Credential Cache) — это файл, в котором содержатся данные о пользователе и его билеты, что позволяет избежать повторной аутентификации при доступе к службам. Обычно эти файлы хранятся в /tmp
, имеют разрешения 600 и формат krb5cc_<uid>
. С точки зрения атакующего это важно по следующим причинам:
действительные билеты могут быть использованы для аутентификации без необходимости знать пароль пользователя в открытом тексте;
билеты CCACHE портативны. Их можно скачать и загрузить на другой хост без необходимости обновления или проверки билета
klist
.
При этом будет выведена информация об активном билете Kerberos, а в поле Ticket cache
будет указан путь до него. На рисунке видно, что сам CCHACHE файл находится в папке /tmp
.
Теперь посмотрим события, которые генерируются при обращении к этим билетам.
Для мониторинга событий доступа к файлам воспользуемся самым распространенным демоном аудита Linux — Auditd. Чтобы подобные события генерировались, нам понадобится следующее правило конфигурации для Auditd:
-w /tmp -p rwa -k ticket_ccache_file_read
После добавления правила, при обращении к CCHACHE файлу генерируется событие Object Access:
В событии Object Access нас интересуют:
Исполняемый файл, который инициировал активность (
exe=
), в нашем случае/usr/bin/cat
.Файл, к которому осуществлялось обращение (
name=
) в указанном выше событии/tmp/krb5cc_1472000008
. После нормализации это поле называетсяfilePath
. Если обращение к файлу CCACHE будет происходить из/tmp
, путь будет указан в полеcwd=
(после нормализации это полеobjPath
).Номер сискола (
syscall=
). В нашем случае номер257
, что означаетopenat
- открытие файла. После нормализации это поле называетсяcs4
.Права, с которыми осуществлялось обращение (
a2=
), равны0
, что означает открытие файла для чтения. После нормализации это поле называетсяfilePermission
.
На основании приведенной выше активности можно сделать вывод, что необходимо мониторить открытие файла (syscall =openat
), который содержит подстроку krb5cc_
в имени и находится по пути /tmp
, с правами на чтение r
.
На рисунке ниже представлен пример такого правила в R-Vision SIEM:
Код правила написан в плагине R-Object, о котором мы недавно выпустили статью.
Полный код можно посмотреть под спойлером:
Чтение Ticket CCACHE файла
id: ce9ec896-9549-42ae-a855-9010a5ea41e2
name: Чтение Ticket CCACHE файла
type: correlation_rule
severity: medium
version: 1.0.1
status: stable
date: 2024-05-02
author: Ilya Efimov, R-Vision
description: Когда билеты настроены на сохранение в виде файла на диске,
стандартным форматом и типом является файл CCACHE. Это простой
двоичный формат файла для хранения учетных данных Kerberos. Эти
файлы обычно хранятся в /tmp и имеют разрешения 600. С точки зрения
атакующего это важно по следующим причинам - 1)Действительные билеты могут
быть использованы для аутентификации без необходимости знать пароль
пользователя в открытом тексте. 2) Билеты CCACHE очень портативны.
Их можно скачать и загрузить на другой хост без необходимости обновления
или проверки билета. Таким образом доступ к билетам CCACHE является критичным
событием ИБ и может означать действия злоумышленника по разведке учетных записей
и доступу к действительным билетам Kerberos.
В случае возникновения активности необходимо опросить владельца учетной записи инициатора активности
на предмет совершенных действий.
reference:
- https://posts.specterops.io/attacking-freeipa-part-i-authentication-77e73d837d6a
- https://book.hacktricks.xyz/linux-hardening/privilege-escalation/linux-active-directory
known_false_positives:
- Действия пользователя по изучению своих билетов
data_source:
- Linux
- auditd
- R-Point
- credential-access
tags:
- Credential Access
- attack.T1558
filter: !vrl |
.dvendor == "Linux" &&
downcase(to_string(.cs4) ?? "") == "openat" &&
contains(to_string(.filePath) ?? "", "krb5cc_") &&
(downcase(to_string(.objPath) ?? "") == "/tmp" || contains(to_string(.filePath) ?? "", "/tmp")) &&
downcase(to_string(.filePermission) ?? "") == "r"
aliases:
event:
filter: !vrl |
true
select:
alias: event
ttl: 30
on_correlate: !vrl |
. |= compact({
"act" : %event.act,
"suser" : %event.suser,
"sproc" : %event.sproc,
"dproc" : %event.dproc,
"dpid" : %event.dpid,
"shost" : %event.shost,
"externalId" : %event.externalId,
"cmd": %event.cmd,
"fname" : %event.fname,
"duser" : %event.duser,
"sntdom" : %event.sntdom,
"dntdom" : %event.dntdom,
"sourceSessionId" : %event.sourceSessionId,
"targetSessionId" : %event.targetSessionId,
"msg" : join(["На хосте", (to_string(%event.dvchost) ?? "-"), "учетной записью",(to_string(%event.duser) ?? "-"), "выполнено чтение Ticket CCACHE файла", (to_string(%event.filePath) ?? "-"), "при помощи команды", (to_string(%event.cmd) ?? "-")], separator: " ") ?? "-",
"dhost" : %event.dhost,
"dvchost" : %event.dvchost,
"cs6Label" : %event.cs6Label,
"cs6" : %event.cs6,
"cs5Label" : %event.cs5Label,
"cs5" : %event.cs5,
"oldFileName" : %event.oldFileName,
"cs8Label" : %event.cs8Label,
"cs8" : %event.cs8,
"objPath" : %event.objPath,
"filePath" : %event.filePath,
"fileId" : %event.fileId,
"cs4" : %event.cs4,
"cs4Label" : %event.cs4Label,
"cs2" : %event.cs2,
"cs2Label" : %event.cs2Label
})
.correlationSeverity = 2
Что касается False Positive, обычный пользователь, вероятно, не будет выполнять такие действия, хотя у него может быть доступ. Однако, если срабатывает это правило корреляции, необходимо проанализировать другие логи с хоста на предмет необычной активности и связаться с ответственным за учётную запись.
Ещё одним распространённым вектором атак на любую систему являются атаки путём перебора. Давайте рассмотрим, что можно сделать во FreeIPA.
Brute Force
Куда же без старого-доброго Brute Force (T1110.001)? Для моделирования атаки можем, например, воспользоваться инструментом kerbrute
.
Пример команды:
./kerbrute bruteuser -d <domain> <dictionary> <user>
На скриншоте видно, что утилита отработала успешно и был найден валидный пароль.
Давайте посмотрим события, которые генерируются после использования этой утилиты.
Во время всех успешных и неуспешных попыток авторизации события будут генерироваться в стандартном журнале FreeIPA kerberos
по пути /var/log/krb5kdc.log
. При неуспешной попытке входа регистрируется событие:
Здесь нам будут интересны следующие поля:
AS_REQ
— содержит тип события. После нормализации помещается в полеcat
;PREAUTH_FAILED
— говорит о неуспешной пре-аутентификации. Помещается в полеact
после нормализации;bruter@DOMAIN.LOCAL
— имя пользователя, совершающего попытку логина. После нормализации разбивается на поляduser
иdntdom
с именем пользователя и доменом соответственно;-
10.150.50.77
— хост источник активности. После нормализации помещается в полеshost
.Если попытка входа была успешной, генерируется событие запроса AS-REQ:
В событии с успешной аутентификаией нам интересно наличие поля ISSUE
(помещается в поле act
после нормализации), так как оно говорит о том, что аутентификация прошла успешно и билет был выдан.
Исходя из вышеуказанных событий можно реализовать два правила корреляции со следующей логикой:
-
Множество неуспешных попыток Kerberos пре-аутентификации. После первого события с неуспешной аутентификацией открывается корреляционное окно длиной в 30 секунд и отсчитывает 10 неуспешных попыток. Определять неуспешные попытки будем по полю
act
и наличию в нем значенияPREAUTH_FAILED
.Правило на множество неуспешных попыток входа пользователя в R-Vision SIEM:
Подбор пароля пользователя FreeIPA
id: dc8ea3bf-099d-4582-b313-71def8878dfc
name: Подбор пароля пользователя FreeIPA
type: correlation_rule
severity: medium
version: 1.0.0
status: stable
date: 2024-04-26
author: Ilya Efimov, R-Vision
description: В домене под управлением FreeIPA в качестве основного механизма аутентификации
используется протокол Kerberos. Использование данного протокола позволяет
производить атаки, аналогичные атакам на Active Directory. Одним из видов такой
атаки является перебор паролей для учетной записи.
Для получения доступа к учетной записи или хосту, атакующий может попробовать подобрать пароль с помощью перебора.
В случае возникновения активности необходимо опросить владельца учетной записи инициатора активности.
reference:
- https://www.thehacker.recipes/a-d/movement/kerberos/pre-auth-bruteforce
known_false_positives:
- Устаревшие сохраненные учетные данные на узле инициаторе
- Забытый пароль
data_source:
- FreeIPA
- KRB5KDC
tags:
- Credential Access
- Brute Force
- attack.T1110
- attack.T1110.001
filter: !vrl |
.dvendor == "FreeIPA" &&
contains(to_string(.fname) ?? "", "krb5kdc_log") &&
downcase(to_string(.cat) ?? "") == "as_req" &&
downcase(to_string(.act) ?? "") == "preauth_failed"
aliases:
pre_auth_fail:
filter: !vrl |
true
select:
alias: pre_auth_fail
group:
- alias: pre_auth_fail
by:
- duser
count: 10
ttl: 30
on_correlate: !vrl |
. |= compact({
"act" : %pre_auth_fail[0].act,
"suser" : %pre_auth_fail[0].suser,
"sproc" : %pre_auth_fail[0].sproc,
"dproc" : %pre_auth_fail[0].dproc,
"dpid" : %pre_auth_fail[0].dpid,
"shost" : %pre_auth_fail[0].shost,
"externalId" : %pre_auth_fail[0].externalId,
"cmd": %pre_auth_fail[0].cmd,
"fname" : %pre_auth_fail[0].fname,
"duser" : %pre_auth_fail[0].duser,
"sntdom" : %pre_auth_fail[0].sntdom,
"dntdom" : %pre_auth_fail[0].dntdom,
"sourceSessionId" : %pre_auth_fail[0].sourceSessionId,
"targetSessionId" : %pre_auth_fail[0].targetSessionId,
"msg" : join(["На хосте", (to_string(%pre_auth_fail[0].dvchost) ?? "-"), "под учетной записью",(to_string(%pre_auth_fail[0].duser) ?? "-"), "с доменом", (to_string(%pre_auth_fail[0].dntdom) ?? "-"), "зафиксированы множественные неуспешные попытки kerberos пре-аутентификации с хоста", (to_string(%pre_auth_fail[0].shost) ?? "-")], separator: " ") ?? "-",
"dhost" : %pre_auth_fail[0].dhost,
"dvchost" : %pre_auth_fail[0].dvchost,
"cs6Label" : %pre_auth_fail[0].cs6Label,
"cs6" : %pre_auth_fail[0].cs6,
"cs5Label" : %pre_auth_fail[0].cs5Label,
"cs5" : %pre_auth_fail[0].cs5,
"oldFileName" : %pre_auth_fail[0].oldFileName,
"cs8Label" : %pre_auth_fail[0].cs8Label,
"cs8" : %pre_auth_fail[0].cs8,
"objPath" : %pre_auth_fail[0].objPath,
"filePath" : %pre_auth_fail[0].filePath,
"fileId" : %pre_auth_fail[0].fileId,
"cs4" : %pre_auth_fail[0].cs4,
"cs4Label" : %pre_auth_fail[0].cs4Label,
"cs2" : %pre_auth_fail[0].cs2,
"cs2Label" : %pre_auth_fail[0].cs2Label
})
.correlationSeverity = 2
-
Успешный подбор пароля пользователя после множества неуспешных попыток Kerberos пре-аутентификации. Логика такая же, как и в случае с неуспешными попытками, но мы смотрим одно событие с успешной попыткой. Нужно найти вхождение строки
issue
в полеact
.Правило на успешный подбор пароля после множества неуспешных попыток:
Успешный подбор пароля пользователя FreeIPA
id: 691e0f41-3763-465b-b92a-1d542dada346
name: Успешный подбор пароля пользователя FreeIPA
type: correlation_rule
severity: medium
version: 1.0.0
status: stable
date: 2024-04-26
author: Ilya Efimov, R-Vision
description: В домене под управлением FreeIPA в качестве основного механизма аутентификации
используется протокол Kerberos. Использование данного протокола позволяет
производить атаки, аналогичные атакам на Active Directory. Одним из видов такой
атаки является перебор паролей для учетной записи.
Для получения доступа к учетной записи или хосту, атакующий может попробовать подобрать пароль с помощью перебора.
В случае возникновения активности необходимо опросить владельца учетной записи инициатора активности.
reference:
- https://www.thehacker.recipes/a-d/movement/kerberos/pre-auth-bruteforce
known_false_positives:
- Устаревшие сохраненные учетные данные на узле инициаторе
- Забытый пароль
data_source:
- FreeIPA
- KRB5KDC
tags:
- Credential Access
- Brute Force
- attack.T1110
- attack.T1110.001
filter: !vrl |
.dvendor == "FreeIPA" &&
contains(to_string(.fname) ?? "", "krb5kdc_log") &&
downcase(to_string(.cat) ?? "") == "as_req"
aliases:
pre_auth_fail:
filter: !vrl |
downcase(to_string(.act) ?? "") == "preauth_failed"
pre_auth_success:
filter: !vrl |
downcase(to_string(.act) ?? "") == "issue"
select:
alias: pre_auth_fail
join:
alias: pre_auth_success
on:
- eq: { pre_auth_fail: duser, pre_auth_success: duser }
- eq: { pre_auth_fail: dntdom, pre_auth_success: dntdom }
- eq: { pre_auth_fail: shost, pre_auth_success: shost }
group:
- alias: pre_auth_fail
by:
- duser
count: 10
ttl: 30
on_correlate: !vrl |
. |= compact({
"act" : %pre_auth_fail[0].act,
"suser" : %pre_auth_fail[0].suser,
"sproc" : %pre_auth_fail[0].sproc,
"dproc" : %pre_auth_fail[0].dproc,
"dpid" : %pre_auth_fail[0].dpid,
"shost" : %pre_auth_fail[0].shost,
"externalId" : %pre_auth_fail[0].externalId,
"cmd": %pre_auth_fail[0].cmd,
"fname" : %pre_auth_fail[0].fname,
"duser" : %pre_auth_fail[0].duser,
"sntdom" : %pre_auth_fail[0].sntdom,
"dntdom" : %pre_auth_fail[0].dntdom,
"sourceSessionId" : %pre_auth_fail[0].sourceSessionId,
"targetSessionId" : %pre_auth_fail[0].targetSessionId,
"msg" : join(["На хосте", (to_string(%pre_auth_fail[0].dvchost) ?? "-"), "под учетной записью",(to_string(%pre_auth_fail[0].duser) ?? "-"), "с доменом", (to_string(%pre_auth_fail[0].dntdom) ?? "-"), "зафиксирована успешная попытка kerberos пре-аутентификации после множества неуспешных попыток пре-аутентификации с хоста", (to_string(%pre_auth_fail[0].shost) ?? "-")], separator: " ") ?? "-",
"dhost" : %pre_auth_fail[0].dhost,
"dvchost" : %pre_auth_fail[0].dvchost,
"cs6Label" : %pre_auth_fail[0].cs6Label,
"cs6" : %pre_auth_fail[0].cs6,
"cs5Label" : %pre_auth_fail[0].cs5Label,
"cs5" : %pre_auth_fail[0].cs5,
"oldFileName" : %pre_auth_fail[0].oldFileName,
"cs8Label" : %pre_auth_fail[0].cs8Label,
"cs8" : %pre_auth_fail[0].cs8,
"objPath" : %pre_auth_fail[0].objPath,
"filePath" : %pre_auth_fail[0].filePath,
"fileId" : %pre_auth_fail[0].fileId,
"cs4" : %pre_auth_fail[0].cs4,
"cs4Label" : %pre_auth_fail[0].cs4Label,
"cs2" : %pre_auth_fail[0].cs2,
"cs2Label" : %pre_auth_fail[0].cs2Label
})
.correlationSeverity = 2
Из False Positive возможны сработки в следующих ситуациях:
устаревшие сохраненные учетные данные на узле;
забытый пароль.
С детектом получения учетных данных разобрались, а что дальше? Так как на сервер FreeIPA можно зайти не только через веб, но и по ssh, предлагаю рассмотреть технику Command and Scripting Interpreter: Unix Shell в рамках тактики Execution.
Изменение оболочки входа
Некоторые оболочки могут предоставлять больше возможностей, чем стандартный sh
для выполнения скриптов или команд (по MITRE ATT&CK Command and Scripting Interpreter: Unix Shell (T1059.004)). Атакующие могут воспользоваться изменением оболочки входа для повышения своих привилегий в системе. Такая схема реализовывается за счет функции user_mod()
из API FreeIPA (необходимо указать ipa
перед вводом команды). Функция user_mod()
предназначена для модификации учетных записей пользователей и позволяет изменять различные параметры, такие как оболочка входа (Login Shell), пароль, домашний каталог и т. д.
FreeIPA позволяет менять оболочку входа (Login Shell) для любого пользователя как в UI, так и в CLI при помощи функции ipa user-mod
.
Изменение при помощи UI
Изменить оболочку входа в пользовательском интерфейсе можно в параметрах учетной записи:
События при этом будут генерироваться в журнале FreeIPA API call logs по пути /var/log/httpd/error_log
. Событие изменения оболочки входа через UI FreeIPA:
В этом событии нам интересна строка INFO
(после нормализации это поле преобразовывается в поле cmd
), а конкретно наличие в ней функции user_mod
и подстроки loginshell
, которая свидетельствует о смене оболочки входа по умолчанию.
После входа в систему мы можем увидеть как поменялся login shell:
Изменение при помощи CLI
Изменение оболочки входа доступно также при помощи команды:
ipa user-mod --shell=/bin/bash 'roaster'
В параметре --shell
нужно указать путь к оболочке, которая будет запускаться при входе пользователя.
Вывод после выполнения программы:
При этом в журнале /var/log/httpd/error_log
будет сгенерировано событие, которое почти идентично предыдущему, за исключением одного момента:
Можно заметить, что при вызове функции через UI выполнилась функция user_mod
, а через CLI — функция user_mod/1
. Так происходит всегда при вызове всех API функций. При изменении оболочки shell, не важно через UI или CLI, будут сформированы события в журнале /var/log/httpd/error_log
. На этой основе можно реализовать детект на наличие подстрок user_mod
и loginshell=
в поле INFO
(поле cmd
после нормализации в R-Vision SIEM).
Правило по изменению оболочки входа пользователя:
Изменение оболочки входа при помощи средств FreeIPA
id: 21fe2fbd-7fea-4d42-888f-f371875d20e8
name: Изменение оболочки входа при помощи средств FreeIPA
type: correlation_rule
severity: medium
version: 1.0.0
status: stable
date: 2024-04-24
author: Ilya Efimov, R-Vision
description: Некоторые оболочки могут предоставлять больше возможностей для выполнения скриптов или команд.
Злоумышленники могут воспользоваться изменением оболочки входа для повышения своих возможностей в системе.
Данный функционал реализовывается за счет функции user_mod() из функционала API FreeIPA (ipa user-mod) или при помощи смены оболочки пользователя в web-интерфейсе.
В случае возникновения активности требуется опросить пользователя, ответственного за учетную запись инициатора активности,
на предмет осуществления активности. В случае, если активность нелегитимна, заблокировать учетную запись инициатора активности.
reference:
- https://posts.specterops.io/attacking-freeipa-part-i-authentication-77e73d837d6a
- https://freeipa.readthedocs.io/en/latest/api/commands.html
known_false_positives:
- Не выявлено
data_source:
- FreeIPA
- HTTPD
tags:
- execution
- attack.T1059
- attack.T1059.004
filter: !vrl |
.dvendor == "FreeIPA" &&
contains(to_string(.fname) ?? "", "error_log") &&
contains_all(to_string(.cmd) ?? "", ["user_mod", "loginshell="], case_sensitive: false)
aliases:
change_login_shell:
filter: !vrl |
true
select:
alias: change_login_shell
ttl: 20
on_correlate: !vrl |
. |= compact({
"act" : %change_login_shell.act,
"suser" : %change_login_shell.suser,
"sproc" : %change_login_shell.sproc,
"dproc" : %change_login_shell.dproc,
"dpid" : %change_login_shell.dpid,
"externalId" : %change_login_shell.externalId,
"cmd": %change_login_shell.cmd,
"fname" : %change_login_shell.fname,
"duser" : %change_login_shell.duser,
"sntdom" : %change_login_shell.sntdom,
"dntdom" : %change_login_shell.dntdom,
"sourceSessionId" : %change_login_shell.sourceSessionId,
"targetSessionId" : %change_login_shell.targetSessionId,
"msg" : join(["На хосте", (to_string(%change_login_shell.dvchost) ?? "-"), "учетной записью",(to_string(%change_login_shell.suser) ?? "-"), "с доменом", (to_string(%change_login_shell.sntdom) ?? "-"), "выполнено изменение оболочки входа средствами FreeIPA для пользователя", (to_string(%change_login_shell.duser) ?? "-"),"на оболочку", (to_string(%change_login_shell.cs1) ?? "-"), ". Хост инициатор активности:", (to_string(%change_login_shell.shost) ?? "-")], separator: " ") ?? "-",
"dhost" : %change_login_shell.dhost,
"dvchost" : %change_login_shell.dvchost,
"cs6Label" : %change_login_shell.cs6Label,
"cs6" : %change_login_shell.cs6,
"cs5Label" : %change_login_shell.cs5Label,
"cs5" : %change_login_shell.cs5,
"oldFileName" : %change_login_shell.oldFileName,
"cs8Label" : %change_login_shell.cs8Label,
"cs8" : %change_login_shell.cs8,
"objPath" : %change_login_shell.objPath,
"filePath" : %change_login_shell.filePath,
"fileId" : %change_login_shell.fileId,
"cs4" : %change_login_shell.cs4,
"cs4Label" : %change_login_shell.cs4Label
})
.correlationSeverity = 2
Давайте рассмотрим критичные сервисы, благодаря которым работает FreeIPA.
Остановка критичных сервисов
Одной из популярных техник в тактике Impact является Service Stop (T1489). Злоумышленники могут отключить критичные для работы системы сервисы, что сделает ее недоступной для обычных легитимных пользователей. Так как FreeIPA устанавливается на Linux, все конфигурационные файлы, сервисы и исполняемые файлы для управления будут стандартными для Linux систем — их можн о мониторить, например, через Auditd. На сервере IPA запущено множество сервисов, но мы можем выделить наиболее критичные, остановка и выключение которых может нанести вред как работоспособности самой FreeIPA, так и ее безопасности.
К таким сервисам относятся:
ipa
— основной сервис FreeIPA который служит для управления LDAP-сервером, Kerberos KDC, DNS, и другими компонентами. Остановка основного сервиса IPA может привести к отключению всей системы централизованного управления идентификацией и аутентификацией, что сделает невозможным управление пользователями, группами, хостами и политиками безопасности.ipa-custodia
— сервис, отвечающий за безопасное хранение и передачу секретных данных между серверами FreeIPA. Остановка IPA Custodia приведет к прекращению безопасной передачи и хранения ключей и секретов.ipa-ccache-sweep
(IPA Credential Cache Sweep) — сервис для управления и отчистки кэшированных учетных данных в IPA. Без регулярной очистки устаревших кэшированных учетных данных увеличивается риск использования скомпрометированных или устаревших учетных записей, что может привести к атаке с кражей CCACHE ticket.krb5kdc
— управляет выдачей и проверкой Kerberos тикетов, которые используются для аутентификации пользователей и сервисов в сети. Остановка Kerberos KDC приведет к прекращению выдачи и проверки Kerberos тикетов. Это сделает невозможной аутентификацию пользователей и сервисов, фактически парализуя всю систему аутентификации и нарушая доступ к ресурсам сети.dirsrv
— относится к Directory Server (LDAP-серверу). Этот сервис управляет каталогом, содержащим информацию о пользователях, группах, хостах и других объектах в сети. Каталог также отвечает за аутентификацию и авторизацию пользователей и устройств в домене. При отключении у пользователей пропадет возможность аутентифицироваться в домене и нарушится работа других сервисов FreeIPA: Kerberos, DNS и PKI.
После отключения сервиса будет сгенерировано событие в Auditd:
В этом событии нам интересны следующие поля:
type
(deviceProcessName
после нормализации)=SERVICE_STOP — это значение поля говорит о том, что сервис был остановлен;unit
(destinationServiceName
после нормализации) — имя сервиса, который был остановлен.
Если будет остановлен сервис ipa
, то остановятся и все остальные сервисы, указанные выше. При помощи подобных событий можно реализовать детект на отключение сервисов, критичных для функционала FreeIPA. Необходимо мониторить поле cat
на предмет наличия значения SERVICE_STOP
и название критичного сервиса FreeIPA в поле destinationServiceName
.
Полный код правила можно посмотреть под спойлером:
Остановка/перезапуск сервисов FreeIPA
id: fda17910-b679-44de-9908-b5b7edbebd41
name: Остановка/перезапуск сервисов FreeIPA
version: 1.0.0
date: 27.04.2024
author: Ilya Efimov, R-Vision
status: stable
type: correlation_rule
severity: medium
description: Для работы сервера freeipa по умолчанию устанавливается несколько сервисов.
Для применения изменения многих конфигураций требуется перегазагрузка сервисов.
Злоумышленник может перезапустить или остановить сервисы для отключения функционала или подмены легитимных сервисов на вредоносные.
tags:
- attack.T1543.002
- attack.T1543
- linux
data_source:
- Linux
- auditd
known_false_positives:
- Действия администратора
- Установка/обновления FreeIPA
aliases:
event:
filter: !vrl |
bin_list=["ipa", "ipa-custodia", "ipa-dnskeysyncd", "ipa-otpd", "ipa-ccache-sweep", "httpd-init", "httpd", "krb5kdc", "dirsrv"]
.dvendor == "Linux" &&
.cat == "SERVICE_STOP" &&
includes(bin_list, .destinationServiceName)
select:
alias: event
ttl: 10
on_correlate: !vrl
.correlationSeverity = 2
.dvchost = %event.dvchost
.duser = %event.duser
.suser = %event.duser
.dproc = %event.dproc
.filePath = %event.filePath
.msg = "На хосте " + (to_string(.dvchost) ?? "-") + " пользователь " + (to_string(.duser) ?? "-") + " оставновил критичный сервис FreeIPA " + (to_string(.filePath) ?? "-") + " с помощью процесса " + (to_string(.dproc) ?? "-")
Предлагаю посмотреть иерархию наследования прав во FreeIPA. Она отличается от того, к чему мы привыкли в Active Directory.
Злоупотребление ролями и привилегиями IPA
Во FreeIPA есть 3 основные сущности для назначения прав пользователям: «Разрешения», «Привилегии» и «Роли».
Все они тесно взаимосвязаны друг с другом:
Permissions (Разрешения) — начальные права, которые выдаются на определенные атрибуты в системе.
Privileges (Привилегии) — набор различных Permissions.
Role (Роли) — включают в себя различные Privileges и могут назначаться на пользователей.
Permissions
Для начала кратко рассмотрим разрешения. При помощи разрешений можно выдать доступ к определенным атрибутам пользователей. Наиболее критичные можно найти по следующим ключевым словам:
"krb","admin", "trust","sudo", "services", "vaults", "permissions","privileges","roles","ssh", "private", "selinux", "secret", "users", "ipanthas", "userpassword"
Условно, это точечные доступы, которые могут группироваться в привилегиях.
Privileges
Привилегии сами по себе не содержат каких-либо прав. Им можно присвоить разрешения с помощью следующих команд:
privilege-add-permission
privilege-mod
В системе содержатся более 30 стандартных привилегий. Найти их можно с помощью команды privilege-find
. Наиболее критичными будут являться привилегии, содержащие слова: «admin», «sudo», «selinux», «kerberos», «enrollment», «manager».
Ниже представлено событие, сгенерированное при добавлении разрешения System: Read User Kerberos Login Attributes
. Данное разрешение позволяет получить доступ на чтение к атрибутам Kerberos в привилегии test_privileges
.
В событии мы видим, что в поле INFO
(cmd
после нормализации) содержится команда privilege_add_permission
, которая добавляет в привилегию test_privileges
разрешение Read User Kerberos Login Attributes
(в поле permission=
).
На основе этого можно реализовать детект с помощью проверки поля cmd
на предмет наличия слов, присущих критичным разрешениям и наличия в той же строке команд для добавления и модификации привилегий.
Для детектирования изменения привилегий у нас есть следующее правило:
Изменение конфигураций привилегий во FreeIPA
id: 74296c4d-6121-437a-9f6a-7d6d378ad0g6
name: Изменение конфигураций привилегий в FreeIPA
version: 1.0.0
date: 01.06.2024
author: Alexey Episev, R-Vision
status: stable
type: correlation_rule
severity: high
description: Обнаружение использования команд добавления админских прав в привилегии FreeIPA.
Злоумышленники могут изменять привилегии для закрепления в системе и повышения привилегий на доменных хостах.
tags:
- attack.T1548.003
- attack.T1548
- attack.persistence
- linux
data_source:
- FreeIPA
known_false_positives:
- Действия администратора по добавлению привилегий
- Добавление новых привилегированных пользователей
aliases:
event:
filter: !vrl |
.dvendor == "FreeIPA" &&
cmd = downcase(to_string(.cmd) ?? "")
permissions=["kerberos","admin","manag","sudo", "trust","privilege","modify",
"selinux","roles","ssh","enroll","delete","add","vault"]
filt=false
for_each(permissions) -> |_index, value| {
if contains(cmd,value) == true {
filt = true
}
}
if filt==true && (contains(cmd, "privilege_add_permission") || contains(cmd, "privilege_mod"))
{ true } else { false }
}
select:
alias: event
ttl: 10
on_correlate: !vrl |
.correlationSeverity = 3
.dvchost = %event.dvchost
.msg = %event.msg
.suser = %event.suser
.dproc = %event.dproc
.cmd = %event.cmd
.msg = "На хосте " + (to_string(.dvchost) ?? "-") + " пользователь " + (to_string(.suser) ?? "-") + " изменил изменил привилегии FreeIPA с помощью команды " + (to_string(.cmd) ?? "-")
Привилегии мы создали, а теперь нужно присвоить их ролям.
Roles
Ролям могут присваиваться различные привилегии через web-интерфейс или с помощью команд:
role-mod
role-add-privilege
Далее, роли могут назначаться пользователям также через web-интерфейс или с помощью команды:
role-add-member
Рассмотрим пример события с добавлением привилегии Sudo Administrator
роли test_role
:
В событии мы видим, что в поле INFO
(cmd) содержится команда role_add_privilege
, которая добавляет роли test_role
привилегию Sudo Administrator
(указана в поле privilege=
). Привилегия Sudo Administartor
имеет разрешения на управление командой sudo
(добавление пользователей в группы sudo
, добавление команд для sudo
и т. д.).
В системе также содержатся стандартные роли с повышенными привилегиями:
На основе этой информации можно реализовать детект путем проверки поля cmd
на предмет наличия слов, присущих критичным привилегиям и наличия в той же строке команд для присвоения и модификации ролей.
Для детектирования изменения ролей у нас есть следующее правило:
Изменение конфигураций ролей в FreeIPA
id: 7409eefb-c10b-4be6-8f47-7833c6cce304
name: Изменение конфигураций ролей в FreeIPA
version: 1.0.0
date: 01.06.2024
author: Alexey Episev, R-Vision
status: stable
type: correlation_rule
severity: high
description: Обнаружение использования команд добавления админских прав в привилегии и их назначение ролям FreeIPA.
Злоумышленники могут изменять роли для закрепления в системе и повышения привилегий на доменных хостах.
tags:
- attack.T1548.003
- attack.T1548
- attack.persistence
- linux
data_source:
- FreeIPA
known_false_positives:
- Действия администратора по добавлению ролей
- Добавление новых привилегированных пользователей
aliases:
event:
filter: !vrl |
.dvendor == "FreeIPA" &&
cmd = downcase(to_string(.cmd) ?? "")
if (((contains(cmd, "role_add_privilege") || contains(cmd, "role-mod")) && ((contains(cmd, "admin") || contains(cmd, "sudo") || contains(cmd, "selinux") || contains(cmd, "kerberos") ||
contains(cmd, "enrollment") || contains(cmd, "manager"))) ||
(contains(cmd, "role_add_member") && ((contains(cmd, "admin") || contains(cmd, "manager"))) )))
{ true } else { false }
}
select:
alias: event
ttl: 10
on_correlate: !vrl |
.correlationSeverity = 3
.dvchost = %event.dvchost
.msg = %event.msg
.suser = %event.suser
.dproc = %event.dproc
.cmd = %event.cmd
.msg = "На хосте " + (to_string(.dvchost) ?? "-") + " пользователь " + (to_string(.suser) ?? "-") + " изменил изменил роль FreeIPA с помощью команды " + (to_string(.cmd) ?? "-")
Заключение
В этой статье мы рассмотрели несколько сценариев атак на систему доменных сервисов FreeIPA и их детектирования. Мы проанализировали способы компрометации учетных данных через Kerberos CCACHE и методы брутфорс атак, выполнение команд через Unix Shell, остановку и перезапуск критических сервисов, а также злоупотребление критичными ролями и привилегиями.
Основные выводы и рекомендации:
Steal or Forge Kerberos Tickets: защищайте
Kerberos
CCACHE файлы. Для этого требуется настраивать Auditd для мониторинга доступа к ним. Это позволяет оперативно выявлять несанкционированное использование билетов.Brute Force: анализируйте журнал
Kerberos
для выявления брутфорс атак и настраивайте соответствующие правила корреляции для их детектирования.Login Shell: контролируйте изменение оболочки входа пользователей и настраивайте правила мониторинга для выявления несанкционированных изменений через API FreeIPA.
Service Stop: проводите мониторинг состояния критических сервисов FreeIPA и обеспечивайте их стабильную работу для предотвращения атак по выводу системы из строя.
Roles and Privileges: тщательно контролируйте создание и изменение критичных ролей, привилегий и разрешений в системе FreeIPA, чтобы минимизировать риски повышения привилегий атакующими.
Реализация предложенных мер позволит повысить безопасность и устойчивость FreeIPA к различным видам атак, обеспечивая надежную защиту доменной инфраструктуры вашей сети.
В этой статье описаны далеко не все правила, которые есть у нас по FreeIPA, иначе она бы получилось еще длиннее. Если вам будут интересны остальные правила, готов обсудить их в комментариях.
Ruucker
Можно ли говорить о том что FreeIPA безопаснее MS AD? Как минимум нет NTLM
sea-team Автор
Добрый день! На мой взгляд, пока рано утверждать, что FreeIPA безопаснее Active Directory (AD). Действительно, на FreeIPA сейчас совершается мало атак, но это скорее связано с тем, что она не так популярна, как AD. Злоумышленники просто не успели обнаружить столько уязвимостей и вариантов атак, сколько есть в MS AD.
Атаки на FreeIPA, например, на Kerberos, немного отличаются от атак на AD. Атаки типа Golden/Silver Ticket здесь имеют другой формат, потому что можно выпустить билет для любого пользователя или сервиса прямо с контроллера домена, имея root-права и не нуждаясь в хэше пароля krbtgt. В случае с AD для этого потребуются сторонние инструменты, такие как mimikatz, rubeus и другие. Существующие инструменты не подходят для работы с используемыми в FreeIPA тикетами.
Подводя итог, я бы не спешил утверждать, что FreeIPA безопаснее. С ростом популярности этого решения появится больше инструментов и методов атак.