Привет, Хабр!

Меня зовут Всеволод Саломадин, я ведущий аналитик-исследователь угроз кибербезопасности в компании 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) включает в себя несколько ключевых компонентов:

  1. Веб-сервер:

    • используется для настройки политик и управления учетными записями;

    • реализован на основе Apache HTTP Server.

  2. Сервер каталогов 389:

    • обеспечивает централизованное хранение данных о пользователях и ресурсах;

    • использует LDAP (Lightweight Directory Access Protocol).

  3. MIT Kerberos:

    • отвечает за аутентификацию и управление тикетами доступа (используются стандартные, как в AD, TGT и TGS, а для хранения тикета локально используется файл CCACHE);

    • позволяет безопасно аутентифицировать пользователей и службы в сети.

  4. NTP (Network Time Protocol):

    • синхронизирует время между всеми компонентами системы;

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

  5. DNS:

    • управляет доменными именами и их разрешением в IP-адреса;

    • включает поддержку SRV-записей для Kerberos и LDAP.

  6. Система сертификатов 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/accessDirectory Server utilization – логирует обращения по протоколу LDAP;

  • /var/log/dirsrv/slapd-$REALM/errorsDirectory 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.

Парсинг CCHACHE файла
Парсинг CCHACHE файла

При этом будет выведена информация об активном билете Kerberos, а в поле Ticket cache будет указан путь до него. На рисунке видно, что сам CCHACHE файл находится в папке /tmp.

Содержимое CCHACHE файла
Содержимое CCHACHE файла

Теперь посмотрим события, которые генерируются при обращении к этим билетам.
Для мониторинга событий доступа к файлам воспользуемся самым распространенным демоном аудита Linux — Auditd. Чтобы подобные события генерировались, нам понадобится следующее правило конфигурации для Auditd:

-w /tmp -p rwa -k ticket_ccache_file_read

После добавления правила, при обращении к CCHACHE файлу генерируется событие Object Access:

Событие доступа к CCACHE файлу в R-Vision SIEM
Событие доступа к CCACHE файлу в R-Vision SIEM

В событии 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:

Правило для детектирования чтения CCACHE файла в R-Vision SIEM
Правило для детектирования чтения CCACHE файла в 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>
Брутфорс пароля пользователя bruter
Брутфорс пароля пользователя bruter

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

Во время всех успешных и неуспешных попыток авторизации события будут генерироваться в стандартном журнале FreeIPA kerberos по пути /var/log/krb5kdc.log. При неуспешной попытке входа регистрируется событие:

500
Событие с неуспешной попыткой входа в R-Vision SIEM

Здесь нам будут интересны следующие поля:

  • AS_REQ — содержит тип события. После нормализации помещается в поле cat;

  • PREAUTH_FAILED — говорит о неуспешной пре-аутентификации. Помещается в поле act после нормализации;

  • bruter@DOMAIN.LOCAL — имя пользователя, совершающего попытку логина. После нормализации разбивается на поля duser и dntdom с именем пользователя и доменом соответственно;

  • 10.150.50.77 — хост источник активности. После нормализации помещается в поле shost.

    Если попытка входа была успешной, генерируется событие запроса AS-REQ:

500
Событие с успешной аутентификацией и выдачей билета

В событии с успешной аутентификаией нам интересно наличие поля 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

Изменить оболочку входа в пользовательском интерфейсе можно в параметрах учетной записи:

Способ смены оболочки входа пользователя через UI FreeIPA
Способ смены оболочки входа пользователя через UI FreeIPA

События при этом будут генерироваться в журнале FreeIPA API call logs по пути /var/log/httpd/error_log. Событие изменения оболочки входа через UI FreeIPA:

400
Событие о смене оболочки входа пользователя через UI R-Vision SIEM

В этом событии нам интересна строка INFO (после нормализации это поле преобразовывается в поле cmd), а конкретно наличие в ней функции user_mod и подстроки loginshell, которая свидетельствует о смене оболочки входа по умолчанию.

После входа в систему мы можем увидеть как поменялся login shell:

Действующий login shell
Действующий login shell

Изменение при помощи CLI

Изменение оболочки входа доступно также при помощи команды:

ipa user-mod --shell=/bin/bash 'roaster' 

В параметре --shell нужно указать путь к оболочке, которая будет запускаться при входе пользователя.

Вывод после выполнения программы:

400
Вывод после смены оболочки shell через CLI

При этом в журнале /var/log/httpd/error_log будет сгенерировано событие, которое почти идентично предыдущему, за исключением одного момента:

500
Вывод после смены оболочки shell через CLI

Можно заметить, что при вызове функции через 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, так и ее безопасности.

К таким сервисам относятся:

  1. ipa — основной сервис FreeIPA который служит для управления LDAP-сервером, Kerberos KDC, DNS, и другими компонентами. Остановка основного сервиса IPA может привести к отключению всей системы централизованного управления идентификацией и аутентификацией, что сделает невозможным управление пользователями, группами, хостами и политиками безопасности.

  2. ipa-custodia — сервис, отвечающий за безопасное хранение и передачу секретных данных между серверами FreeIPA. Остановка IPA Custodia приведет к прекращению безопасной передачи и хранения ключей и секретов.

  3. ipa-ccache-sweep (IPA Credential Cache Sweep) — сервис для управления и отчистки кэшированных учетных данных в IPA. Без регулярной очистки устаревших кэшированных учетных данных увеличивается риск использования скомпрометированных или устаревших учетных записей, что может привести к атаке с кражей CCACHE ticket.

  4. krb5kdc — управляет выдачей и проверкой Kerberos тикетов, которые используются для аутентификации пользователей и сервисов в сети. Остановка Kerberos KDC приведет к прекращению выдачи и проверки Kerberos тикетов. Это сделает невозможной аутентификацию пользователей и сервисов, фактически парализуя всю систему аутентификации и нарушая доступ к ресурсам сети.

  5. dirsrv — относится к Directory Server (LDAP-серверу). Этот сервис управляет каталогом, содержащим информацию о пользователях, группах, хостах и других объектах в сети. Каталог также отвечает за аутентификацию и авторизацию пользователей и устройств в домене. При отключении у пользователей пропадет возможность аутентифицироваться в домене и нарушится работа других сервисов FreeIPA: Kerberos, DNS и PKI.

После отключения сервиса будет сгенерировано событие в Auditd:

400
Событие остановки сервиса IPA

В этом событии нам интересны следующие поля:

  • 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.

500
Событие добавления привилегии разрешению из журнала error_log

В событии мы видим, что в поле 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
Добавление привилегии Sudo Administrator роли test_role

Рассмотрим пример события с добавлением привилегии Sudo Administrator роли test_role:

500
Событие добавления роли привилегии из журнала error_log

В событии мы видим, что в поле 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, остановку и перезапуск критических сервисов, а также злоупотребление критичными ролями и привилегиями.

Основные выводы и рекомендации:

  1. Steal or Forge Kerberos Tickets: защищайте Kerberos CCACHE файлы. Для этого требуется настраивать Auditd для мониторинга доступа к ним. Это позволяет оперативно выявлять несанкционированное использование билетов.

  2. Brute Force: анализируйте журнал Kerberos для выявления брутфорс атак и настраивайте соответствующие правила корреляции для их детектирования.

  3. Login Shell: контролируйте изменение оболочки входа пользователей и настраивайте правила мониторинга для выявления несанкционированных изменений через API FreeIPA.

  4. Service Stop: проводите мониторинг состояния критических сервисов FreeIPA и обеспечивайте их стабильную работу для предотвращения атак по выводу системы из строя.

  5. Roles and Privileges: тщательно контролируйте создание и изменение критичных ролей, привилегий и разрешений в системе FreeIPA, чтобы минимизировать риски повышения привилегий атакующими.

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

В этой статье описаны далеко не все правила, которые есть у нас по FreeIPA, иначе она бы получилось еще длиннее. Если вам будут интересны остальные правила, готов обсудить их в комментариях.

Комментарии (2)


  1. Ruucker
    11.07.2024 08:34

    Можно ли говорить о том что FreeIPA безопаснее MS AD? Как минимум нет NTLM


    1. sea-team Автор
      11.07.2024 08:34

      Добрый день! На мой взгляд, пока рано утверждать, что FreeIPA безопаснее Active Directory (AD). Действительно, на FreeIPA сейчас совершается мало атак, но это скорее связано с тем, что она не так популярна, как AD. Злоумышленники просто не успели обнаружить столько уязвимостей и вариантов атак, сколько есть в MS AD.

      Атаки на FreeIPA, например, на Kerberos, немного отличаются от атак на AD. Атаки типа Golden/Silver Ticket здесь имеют другой формат, потому что можно выпустить билет для любого пользователя или сервиса прямо с контроллера домена, имея root-права и не нуждаясь в хэше пароля krbtgt. В случае с AD для этого потребуются сторонние инструменты, такие как mimikatz, rubeus и другие. Существующие инструменты не подходят для работы с используемыми в FreeIPA тикетами.

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