
Beagle — это инструмент для реагирования на инциденты и цифровой криминалистики, который преобразует журналы безопасности и данные в графы.
Beagle — это инструмент для реагирования на инциденты и цифровой криминалистики, который преобразует источники данных и журналы в графы. Поддерживаемые источники данных включают FireEye HX Triages, файлы Windows EVTX, журналы SysMon и образы оперативной памяти Windows. Полученные графы могут быть отправлены в графовые базы данных, такие как Neo4J или DGraph, или сохранены локально как объекты Python NetworkX.
Beagle можно использовать напрямую как библиотеку Python или через предоставленный веб-интерфейс.
Библиотека может использоваться как последовательность функциональных вызовов из одного источника данных.
>>> from beagle.datasources import SysmonEVTX
>>> graph = SysmonEVTX("malicious.evtx").to_graph()
>>> graph
<networkx.classes.multidigraph.MultiDiGraph at 0x12700ee10>
Как граф, сгенерированный из набора нескольких артефактов
>>> from beagle.datasources import SysmonEVTX, HXTriage, PCAP
>>> from beagle.backends import NetworkX
>>> nx = NetworkX.from_datasources(
datasources=[
SysmonEVTX("malicious.evtx"),
HXTriage("alert.mans"),
PCAP("traffic.pcap"),
]
)
>>> G = nx.graph()
<networkx.classes.multidigraph.MultiDiGraph at 0x12700ee10>
Или путём строгого вызова каждого промежуточного шага процесса преобразования источника данных в граф.
>>> from beagle.backends import NetworkX
>>> from beagle.datasources import SysmonEVTX
>>> from beagle.transformers import SysmonTransformer
>>> datasource = SysmonEVTX("malicious.evtx")
# Transformers принимают источник данных и преобразуют каждое событие
# в кортеж из одного или нескольких узлов.
>>> transformer = SysmonTransformer(datasource=datasource)
>>> nodes = transformer.run()
# Transformers выдают массив узлов.
[
(<SysMonProc> process_guid="{0ad3e319-0c16-59c8-0000-0010d47d0000}"),
(<File> host="DESKTOP-2C3IQHO" full_path="C:\Windows\System32\services.exe"),
...
]
# Backends принимают узлы и преобразуют их в графы
>>> backend = NetworkX(nodes=nodes)
>>> G = backend.graph()
<networkx.classes.multidigraph.MultiDiGraph at 0x126b887f0>
Графы сосредоточены вокруг активности отдельных процессов и предназначены в первую очередь для помощи аналитикам в исследовании активности на хостах, а не между ними.
Beagle доступен в виде Docker-образа:
docker pull yampelo/beagle
mkdir -p data/beagle
docker run -v "$PWD/data/beagle":"/data/beagle" -p 8000:8000 yampelo/beagle
Также доступен как библиотека. Полная документация по API доступна на https://beagle-graphs.readthedocs.io
pip install pybeagle
Примечание: Поддерживается только Python 3.6+.
Rekall не устанавливается автоматически. Чтобы установить Rekall, выполните следующую команду:
pip install pybeagle[rekall]
Любую запись в файле конфигурации можно изменить с помощью переменных окружения, которые следуют следующему формату: BEAGLE__{SECTION}__{KEY}. Например, чтобы изменить ключ API VirusTotal, используемый при работе с Docker-образом, используйте параметр -e и установите переменную BEAGLE__VIRUSTOTAL__API_KEY:
docker run -v "data/beagle":"/data/beagle" -p 8000:8000 -e "BEAGLE__VIRUSTOTAL__API_KEY=$API_KEY" beagle
Переменные окружения и каталоги можно легко определить с помощью docker compose
version: "3"
services:
beagle:
image: yampelo/beagle
volumes:
- /data/beagle:/data/beagle
ports:
- "8000:8000"
environment:
- BEAGLE__VIRUSTOTAL__API_KEY=$key$
Docker-образ Beagle поставляется с веб-интерфейсом, который объединяет процессы преобразования данных в графы и их использования для исследования данных.
Форма загрузки оборачивает процесс создания графа и автоматически использует NetworkX в качестве бэкенда. В зависимости от параметров, требуемых источником данных, форма предложит либо загрузить файл, либо ввести текст. Например:
Любой созданный граф сохраняется локально в папке, заданной ключом dir из раздела storage в конфигурации. Это можно изменить, установив переменную окружения BEAGLE__STORAGE__DIR.
При желании к любому графу можно добавить комментарий, чтобы лучше его описать.
Каждый источник данных автоматически извлекает метаданные из предоставленного параметра. Метаданные и комментарий будут видны позже при просмотре существующих графов этого источника данных.
Щелчок по источнику данных на боковой панели отображает таблицу всех обработанных графов для этого источника данных.
Просмотр графа в Beagle предоставляет веб-интерфейс, позволяющий аналитикам быстро переключаться между аспектами инцидента.
Интерфейс разделён на две основные части: левая часть содержит различные перспективы графа (Граф, Дерево, Таблица и т.д.), а правая часть позволяет фильтровать узлы и рёбра по типу, искать узлы и разворачивать свойства узла. Также доступны отмена и повтор операций, выполняемых над графом.
Любой элемент графа, над которым есть разделитель, можно свернуть:
Узлы в графе отображают первые 15 символов определённого поля. Например, для узла процесса это будет имя процесса.
Рёбра просто показывают тип ребра.
Одиночный щелчок по узлу или ребру фокусируется на этом элементе и отображает его информацию на панели «Информация об узле» на правой боковой панели.
Двойной щелчок по узлу подтягивает соседние узлы. Соседний узел — это любой узел, соединённый с выбранным узлом ребром. Если соседей нет, изменений в графе не будет.
Долгий одиночный щелчок по узлу скрывает его из графа, а также все рёбра, которые от него зависят.
Щелчок правой кнопкой мыши по узлу открывает контекстное меню, позволяющее запускать мутаторы графа. Мутаторы — это функции, которые принимают состояние графа и возвращают новое состояние.
Два чрезвычайно полезных мутатора:
Откат узла чрезвычайно полезен и аналогичен поиску первопричины инфекции в файлах журналов.
Развёртывание потомков узла позволяет сразу просмотреть всё, что произошло в результате этого узла. Это действие показывает подграф, корнем которого является выбранный узел.
Иногда узел или ребро могут не относиться к текущему инциденту. Вы можете включать и отключать типы рёбер и узлов. Как только тип отключается, узлы или рёбра этого типа удаляются из видимого графа.
Отключение типа узла предотвращает использование этого типа узла в мутаторах или при подтягивании соседей.
Любое действие в графе можно немедленно отменить! С помощью кнопок отмены/повтора вы можете отменить любое выполненное действие. Кнопка сброса возвращает граф к состоянию, в котором он был загружен, избавляя от необходимости обновлять страницу.
По мере изменения текущего состояния графа с помощью описанных выше действий вы также можете просмотреть текущий набор видимых узлов и рёбер в другой перспективе. Вкладки в верхней части экрана графа позволяют преобразовать данные в различные представления:
Каждая из перспектив поддерживает фокусировку на узлах путём щелчка по ним.
Процесс генерации графа может выполняться программно с помощью библиотеки Python. Процесс генерации графа состоит из трёх шагов:
DataSource разбирают и выдают события одно за другим.Transformer принимают эти входные данные и преобразуют их в различные классы узлов, такие как Process.Backend принимают массив узлов, помещают их в структуру графа и отправляют в нужное место.Пакет Python можно установить через pip:
pip install pybeagle
Создание графа требует объединения этих шагов. Это можно сделать автоматически с помощью функции to_graph().
from beagle.datasources import HXTriage
# По умолчанию при использовании to_graph() используется NetworkX и первый трансформер.
G = HXTriage('test.mans').to_graph()
<networkx.classes.multidigraph.MultiDiGraph at 0x12700ee10>
Это также можно сделать явно на каждом шаге. Используя функциональные вызовы, вы можете указать, какой бэкенд использовать, например, для отправки данных в DGraph.
from beagle.datasources import HXTriage
from beagle.backends import DGraph
from beagle.transformers import FireEyeHXTransformer
# Данные будут отправлены в экземпляр DGraph, настроенный в файле конфигурации
backend = HXTriage('test.mans').to_graph(backend=DGraph)
# Можно также указать трансформер
backend = HXTriage('test.mans').to_transformer(transformer=FireEyeHXTransformer).to_graph(backend=DGraph)
При вызове методов to_graph или to_transformer вы можете передавать любые аргументы в эти классы:
from beagle.datasources import HXTriage
from beagle.backends import Graphistry
# Отправить в Graphistry, предварительно анонимизировать данные и вернуть URL
graphistry_url = HXTriage('test.mans').to_graph(backend=Graphistry, anonymize=True, render=False)
Вы также можете вручную вызывать каждый шаг описанного выше процесса, получая доступ к промежуточным результатам.
>>> from beagle.backends import NetworkX
>>> from beagle.datasources import HXTriage
>>> from beagle.transformers import FireEyeHXTransformer
>>> datasource = HXTriage("test.mans")
>>> transformer = FireEyeHXTransformer(datasource=datasource)
>>> nodes = transformer.run()
>>> backend = NetworkX(nodes=nodes)
>>> G = backend.graph()
Если вы хотите вызывать каждый шаг вручную, убедитесь, что экземпляр класса Transformer совместим с выходными данными предоставленного класса DataSource.
Каждый источник данных определяет список трансформеров, с которыми он совместим, и к нему можно получить доступ через атрибут .transformers:
>>> from beagle.datasources import HXTriage
>>> HXTriage.transformers
[beagle.transformers.fireeye_hx_transformer.FireEyeHXTransformer]
По умолчанию рёбра не сжимаются, то есть если узел процесса u записывает в узел файла v 5000 раз, между этими узлами будет 5000 рёбер. Иногда, особенно при попытке визуализировать данные, это может перегрузить аналитика.
Вы можете сжать все 5000 рёбер в одно ребро для данного типа действия (в данном случае «запись»), передав классу бэкенда параметр consolidate_edges=True, например:
SysmonEVTX("data/sysmon/autoruns-sysmon.evtx").to_graph(NetworkX, consolidate_edges=False)
# Граф содержит 826 узлов и 2469 рёбер.
SysmonEVTX("data/sysmon/autoruns-sysmon.evtx").to_graph(NetworkX, consolidate_edges=True)
# Граф содержит 826 узлов и 1396 рёбер
По умолчанию веб-интерфейс сжимает рёбра.
Использование бэкенда NetworkX позволяет сохранить полученный граф как объект JSON для последующего использования. Вы можете использовать статический метод NetworkX.from_json, чтобы загрузить его обратно.
import json
from beagle.datasources import SysmonEVTX
from beagle.backends import NetworkX
# Получить объект nx.MultiDiGraph
graph = SysmonEVTX("malicious.evtx").to_graph()
# Преобразовать объект в JSON
graph_json = NetworkX.graph_to_json(graph)
with open("my_graph.json", "w") as f:
json.dump(graph_json, f)
# Позже:
# G — это тот же объект nx.MultiDiGraph, что был сгенерирован .to_graph()
G = NetworkX.from_json("my_graph.json")