Архитектутра SIEM системы

«Коллеги, напоминаю, в этом квартале запланированы курсы повышения квалификации для партнеров на тему управления информационной безопасностью. Нашему коллективу предлагается подготовить практическое занятие, посвященное вопросам построения SIEM систем!» – после такого предложения начальника возникла пауза во время очередной летучки.

Участники заседания из числа предполагаемых исполнителей понимали, к чему обязывает такое предложение (слава и почет затраты времени, сил, нервов). Но, поскольку проведение исследований решений SIEM (Security Information and Event Management, системы управления инцидентами безопасности) – одно из направлений нашей деятельности, отказываться от предложения не представлялось возможным. Выдохнули и приступили.

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

Делимся материалами практикума по разработке собственной SIEM системы за один день с убедительными примерами.

Дисклеймер. Материал — объемный, рассчитанный на полный учебный день занятий в размеренном темпе. Пример — примитивный. Авторы сомневаются в возможности промышленного применения open-source решений SIEM, но вместе с тем считают, что изучение практических примеров позволит лучше разобраться в предметной области.

Анализ исходных данных и постановка задачи


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

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

Известны и пожелания партнеров – на занятиях рассмотреть вопросы построения современных систем управления инцидентами безопасности с минимумом теории и максимумом практики и пользы.

Итак, предлагается подготовить практикум, в ходе которого:

  • рассказать об известных подходах к построению SIEM систем;
  • пояснить архитектурные особенности класса подобных систем на примере (пусть и примитивном, но убедительном) разработки собственного решения;
  • продемонстрировать работу собственной SIEM системы в «учебно-боевых» условиях мониторинга безопасности тестовой сетевой инфраструктуры.

Рассчитываем, что слушатели знакомы с сетевыми технологиями и основами программирования (примеры кода – на PHP и C#).

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

Практикум по разработке SIEM системы


Во вступительном слове ограничимся общими пояснениями.

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

Базовые возможности системы SIEM должны обеспечивать решение следующих задач [1, 2]:

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

Кроме того, к современным решениям класса SIEM предъявляются дополнительные требования с целью обеспечить реализацию следующих функциональных возможностей [3]:

  • оценка защищенности ресурсов контролируемой системы;
  • проверка соответствия системы управления ИБ существующим требованиям и нормам;
  • управление рисками ИБ и др.

Функциональная модель системы SIEM объединяет следующие функциональные подсистемы: сбора данных, предварительной обработки, хранения, анализа, представления [1]. Обобщенная последовательность обработки событий безопасности в решениях SIEM поясняется рисунком [2]:

Подсистемы SIEM

Далее предлагается рассмотреть пример разработки собственной SIEM системы для развития практических навыков.

В примере моделируется упрощенный сценарий атаки типа «перебор пароля» в отношении учебного веб-приложения. Задача разрабатываемой SIEM системы – оповестить администратора безопасности о попытке реализации такой атаки.

Для сборки испытательного стенда будут использоваться open-source решения и собственные приложения на PHP и C#. Архитектура испытательного стенда представлена на рисунке ниже (повторяет титульное изображение публикации).

Архитектутра SIEM системы

Для удобства навигации подразделы примера пронумерованы. Приступаем к практике:

1. Организация тестового окружения.
     1.1. Установка и настройка веб-сервера Apache.
     1.2. Установка и настройка хранилища данных MongoDB.
     1.3. Установка и настройка брокера сообщений RabbitMQ.
     1.4. Установка и настройка среды разработки Visual Studio.
2. Разработка защищаемого веб-приложения Buggy Webapp.
3. Разработка коннектора для веб-сервера Apache.
4. Разработка ядра корреляции (обработчика событий).
     4.1. Оценка производительности хранилища данных MongoDB.
     4.2. Формирование набора правил корреляции.
     4.3. Реализация ядра корреляции.
5. Разработка консоли администратора безопасности.
6. Проверка работоспособности разработанной SIEM системы.


Библиографический список:

  1. «Применение технологии управления информацией и событиями безопасности для защиты информации в критически важных инфраструктурах» – одна из первых статей (2012 год) коллектива исследователей лаборатории проблем компьютерной безопасности СПИИРАН (И. В. Котенко, И. Б. Саенко, О. В. Полубелова, А. А. Чечулин) с общими положениями по построению и функционированию SIEM систем. Полный список публикаций лаборатории.
  2. «Security Information and Event Management (SIEM) Implementation» – замечательная книга Дэвида Миллера, Шона Харриса и др. Издание 2011 года, с отдельными устаревшими главами, но во многом по-прежнему актуальное. Системный взгляд на организацию SIEM систем, доступный английский язык, понятные примеры.
  3. Magic Quadrant for Security Information and Event Management 2015. Тематические отчеты Gartner за 2016 и 2017 годы также будут полезны исследователям SIEM систем.

1. Организация тестового окружения


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

1.1 Установка и настройка веб-сервера Apache


В качестве веб-сервера будем использовать сборку XAMPP for Windows, версия 7.1.9 (Apache 2.4.27 + PHP 7.1.9). Загружаем и устанавливаем XAMPP с помощью инсталлятора, выбираем папку для установки по умолчанию – «c:\xampp\».

Для проверки правильности установки веб-сервера достаточно открыть панель управления XAMPP Control Panel и запустить модуль Apache. После чего в браузере по адресу «http://127.0.0.1/» откроется приветственная страница проекта XAMPP.

Если ошибок нет, переходим к следующему пункту.

1.2 Установка и настройка хранилища данных MongoDB


Для организации хранилища данных предлагается использовать документную базу данных MongoDB. Основная причина такого выбора – решение образовательной задачи и знакомство с подходами NoSQL. Кроме того, даже поверхностное изучение коммерческих SIEM систем позволяет сделать вывод о том, что большинство ведущих производителей вместе с традиционными SQL базами данных в своих решениях применяют технологии NoSQL/NewSQL.

Ниже представлена модель одной известной коммерческой SIEM системы, подтверждающая использование производителем решений MongoDB и RabbitMQ (брокер сообщений, рассматривается далее):

Модель коммерческой SIEM системы

Загружаем с официального сайта и устанавливаем инсталляционный пакет MongoDB Community Server версии 3.4.10. Примеры инструкций:


Проверяем работоспособность сервера, создав в коллекции (collection) test новый документ (document) с полем (field) { a: 1 }. Попытка найти документ в коллекции должна завершиться успехом.

Результат проверки MongoDB

Заметим, что при добавлении документа в коллекцию сервер MongoDB по умолчанию дополняет документ полем _id типа ObjectId. «Добавка» эта уникальная (не путать с хэшем, правила формирования иные) и позволяет однозначно идентифицировать документ в коллекции.

Выполним еще одну проверку, более наглядную. Загрузим одно из доступных средств администрирования, например Robomongo версии 1.1.0-Beta, и подключимся к серверу MongoDB. В коллекции test должен содержаться созданный документ с полем { a: 1 }.

Проверка Robomongo

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

Оценку производительности хранилища данных предлагается выполнить ниже.

Если ошибок нет, переходим к следующему пункту.

Полезные ссылки и источники дополнительного знания:


1.3 Установка и настройка брокера сообщений RabbitMQ


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

Выполняем рекомендуемую инструкцию по установке RabbitMQ Server для Windows (версия 3.7.2). Потребуется установить Erlang, предварительно проверив зависимости версий – для RabbitMQ Server 3.7.2 подойдет Erlang версии 20.1.

Установщик настроит RabbitMQ Server как службу. Для дальнейших проверок перейдем в каталог «c:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.2\sbin\».

Выполняем команду запуска службы:

rabbitmq-service start

Проверяем статус командой

rabbitmqctl status

Если статус без ошибок – значит все отлично.

Для визуального контроля за функционированием брокера сообщений подключим соответствующий плагин – Management plugin:

rabbitmq-plugins enable rabbitmq_management

После запуска плагина в браузере по адресу «http://127.0.0.1:15672/» будет доступна панель администрирования (учетная запись по умолчанию – guest/guest).

Проверка RabbitMQ

При сборке испытательного стенда мы установили сервер обмена сообщениями на узле с адресом 192.168.137.1. Если необходимо удаленное подключение к панели администрирования, потребуется создать нового пользователя и предоставить ему соответствующие разрешения, например:

rabbitmqctl add_user siemuser siempass
rabbitmqctl set_user_tags siemuser administrator
rabbitmqctl set_permissions -p / siemuser ".*" ".*" ".*"

После проверки подключения к панели администрирования считаем установку и настройку брокера сообщений успешной. Проверку обмена сообщениями реализуем на следующих этапах.

Источники дополнительного знания:


1.4 Установка и настройка среды разработки Visual Studio


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

Используем Visual Studio Community 2017, отправная точка для установки – www.visualstudio.com/ru/downloads/. Проверку правильности установки отложим до сборки первого решения на C#.

2. Разработка защищаемого веб-приложения Buggy Webapp


Для примера разработаем простое веб-приложение, реализующее функцию аутентификации пользователя. Вдохновляемся идеями минимализма в разметке, верстаем макет приложения с использованием Bootstrap 4. Для реализации используем язык PHP.

Исходный код приложения Buggy Webapp: buggy/admin.php.

Скрипт admin.php запрашивает имя пользователя и пароль и сравнивает их с соответствующими параметрами административной учетной записи (admin/admin). Если имя пользователя и/или пароль не совпадают, выводится сообщение об ошибке.

Сообщение об ошибке

В случае правильно введенных имени пользователя и пароля предоставляется доступ к административному разделу.

Предоставление доступа

Сохраняем файл admin.php в соответствующей папке сборки XAMPP (путь к файлу – «c:\xampp\htdocs\buggy\admin.php»). Из панели управления XAMPP запускаем веб-сервер, после чего веб-приложение должно быть доступно в браузере по адресу «http://127.0.0.1/buggy/admin.php». Если ошибок нет, идем дальше.

3. Разработка коннектора для веб-сервера Apache


Как отследить обращения к защищаемому веб-приложению и попытаться обнаружить подозрительные действия пользователей? Простой и понятный способ – просмотреть журнал доступа (журнал обращений) веб-сервера.

В случае используемого окружения журнал обращений хранится в файле access.log (примерный путь в XAMPP – «c:\xampp\apache\logs\access.log»).

После нескольких загрузок веб-приложения в браузере обратимся к содержимому файла журнала:

127.0.0.1 - - [01/Jan/2099:12:30:39 +0300] "GET /buggy/admin.php?username=hacker&password=123 HTTP/1.1" 200 2040 "http://127.0.0.1/buggy/admin.php" "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36"

Формат записи определяется в конфигурационном файле httpd.conf веб-сервера Apache (примерный путь в XAMPP – «c:\xampp\apache\conf\ httpd.conf»):

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
CustomLog "logs/access.log" combined

Знакомимся с детальным описанием формата, готовим схему мэппинга и приступаем к разработке коннектора.

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

Исходный код коннектора: ApacheConnector.

Общее описание алгоритма:

  1. На начальном этапе обращаемся к журналу доступа access.log и запоминаем размер файла.
  2. Далее в бесконечном цикле с паузой между итерациями отслеживаем изменения размера файла. При увеличении размера читаем из файла последние добавленные строки и передаем в очередь сообщений RabbitMQ, запоминаем новый размер файла.
  3. Файл access.log может быть перезаписан. Учитываем такой случай (уменьшение размера файла).

Стиль форматирования кода стараемся выдерживать согласно примерам Джеффри Рихтера (Jeffrey Richter) и Стива Макконнелла (Steve McConnell). Обе эти книги горячо рекомендуются всем заинтересованным лицам.

Для сборки коннектора потребуется подключить к проекту библиотеку .NET/C# RabbitMQ client library. Проще всего это сделать, установив соответствующий пакет NuGet в консоли Package Manager Console среды разработки Visual Studio с помощью команды:

Install-Package RabbitMQ.Client -Version 5.0.1

Отметим, что при сборке решения, доступного на GitHub (github.com/fisher85/AirSIEM), нет необходимости вручную устанавливать пакеты – они загрузятся автоматически (требуется лишь подключение к Интернету).

Выполним тестовый запуск коннектора с одновременной проверкой работоспособности брокера сообщений в соответствии со следующим сценарием:

  1. Запуск приложения ApacheConnector. Коннектор начинает отслеживать изменения размера файла access.log.
  2. В браузере несколько раз обновляем страницу веб-приложения Buggy Webapp, при этом в журнал доступа веб-сервера будут дописаны строки, соответствующие обращениям браузера к веб-серверу.
  3. Приложение ApacheConnector обнаружит изменения размера файла и отправит последние строки в очередь брокера сообщений RabbitMQ.

    Проверка ApacheConnector
  4. Если все правильно настроено, в панели администрирования RabbitMQ (адрес для нашего случая – «http://192.168.137.1:15672/») мы обнаружим добавленную очередь AirSIEM_ConnectorQueue с ненулевой нагрузкой.

    Нагрузка RabbitMQ

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

Скромный опыт по устранению ошибок в настройке RabbitMQ:

  1. Первое, что стоит попробовать – отключить брандмауэр, антивирус, проксификатор и др. Если поможет – включить и правильно их настроить.
  2. Если возникает ошибка несовпадения Erlang hash взаимодействующих компонентов, попробуйте оставить на рабочей станции одну единственную установленную версию Erlang.

Примечания по алгоритму работы коннектора:

  1. Источники вдохновения: примеры из книги Джеффри Рихтера «Программирование на платформе .NET 4.5» (глава 27, «Асинхронные вычислительные операции») и проект Log Monitor.
  2. Почему не используем FileSystemWatcher? В одном случае на миллион класс будет некорректно отслеживать изменения файла. Этот случай, по известному закону, наблюдался при проведении экспериментов.

4. Разработка ядра корреляции (обработчика событий)


Итак, к настоящему этапу мы настроили подсистему сбора событий безопасности от одного источника – веб-сервера Apache. Коннектор ApacheConnector отслеживает изменения журнала обращений access.log и отправляет последние строки в очередь брокера сообщений RabbitMQ.
Следующий этап – разработка ядра корреляции (обработчика событий). Но предварительно, как было отмечено ранее, предлагается оценить скорость записи и чтения из хранилища данных MongoDB. Ожидаем, что этот компонент будет представлять собой bottleneck разрабатываемой системы и определит верхнюю границу производительности.

4.1 Оценка производительности хранилища данных MongoDB


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

Исходный код приложения: MongoBenchmark/Program.cs.

Для работы с MongoDB к проекту необходимо подключить .NET driver for MongoDB. Проще всего это сделать, установив соответствующий пакет NuGet в консоли Package Manager Console с помощью команды:

Install-Package MongoDB.Driver -Version 2.5.0

После запуска приложения оценим результаты бенчмарка:

InsertMany by 1: 20000 ops in 13.52 seconds (1479.15 ops/sec) => 1479.15 docs/sec
InsertMany by 2: 10000 ops in 7.11 seconds (1406.24 ops/sec) => 2812.48 docs/sec
InsertMany by 5: 4000 ops in 3.20 seconds (1250.93 ops/sec) => 6254.66 docs/sec
InsertMany by 10: 2000 ops in 2.08 seconds (960.88 ops/sec) => 9608.78 docs/sec
InsertMany by 50: 400 ops in 1.15 seconds (347.68 ops/sec) => 17384.15 docs/sec
InsertMany by 100: 200 ops in 1.06 seconds (188.32 ops/sec) => 18832.26 docs/sec
InsertMany by 250: 80 ops in 0.95 seconds (83.87 ops/sec) => 20968.05 docs/sec
InsertMany by 500: 40 ops in 0.92 seconds (43.67 ops/sec) => 21835.64 docs/sec
InsertMany by 1000: 20 ops in 0.93 seconds (21.39 ops/sec) => 21391.22 docs/sec
InsertMany by 5000: 4 ops in 1.00 seconds (3.99 ops/sec) => 19936.32 docs/sec
InsertMany by 10000: 2 ops in 1.01 seconds (1.97 ops/sec) => 19730.96 docs/sec
InsertMany by 20000: 1 ops in 1.01 seconds (0.99 ops/sec) => 19832.80 docs/sec
Find: 10000 ops in 6.17 seconds (1620.21 ops/sec)

«Горб» распределения приходится на случай отправки 500 событий в одном пакете (блоке), скорость последовательной записи при этом – 21835 документов в секунду. Скорость случайного чтения из коллекции – 1620 документов в секунду. Учитывая тот факт, что испытательный стенд организован с использованием персональных компьютеров «нетоповых» комплектаций, результаты нас вполне устраивают. Считаем, что полученные в эксперименте значения скорости записи и чтения позволят хранилищу данных MongoDB обработать запланированную в примере нагрузку.

Примечания:

  • Широко цитируемый источник по вопросу «замера» времени выполнения операций: обсуждение Environment.TickCount vs DateTime.Now на Stack Overflow.
  • Попытка вставить в коллекцию два документа c одинаковыми _id закончится неприятностью в виде исключения MongoDB.Driver.MongoWriteException с примерным пояснением:

    E11000 duplicate key error collection: test.events index: _id_ dup key: { : ObjectId('5a2a2b386a49df197845deaa') }
    

4.2 Формирование набора правил корреляции


И еще одно отступление. Ядро корреляции при поступлении очередного события безопасности пытается применить к нему заранее загруженные правила обработки (правила выявления зависимостей между отдельными событиями, правила корреляции). Сформируем тестовый набор правил, который будет использоваться далее в примере.

Для описания правил будем использовать синтаксис правил корреляции, предложенный в проекте OSSEC, с минимальными изменениями. В примере моделируется упрощенный сценарий атаки типа «перебор пароля» в отношении защищаемого веб-приложения, для этого примера составим соответствующий набор правил test_webapp_rules.xml:

<group name="web-app">

  <rule id="100000" level="0">
    <match>/buggy/</match>
    <description>Access to BUGGY webapp</description>
  </rule>

  <rule id="100001" level="0">
    <if_sid>100000</if_sid>
    <match>password</match>
    <description>Attempt to login to BUGGY webapp</description>
  </rule>
  
  <rule id="100002" level="1" frequency="3" timeframe="5">
    <if_matched_sid>100001</if_matched_sid>
    <same_source_ip/>
    <description>Brute force trying to login to BUGGY webapp</description>
  </rule>

</group>

Формат набора правил минимально отличается от формата XML. К примеру, допускается наличие в файле нескольких корневых элементов. Такой документ не является корректным (well-formed) документом XML, эту особенность будем учитывать при разборе файла средствами, предоставляемыми пространством имен System.XML.

Далее рассмотрим отдельно каждое правило и коротко поясним особенности синтаксиса. Первое правило:

  <rule id="100000" level="0">
    <match>/buggy/</match>
    <description>Access to BUGGY webapp</description>
  </rule>

Элемент <rule> описывает правило.

Атрибут id элемента <rule> определяет идентификатор правила. Идентификаторы выбираем из диапазона, рекомендуемого проектом OSSEC для «авторских» правил: >=100000.

Атрибут level элемента <rule> определяет уровень значимости правила. Минимальное значение – 0 (в общем случае не отображаем в консоли администратора безопасности), максимальное значение – 16.

Элемент <match> задает подстроку для поиска в строке обрабатываемого сообщения.

Элемент <description> задает описание правила, которое будет отображаться в качестве оповещения для администратора безопасности.

Случай срабатывания такого правила проверяется просто – если подстрока, указанная в элементе <match>, будет обнаружена в строке обрабатываемого сообщения, ядро корреляции сформирует оповещение безопасности.

Логика правила 100000 следующая: оповещать систему безопасности обо всех попытках обращения к защищаемому веб-приложению Buggy Webapp. Для этого отслеживается подстрока «/buggy/» во всех обращениях к веб-серверу. Уровень значимости у правила 100000 нулевой, критичность в отслеживаемых обращениях отсутствует, срабатывания правила будут использоваться для построения более сложных цепочек правил.

Отметим отдельно, что по сути правило 100000 никаких зависимостей между событиями безопасности не обнаруживает и «корреляций» не выявляет. В этом смысле корректнее называть такую запись правилом обработки, а не правилом корреляции.

Второе правило:

  <rule id="100001" level="0">
    <if_sid>100000</if_sid>
    <match>password</match>
    <description>Attempt to login to BUGGY webapp</description>
  </rule>

В описании правила 100001 присутствует новый элемент <if_sid> с идентификатором правила 100000, который накладывает дополнительное условие срабатывания – необходимо, чтобы до этого сработало правило 100000.

Логика правила 100001: если обрабатываемая строка имеет отношение к доступу к защищаемому веб-приложению (предварительно сработало правило 100000) и при этом в обращении к веб-серверу обнаружена подстрока «password» (возможно свидетельствующая о передаче пароля в форму ввода имени пользователя и пароля), то оповестить систему безопасности о попытке получения административного доступа – «Attempt to login to BUGGY webapp».

Правило 100001 позволяет выявлять зависимости между отдельными событиями безопасности и корректно может называться правилом корреляции.

Третье правило:

  <rule id="100002" level="1" frequency="3" timeframe="5">
    <if_matched_sid>100001</if_matched_sid>
    <same_source_ip/>
    <description>Brute force trying to login to BUGGY webapp</description>
  </rule>

В описании правила 100002 присутствует новый элемент <if_matched_sid> с идентификатором правила 100001, который накладывает дополнительное условие срабатывания – необходимо, чтобы правило 100001 сработало не менее 3 раз (атрибут frequency=«3» элемента <rule>) в течение последних 5 секунд (timeframe=«5»).

Пустой элемент <same_source_ip/> указывает на то, что при подсчете срабатываний правила, заданного элементом <if_matched_sid>, учитываются только срабатывания с совпадающими IP-адресами источника.

Логика правила 100002: если в течение последних 5 секунд с одного и того же адреса зафиксировано множество попыток (3 и более) получения доступа к защищаемому веб-приложению, то сформировать оповещение с более высоким уровнем значимости level=«1» о попытке подбора пароля доступа – «Brute force trying to login to BUGGY webapp».

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

4.3 Реализация ядра корреляции


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

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

  1. Ядро корреляции «слушает» очередь сообщений AirSIEM_ConnectorQueue.
  2. При поступлении очередного сообщения (события) ядро пытается применить к нему заранее загруженные правила обработки событий (правила корреляции).
  3. В случае применимости одного из правил к поступившему событию безопасности ядро при необходимости формирует инцидент безопасности и сохраняет его в коллекции alerts хранилища данных MongoDB.

Исходный код: AirSIEM.

Реализация будет достаточно объемной, поэтому для удобства отладки подключим к проекту систему логгирования NLog. Проще всего это сделать, установив соответствующий пакет NuGet в консоли Package Manager Console с помощью команды:

Install-Package NLog -Version 4.4.12

Кроме того, для работы с брокером сообщений потребуется подключить пакет RabbitMQ.Client, а для взаимодействия с хранилищем данных – пакет MongoDB.Driver:

Install-Package RabbitMQ.Client -Version 5.0.1
Install-Package MongoDB.Driver -Version 2.5.0

Следуя инструкции по настройке логгера NLog, добавляем к проекту (Меню Project > Add Existing Item) конфигурационный файл nlog.config (пример содержания) и указываем необходимость его копирования в выходной каталог (перейти в окно Solution Explorer > выбрать файл nlog.config > перейти в окно Properties > для свойства «Copy To Output Directory» выбрать значение «Copy always»).

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

Для проверки правильности работы ядра корреляции необходимо убедиться в том, что в случае обнаружения сценариев атак (заданных соответствующими правилами) ядро формирует инциденты безопасности и сохраняет их в коллекции alert хранилища данных MongoDB. Предлагается проверку выполнить на заключительном этапе, после разработки всех компонентов системы.

5. Разработка консоли администратора безопасности


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

Исходный код: console/index.php.

Чтобы код PHP мог взаимодействовать с MongoDB, потребуется выполнить два действия: к интерпретатору PHP подключить соответствующее расширение, а к веб-приложению – соответствующую библиотеку.

5.1 Подключение расширения php_mongodb.dll к веб-серверу


Вспомним, что мы используем в качестве веб-сервера сборку XAMPP for Windows. По умолчанию интерпретатор PHP не знает о существовании хранилища MongoDB, исправить это можно установкой драйвера MongoDB PHP Driver on Windows.

Открываем инструкцию по установке для нашего случая – Installing the MongoDB PHP Driver on Windows.

Отправляемся на сайт pecl.php.net/package/mongodb в поисках подходящей версии драйвера php_mongodb.dll. Выбираем последнюю стабильную версию (1.4.0), ОС Windows, PHP Version 7.1, thread safe, x86. Выбранный архив – php_mongodb-1.4.0-7.1-ts-vc14-x86.zip, в архиве нужный файл php_mongodb.dll.

Копируем драйвер php_mongodb.dll в папку расширений PHP. По умолчанию «c:\xampp\php\ext\». Добавляем в файл настроек PHP (по умолчанию «c:\xampp\php\php.ini») строку «extension=php_mongodb.dll» в раздел подключения расширений.

Перезапускаем Apache (проще всего – из панели XAMPP), чтобы на последующих этапах не тратить лишнее время на разбор ошибок типа «Uncaught Error: Class 'MongoDB\Driver\Manager' not found».

5.2 Подключение к веб-приложению библиотеки MongoDB PHP Library


Далее необходимо подключить к проекту консоли администратора библиотеку MongoDB PHP Library.

Изучаем официальную документацию. В руководстве рекомендуется самый простой способ – с помощью Composer.

Устанавливаем Composer, знакомимся с примерами использования.

Создаем папку для будущего проекта, например, «c:\xampp\htdocs\console\», выполняем в папке команду установки пакета mongodb:

composer require mongodb/mongodb

Результат выполнения команды:

Установка Composer

Composer загрузит необходимые файлы и добавит их в проект. Чтобы проект мог использовать функционал библиотеки MongoDB PHP Library, в код нужно добавить одну строку:

require_once __DIR__ . "/vendor/autoload.php";

Сохраняем код приложения в файле «c:\xampp\htdocs\console\index.php» и открываем в браузере.

Проверка консоли администратора

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

Если ошибок нет, переходим к заключительному этапу.

Источники дополнительного знания:

  1. MongoDB PHP Driver
  2. MongoDB PHP Library
  3. Install the MongoDB PHP Library

6. Проверка работоспособности разработанной SIEM системы


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

Напомним основную задачу разрабатываемой системы – оповестить администратора безопасности о попытке реализации сценария атаки типа «перебор пароля» в отношении защищаемого веб-приложения.

Рассмотрим итоговый тестовый сценарий в общем виде:

  1. Злоумышленник открывает страницу admin.php защищаемого веб-приложения Buggy Webapp и несколько раз пытается подобрать имя пользователя и пароль администратора.
  2. После нескольких безуспешных попыток злоумышленник подбирает учетные данные администратора – «admin/admin» – и получает доступ к административному разделу (обнаружение успешной попытки доступа после нескольких безуспешных – домашнее задание).
  3. Разработанная SIEM система в результате обработки зарегистрированных событий безопасности с применением заданных правил корреляции обнаруживает реализацию сценария атаки, формирует инцидент безопасности и оповещает администратора.

Далее предлагается выполнить тестовый сценарий и рассмотреть последовательность действий SIEM системы.

Шаг 1. Предварительная подготовка.
Для «чистоты» эксперимента очищаем хранилище данных. Для этого подключаемся к MongoDB с помощью Robomongo и удаляем базу данных AirSIEM (если существует).

Запускаем ApacheConnector.

Шаг 2. Моделирование действий злоумышленника.
Открываем в браузере веб-приложение Buggy Webapp по адресу «http://127.0.0.1/buggy/admin.php». В течение 5 секунд предпринимаем три попытки подбора имени пользователя и пароля администратора.

Шаг 3. Проверка работы коннектора.
В окне приложения ApachеConnector проверяем факт чтения журнала обращений веб-сервера и передачи зарегистрированных событий безопасности в очередь брокера сообщений.

Проверяем в панели администрирования брокера сообщений RabbitMQ («http://127.0.0.1:15672/») наличие нагрузки: в очереди AirSIEM_ConnectorQueue должны появиться сообщения.

Шаг 4. Проверка работы ядра корреляции.
Далее в процесс обработки вступает ядро корреляции. Запускаем приложение AirSIEM. Правильность работы будем оценивать по лог-файлу Logs/log.txt (путь относительно выходного каталога сборки) логгера NLog.

На предварительном этапе загружаются правила корреляции:

----- AirSIEM start -----
ParseRuleDir start
ParseRulesFromXML handles file: test_webapp_rules.xml
  3 rules processed: 100000, 100001, 100002
ParseRuleDir: total 1 files processed
ParseRuleDir: total 3 rules processed
ParseRuleDir stop

После загрузки правил выполняется построение цепочек правил:

CheckDependencies start
Dependencies: 
  100000 children => 100001
  100001 children => 100002
  100002 children => 
CheckDependencies stop

Далее создаются очереди для подсчета числа срабатываний тех правил, идентификаторы которых встречаются в элементах <if_matched_sid>. В тестовом наборе содержится 3 правила, среди которых только одно правило 100002 подсчитывает срабатывания другого правила – с идентификатором 100001. Очередь создается для идентификатора 100001:

GenerateQueueList start
Created 1 queues:
  [100001, FireQueue object => ID=[100001], count=[0], timeFrame=[5 sec], maxSize=[1000]]
GenerateQueueList stop

Затем инициализируется и запускается «подписчик», который «слушает» очередь AirSIEM_ConnectorQueue и передает принятые сообщения обработчику:

RabbitMQConsumer init
RabbitMQConsumer start

После первой попытки злоумышленника подобрать имя пользователя и пароль коннектор ApacheConnector передает очередную строку из журнала обращений access.log веб-сервера в очередь RabbitMQ, «подписчик» получает сообщение и передает на обработку:

RMQ message received: ApacheConnector:127.0.0.1 - - [01/Jan/2099:16:24:57 +0300] "GET /buggy/admin.php?username=1&password...

Из сообщения формируется нормализованное событие безопасности (экземпляр класса SecurityEvent):

SecurityEvent object => timestamp=[16:24:57], source=[127.0.0.1], destination=[], message=[GET /buggy/admin.php?username=1&password=1 HTTP/1.1]

Далее ядро корреляции применяет загруженные правила к обрабатываемому событию. При первом «проходе» просматриваются только те правила, срабатывания которых не зависят от других правил:

Check rule 100000 - Access to BUGGY webapp
  Check <match>/buggy/</match>
  Rule 100000 matched
  ALERT: LEVEL 0 - Access to BUGGY webapp

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

Далее рекурсивно просматриваются правила, срабатывания которых зависят от срабатывания правила 100000:

  Check the child rules
  Check rule 100001 - Attempt to login to BUGGY webapp
    Check <if_sid>100000</if_sid>
    Check <match>password</match>
    Rule 100001 matched
    ALERT: LEVEL 0 - Attempt to login to BUGGY webapp
    Matched rule is queue tracked
    Enqueue item: FireQueueItem object => timestamp=[16:24:57], source=[127.0.0.1], destination=[]
    FireQueue object => ID=[100001], count=[1], timeFrame=[5 sec], maxSize=[1000]
      1: FireQueueItem object => timestamp=[16:24:57], source=[127.0.0.1], destination=[]
    Check the child rules
    Check rule 100002 - Brute force trying to login to BUGGY webapp
      Check <if_matched_sid>100001</if_matched_sid>
        QueueDictionary.CheckIfMatched start
          counter++ => counter=[1]
          counterSameSourceIP++ => counterSameSourceIP=[1]
        Rule 100001 QueueDictionary.CheckIfMatched == FALSE
    Rule 100002 not matched
    Check rule 100002: OK
    Check the child rules: OK
  Check rule 100001: OK
  Check the child rules: OK
Check rule 100000: OK

В результате обработки срабатывает правило 100001, в очередь подсчета FireQueue заносится первое срабатывание. Когда число срабатываний станет равным 3, выполнится одно из условий срабатывания правила 100002.

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

RMQ message received: ApacheConnector:127.0.0.1 - - [01/Jan/2099:16:25:02 +0300] "GET /buggy/admin.php?username=1&password...
SecurityEvent object => timestamp=[16:25:02], source=[127.0.0.1], destination=[], message=[GET /buggy/admin.php?username=1&password=1 HTTP/1.1]
Check rule 100000 - Access to BUGGY webapp
  Check <match>/buggy/</match>
  Rule 100000 matched
  ALERT: LEVEL 0 - Access to BUGGY webapp
  Check the child rules
  Check rule 100001 - Attempt to login to BUGGY webapp
    Check <if_sid>100000</if_sid>
    Check <match>password</match>
    Rule 100001 matched
    ALERT: LEVEL 0 - Attempt to login to BUGGY webapp

После срабатывания правила 100001 проверяется, не подсчитывается ли число срабатываний в какой-либо очереди подсчета FireQueue? Действительно, для идентификатора правила 100001 такая очередь существует:

    Matched rule is queue tracked
    Enqueue item: FireQueueItem object => timestamp=[16:25:02], source=[127.0.0.1], destination=[]
    FireQueue object => ID=[100001], count=[3], timeFrame=[5 sec], maxSize=[1000]
      1: FireQueueItem object => timestamp=[16:24:57], source=[127.0.0.1], destination=[]
      2: FireQueueItem object => timestamp=[16:25:01], source=[127.0.0.1], destination=[]
      3: FireQueueItem object => timestamp=[16:25:02], source=[127.0.0.1], destination=[]

В очереди подсчета зафиксированы 3 срабатывания правила 100001 за интервал времени timeframe (5 секунд). Обработка события безопасности продолжается:

    Check the child rules
    Check rule 100002 - Brute force trying to login to BUGGY webapp
      Check <if_matched_sid>100001</if_matched_sid>

В этом месте проверяется количество срабатываний правила 100001. Поскольку в описании правила присутствовал элемент <same_source_ip/>, одновременно подсчитываются срабатывания с одинаковым значением IP-адреса источника:

        QueueDictionary.CheckIfMatched start
          counter++ => counter=[1]
          counterSameSourceIP++ => counterSameSourceIP=[1]
          counter++ => counter=[2]
          counterSameSourceIP++ => counterSameSourceIP=[2]
          counter++ => counter=[3]
          counterSameSourceIP++ => counterSameSourceIP=[3]
        Rule 100001 QueueDictionary.CheckIfMatched == TRUE
      Rule 100002 matched
      ALERT: LEVEL 1 - Brute force trying to login to BUGGY webapp
    Check rule 100002: OK
    Check the child rules: OK
  Check rule 100001: OK
  Check the child rules: OK
Check rule 100000: OK

Правило 100002 срабатывает, ядро корреляции обнаруживает сценарий атаки типа «перебор пароля» и формирует соответствующий инцидент безопасности. Сведения об инциденте отправляются в хранилище данных MongoDB.

Шаг 5. Проверка хранилища данных.
Проверяем формирование оповещений. Для этого подключаемся к MongoDB с помощью Robomongo и просматриваем коллекцию документов alerts базы данных AirSIEM. Коллекция должна быть непустой.

Шаг 6. Моделирование действий администратора безопасности.
Открываем в браузере консоль администратора безопасности по адресу: «http://127.0.0.1/console/index.php». Если все компоненты SIEM системы настроены правильно, после выполнения тестового сценария окно консоли должно иметь примерный вид:

Финальный запуск разработанной SIEM системы

Подчеркнем, обнаружены не только отдельные события, а выделена последовательность действий злоумышленника и идентифицирован сценарий атаки. В консоли администратора это строка под номером 7, выделенная цветом, с сообщением о выявленной реализации сценария атаки типа «перебор пароля». Метка времени 16:25:03 установлена ядром корреляции, значение отличается от метки времени события, соответствующего третьей попытке получения доступа злоумышленника (16:25:02).

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

Итоги

Администратор безопасности оповещен о подозрительных действиях злоумышленника. Разработанная SIEM система выполнила поставленную задачу. Занавес.

Выводы и заключение


В материалах занятия рассмотрены вопросы построения современных систем управления инцидентами безопасности (SIEM) на примере разработки собственного решения SIEM. Продемонстрированы возможности практического применения разработанной системы в условиях мониторинга безопасности защищаемого веб-приложения: успешно обнаружен сценарий атаки злоумышленника типа «перебор пароля», сформирован инцидент, оповещен администратор.

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

Кроме того, авторы сомневаются в возможности промышленного применения open-source решений SIEM и по большинству позиций соглашаются с мнением Антона Чувакина – «Why No Open Source SIEM, EVER?».

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

Все исходные коды используемых проектов доступны на GitHub в открытом репозитории AirSIEM.

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

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


  1. el_gato
    11.05.2018 14:41

    А почему выбрали способ с чтением лог файла, а не перенаправлением лога в пайп?
    Дает этот способ какие-то преимущества?
    А то я тут на работе как раз недавно подобную вещь реализовывал, только через Kafka + Kafka Streams.


    1. fisher85 Автор
      11.05.2018 16:08

      Соглашаемся с тем, что вариантов передачи исходных событий от источника (в примере — веб-сервер Apache) к обработчику (ядру корреляции) известно множество. В самом начале даже предпринимались попытки использовать связку Filebeat > Logstash > RabbitMQ для этих целей (отказались по причине нетривиальности настроек). Детальное сравнение различных реализаций в рамках проекта не проводилось.

      В наших условиях использование связки «простой пример приложения, отслеживающего изменения лог-файла источника данных» > RabbitMQ обусловлено в большей степени образовательными целями: познакомить слушателей с брокерами сообщений (как классом программных решений) и показать простоту реализации интерфейса в исходном коде коннектора.


      1. el_gato
        11.05.2018 18:27

        Я имел в виду почему аксесс лог апача читали так хитро, а не не напрямую в апачконнектор, без записи в файл httpd.apache.org/docs/2.4/logs.html#piped


  1. fisher85 Автор
    11.05.2018 20:29

    Задача принимается к проработке в последующих релизах, спасибо!


  1. pavel_kirillov
    13.05.2018 14:46

    Интересная статья, спасибо!
    1. Можете рассказать, почему выбрали именно такой стенд с веб-сервером, не, например, авторизацией в Windows?
    2. Почему именно такие продукты для разработки выбраны?
    3. Почему архитектура SIEM получилась именно такая, а не какая-то другая?
    4. Почему не взяли сразу готовый стек продуктов ELK (там меньше разработки, имхо, надо сложить конструктор в единое целое)?


    1. fisher85 Автор
      13.05.2018 23:05

      Пробуем коротко и по порядку:

      1. Среди десятка разных источников событий и коннекторов предложенный в примере вариант c веб-сервером показался нам наиболее удачным. В итоговом сценарии открываем одновременно 4 окна: 1 — окно браузера с тестовым веб-приложением, 2 — окно коннектора, 3 — окно ядра корреляции, 4 — окно с консолью администратора. И слушатели, самостоятельно моделируя перебор пароля, наблюдают взаимосвязь разработанных компонентов и «превращение» отдельных событий безопасности в инцидент. Возможно субъективно, но пример с авторизацией в Windows кажется менее наглядным. Хотя, когда остается время и аудитория подготовленная, после предложенного ApacheConnector довольно быстро появляются и WMIConnector, и MysqlConnector, и SSHConnector, и другие.

      2. XAMPP — быстро. MongoDB — чтобы познакомить с NoSQL/NewSQL. RabbitMQ — чтобы познакомить с брокерами сообщений на примере одного из самых популярных. PHP и C# — личные предпочтения.

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

      4. Уверены, предложенный пример поясняет функциональную модель SIEM системы лучше, чем в примере со стеком ELK. Разработки во втором случае меньше, но правильно ли это? Когда «своими руками» прочитал событие безопасности из файла, передал в канал, нормализовал, обработал, сформировал инцидент, отправил в хранилище и на экран консоли, то сразу разобрался.