Data Science в Инфобезе или observability на максималках
data engineering
pcap
трафик
DUCKDB
SIGMA
Author
i2z1@ddslab.ru
Published
April 12, 2024
Решение возникающих задач подходящими инструментами – удел сильных духом инженеров, знающих сильные и слабые стороны технологий и умеющие их применять.
Сегодня хочу продемонстрировать как можно совместно использовать известные инструменты для решения задач информационной безопасности, а именно – анализ дампа сетевого трафика.
Принципы проведения анализа или Методология исследования
Перед проведением анализа трафика сформулирую принципы, по которым я подбирал инструменты.
Поверхностный анализ существующих средств анализа сетевого трафика приведет к большому количеству существующих решений ( 1, 2, 3). Кроме того, в трафик можно смотреть глазами при помощи анализатора трафика Wireshark.
Цель проекта
Не переизобретать велосипед, использовать существующие зрелые решения
Автоматизировать анализ – он должен быть автоматизирован, выполняться автоматически с определенным качеством, однако позволяя контролировать отдельные процессы внутри, а также итеративно улучшать их в дальнейшем.
Минимизировать операционную аналитическую деятельность в UI – аналитика должна быть воспроизводимой. Поподробнее об этом можно посмотреть здесь
В идеале – такой подход позволяет один раз провести инструментальный анализ, а дальше при изменении входных данных, автоматически получить новый результат.
Извлечение метаданных трафика с Zeek
Сетевой трафик для анализа
Где взять трафик для анализа? Если Вы уверены, что Вас атакуют хакеры, то можно его записать ;) Например, при помощи Wireshark, или в Linux – при помощи tcpdump.
Если Вы не нужны хакерам ;) Вас никто не атакует, то образцы трафика можно скачать:
Запись трафика хранится в файлах pcap, pcapng и вариациях.
Метаданные
Для анализа нам прежде всего нужны характеристики сетевых пакетов: IP-адресы, порты, DNS и HTTP запросы и ответы и др. Для извлечения этой информации из записанного “сырого” трафика воспользуемся Zeek.
Zeek относится к классу средств IDS/NTA (Intrusion Detection System/Network Traffic Analyzer). Zeek умеет извлекать метаинформацию трафика и раскидывать ее в соответствующие папки по протоколам. При этом Zeek сохраняет связность метаинформации между уронями модели OSI, так что всегда можно проследить в каком конкретно пакете на сетевом уровне передавался тот или иной запрос протоколов прикладного уровня.
Zeek устанавливается на Linux и MacosX, если у Вас Windows, то потребуется виртуальная машина, например VirtualBox. Сайт Zeek – https://zeek.org/.
После его установки, метаданные из трафика извлекаются при помощи команды
zeek –C –r mypackets.pcap
Параметр -C отвечает за игнорирование “битых” пакетов. В результате работы Вы получите набор файлов (логов) с метаинформацией о сетевом трафике.
Язык программирования R
Язык программирования R отлично справляется с ролью аналитического ядра анализа метаинформации и служить “клеем”, связывая входы и выходы других инструментов. Для работы с R я использую RstudioIDE, и даже создаю для нее темы оформления
Для работы с сетвым анализатором Zeek, небезысвестный Боб Рудис создал для R пакет zeekr.
Для установки пакета R из Github нам понадобится другой пакет – devtools. Убедитесь, что он у Вас установлен.
После установки в консоли R пакета zeekr с помощью
можно проверить доступность Zeek – zeekr::find_zeek().
Импорт данных в R
Для сбора метаинформации из файлов с записанным трафиком в виде pcap в формат датафремов, с которым работает R, в пакете zeekr есть функция pcap_to_zeek():
После извлечения метаинформации из трафика, импортируем ее в R:
zeek_list <-read_zeek_logs(loc)
zeek_list – это именованный список (list) из датафреймов Zeek.
Список элементов можно получить через names(zeek_list), а обратиться к его элементам – например, так:
zeek_list$conn
Enum network
С чего можно начать анализ?
Прежде всего, хорошо бы получить первоначальное представление о сети, трафик из которой мы получили: какие узлы сети генерируют трафик, на какие сетевые порты, его соотношение между хостами и портами.
Источники и приемники
Каждый узел сети является и источником сетевого трафика (source), и его получателем(destination). Узлы отправляют запросы, получают ответы.
Посмотрим структуру источников, используя библиотеку манипуляции данными dplyr:
# A tibble: 5 × 5
ip_src packets orig_bytes resp_bytes connection_duration
<chr> <int> <int> <int> <dbl>
1 45.15.89.1 70585 NA NA NA
2 45.15.89.180 108 163473 170170 10.6
3 45.15.89.56 22 NA NA NA
4 45.15.89.33 5 NA NA NA
5 fe80::4167:163e:82a9:f2de 1 NA NA NA
Почему я не конкретизирую исходные данные, которые анализирую? Потому что, это неважно – независимо от записанного трафика состав колонок логов Zeek будет один и тот же, т.е. программный код будет работать на любых данных.
Аналогично, приемники трафика (куда выкачивается трафик) можно посмотреть так:
# A tibble: 6 × 5
ip_dst packets orig_bytes resp_bytes connection_duration
<chr> <int> <int> <int> <dbl>
1 45.15.89.33 70712 NA NA NA
2 45.15.89.255 3 NA NA NA
3 45.15.89.56 3 707 21330 11.8
4 224.0.0.251 1 NA NA NA
5 45.15.89.1 1 NA NA NA
6 ff02::fb 1 NA NA NA
Сетевые порты
Давайте посмотрим какие сетевые службы используются в записанном трафике – это можно определить по номерам используемых портов
SIGMA – это формат описания правил детектирования событий информационной безопасности в логах информационных систем. По сути, это сигнатуры атак на наши системы. Поскольку Zeek преобразовал трафик в метаинформацию, которая по сути лог, то мы можем применить имееющиеся сигнатуры SIGMA к нашим данным и попробывать найти сетевые атаки.
Универсальность правил SIGMA заключается в том, что с помощью специального конвертера мы можем перевести любое ее правило в формат популярных SIEM систем или даже в обычный SQL запрос к базе данных, в корой мы можем хранить наши логи. Этот конвертер работает, если для него есть соответствующий плагин, который умеет переводить правила из родного формата SIGMA (это yaml) в формат интересующей нас системы анализа логов. Далее с помощью этого запросы можно обнаружить признаки атаки на нашу систему.
Посмотреть список поддерживаемых плагинов sigma можно с помощью
sigma plugin list
Нас будет интересовать плагин sqlite. Установим его:
sigma plugin install sqlite
В репозитории имеющихся правил для SIGMA https://github.com/SigmaHQ/sigma, в папке rules имеется подпапка network, а в ней – zeek. Это то, что нам нужно!
DuckDB
Чтобы воспользоваться найденными правилами детектирования, нам нужен подходящий бэкенд, который понимает SQL.
Для этого как нельзя лучше подойдет аналитическая СУБД DuckDB – https://duckdb.org/.
DuckDB – это аналог SQLite в мире анализа данных. Колоночная OLAP СУБД, представленная единым бинарником, умеет работать с данными, размер которых превышает объем RAM. Кроме того, отлично работает с данными в формате Parquet. При этом, данные могут хранится удаленно, DuckDB умеет подгружать данные по мере необходимости по HTTPS или S3.
DuckDB и R
В R использовать DuckDB возможно с через пакет duckdb. Устанавливается из CRAN при помощи install.packages("duckdb").
После установки мы можем загрузить наши логи трафика в DuckDB и затем использовать SQL запросы, которые для нас сгенерирует конвертор SIGMA из соответсвующих правил.
Приступаем! Скопировать датафрейм R в базу данных можно либо с использованием функции copy_to(), либо dbWriteTable():
library(duckdb)library(dplyr)con <-dbConnect(duckdb::duckdb(), dbdir =":memory:")copy_to(con, zeek$conn, name ="conn")copy_to(con, zeek$dns, name ="dns")dbWriteTable(con, "files", zeek$files)dbWriteTable(con, "http", zeek$http)dbWriteTable(con, "ssh", zeek$ssh)dbWriteTable(con, "packet_filter", zeek$packet_filter)
Задействуем SIGMA
Теперь, когда наши данные внутри DuckDB, можно перейти к генерации SQL запросов, которые помогут выявить на основе наших данных возможные атаки.
Обратите внимание: каждое правило SIGMA может применяться только к одному из тех датафреймов, которые мы получили в результате работы Zeek. К какому конкретно, определяет поле type в самом YAML правиле.
Получив на выходе SQL запрос, можем теперь его испытать. Запросы к БД можно выполнять с помощью функции dbGetQuery(). При этом, нужно заполнить заглушку <TABLE_NAME> в запросе правильным названием БД. Если правило создано для dns логов, то применять мы его будем к таблице dns.
sql_req <-"SELECT * FROM dns WHERE query LIKE '%seed%' ESCAPE '\' AND query LIKE '%.nkn.org%' ESCAPE '\'"dbGetQuery(con, sql_req)
На выходе получили таблицу с 0 строк, что значит что результатом запроса является пустое множество. То есть признаков компрометации нет!
Для автоматизации всего процесса достаточно обернуть наш код в функции и прогнать по всем имеющимся сигнатурам. Этот вопрос хочу осветить в будущем отдельно.