Привет Хабр! В прошлой статье мы делали обзор на opensource NTA – Arkime, здесь мы продолжим развивать NTA для безопасника и поговорим об анализе файлов в сетевом трафике. Текущая статья будет своего рода обзором — инструкцией по развитию системы.
“Из коробки” Arkime может в YARA, но в таком случае анализ файлов будет на мощностях нод захвата со всеми вытекающими последствиями (увеличение потока трафика потребует СУЩЕСТВЕННОГО увеличения мощности ноды). Чтобы переложить нагрузку с “больной головы” на “здоровую” мы решили прикрутить Strelka.

Strelka
Итак, что же такое Strelka? Как заявляет комьюнити — это энтерпрайз решение для статического анализа и поиска файлов по YARA правилами (и не только) в режиме реального времени. Архитектурно представляет клиент-серверное приложение (понятное дело, требует установки агентов). Агенты написаны на Go Lang, что предоставляет возможность кроссплатформенной установки. Наглядный usecase — поиск вредоносного файла, который обошел антивирусы, но при этом был обнаружен командой кибербеза. На файл написали YARA сигнатуру и запустили поиск по всем агентам в инфраструктуре. Подобный кейс рассмотрим чуть дальше в статье.
К сожалению, о Strelka мало кто знает и использует в СНГ. Разумеется, в этом нет ничего удивительного — как правило, такие функции возлагают на вышеупомянутые коммерческие решения (антивирусы, EDR и пр.), используют самописное, либо вовсе не задумываются о таких задачах.
Изначально Strelka задумывалась как решение для поиска и анализа файлов по запросу, в том числе и анализ файлов на сетевом потоке IDS/IPS сенсорах, полученных из трафика. Именно такой функционал нам и нужен в рамках развития нашего NTA – Arkime.
Из однозначно приятных дополнительных возможностей — отправка файлов в песок для динамического анализа (из коробки реализована только интеграция с Cuckoo sandbox, но есть возможность прикрутить любой другой, если вы умеете в Python). Используя такую интеграцию можно получить песок для всех передаваемых по сети файлов.
Архитектура Strelka достаточно гибкая и позволяет развернуть как маленькую инсталяцию для тестов, так и распределенную инсталяцию для кровавого энтерпрайза (реализация любого взаимодействия серверов и агентов).
В чем профит?
Возникает вполне логичный вопрос — зачем вовсе анализировать файлы на сетевом потоке, когда есть EDR/антивирус и прочие СЗИ с аналогичным функционалом (даже если 146% покрытие инфраструктуры указанными тулами)?
Отвечу списком, который раскрою подробнее:
-
Любой вредонос может бесследно исчезнуть на эндпоинтах до его обнаружения, но не из трафика, который захвачен NTA;
-
Точное понимание откуда, куда и когда передавался файл;
-
Модифицировался ли файл при передаче от одного узла к другому;
-
Обнаружение Lateral Movement (в дальнейшем просто latmov);
-
Передача файла с машины, которая вошла в 0,00001% без покрытия СЗИ (или вовсе не доменной);
-
Автоматизация и упрощение рутинных задач Detection Engineering’а (удобно скармливать файл стрелке и большинство полезной информации удобно (почти) раскладывается в JSON’e, отправляется в песочницы и куда только захотите).
TL;DR подробнее:
-
Как известно, антивирусы не являются серебряной пулей от всех болезней, да и способов обхода их обнаружения известно не мало. Хороший специалист красной команды (этичный хакер) сможет легко обойти антивирус даже для избитого и отлично известного mimikatz’a. А серьезные ребята из АРТ группировок вовсе стараются не оставлять своих следов. При передаче нешифрованным каналом своего инструментария (например smb или любимым psexec’ом) и последующим его запуском с моментальным удалением, вряд ли удастся получить образец файла на целевой системе, однако он осядет на NTA и будет проанализирован strelka. Из этого можно будет написать детект и отслеживать дальнейшее перемещение файла по сети не только с помощью агентов/антивируса и пр, но и на сети. Хочу отметить, что речь идет не о первичном обнаружении, а именно о насыщении инцидента важными подробностями, о последующем респонзе и анализе, что в будущем приведет к своевременному первичному обнаружению.
-
Агенты на устройствах наверняка расскажут о наличии того или иного файла, максимум — подсветят происхождение файла (вспоминаем о Transfer Zone), но едва ли расскажут, откуда появился файл (если только косвенными признаками при анализе логов с хоста, что требует самого ценного ресурса — времени). В случае же анализа Strelk’ой — у вас будет неоспоримое доказательство о дате, источнике передачи точного файла (ведь Strelka считает хэши). Такой подход существенно сокращает время разбора инцидента, а как мы знаем, при активном реагировании, скорость анализа является очень критичным показателем — иногда секунды определят, появится ли новый доменный админ или нет.
-
Некоторые вирусы могут изменять свою структуру с течением времени или иными факторами (разумеется, для избежания обнаружения), но Strelka анализирует все возможные заголовки файлов, в том числе вычисляет imphash и пишет его в лог (imphash — это хэш подключаемых библиотек для исполняемого файла). Кроме imphash для исполняемых файлов записываются: архитектура, для который был написан бинарь, все метаданные исполняемого файла (например версия, цифровая подпись и пр.), ОС, характеристики подключаемых библиотек (их функции) и многие другие заголовки. По таким признакам возможно написать YARA правило (или правило корреляции — ведь логи Strelka отправляются в SIEM), которое будет отслеживать файл, даже если он постоянно изменяется (вы можете справедливо заметить, что в случае продвинутой малвари для избежания обнаружения могут подключаться дополнительные библиотеки для изменения imphash, однако не всегда будут использоваться дополнительные функции новых библиотек).
-
Вполне вероятно, что latmov может отслеживаться на логах и самой сети, однако как быть, когда злоумышленники используют легитимные для инфраструктуры инструменты (конечно же, что бы усложнить свое обнаружение защитниками)? Профилирование активности админов может не спасти — ведь с точки зрения логов и сети, активность ничем не отличается от действий администратора. Однако именно тут на помощь приходит Strelka — в случае передачи своих инструментов по сети (а как иначе?), они будут проанализированы. Согласитесь, что администраторы не используют хактулы и малварь при осуществлении ежедневных обязанностей?
-
Идеальных инфраструктур не существует. Наверняка даже в крупнейших банках мира найдется 1 машина, на которой нет СЗИ или вне домена, или вовсе является нелегитимно подключенным устройством в сеть (например raspberry pi, включенная в RJ-45 розетку сети ip-телефонии). В таком случае СЗИ смогут обнаружить (ЕСЛИ смогут) только факт появления вредоноса на атакуемой машине, но Strelka точно расскажет, откуда прилетел такой файл. В более зрелых, с точки зрения ИБ, инфраструктурах может быть обнаружен факт подключения в сеть неизвестного устройства, что послужит хорошим поводом для начала расследования — при таком раскладе развития событий, Strelka упростит анализ активности нелегитимного устройства.
Резюмируя, все эти пункты можно свести к следующему профиту:
-
Сокращение времени расследования инцидентов;
-
Увеличение видимости инфраструктуры для безопасника;
-
Насыщение контекста инцидентов;
-
Дополнительные возможности детекта вредоносной активности в сети.
Плюсов не мало, однако есть очень важный нюанс, в случае анализа файлов на трафике, они должны быть переданы НЕшифрованным каналом (например, если файл передавался по RDP или по кастомному шифрованному протоколу — разумеется, он не будет проанализирован). В копилку минусов можно так же отнести отсутствие в логах Strelka айпишников, откуда файл был выдернут, НО! с помощью logstash обогатить такие данные.
Предварительная настройка ноды захвата
!!!Дисклеймер!!!
Мы не претендуем (хотя стремимся к ней) на идеальную конфигурацию Suricata, Zeek, Strelka и тд, а так же на полноту покрытия всех потребностей безопасника. Мы точно знаем, что у нас есть недостатки в конфигах, но мы только начали свой путь и, со временем, мы станем лучше, в том числе, благодаря вашим советам и рекомендациям. “Совет начинающим: начните” (с) Великие цитаты Великих людей =)
Для того, чтобы анализировать файлы, их сначала надо откуда-то получить. В прошлой статье мы упоминали, что Arkime сам по себе не выдергивает файлы из трафика (но индексирует их имена). Кроме самого Arkime, на ноде захвата установлена Suricata. Именно с ее помощью мы хотели получать файлы. Однако, столкнулись с тем, что Suricata не особо адекватно выдирает файлы из трафика из-за особенностей пересбора сессии. Более эффективным вариантом будет Zeek (ранее Bro) с настройки на экстракт файлов.
Для этого стоит начать с установки самого Zeek, но мы надеемся, что с эти проблем у вас не будет =). После стандартной настройки (выбор портов для прослушки и т.д.), необходимо написать скрипт на языке самого Zeek (смесь Lua). Такой скрипт есть «из коробки», но он будет собирать все файлы подряд и изначально выключен.
Сам Zeek устроен достаточно хитро и подразумевает внутри себя целую программируемую платформу, которая может делать все что вы захотите, при наличии прямых рук. Для включения скрипта нам нужно “загрузить” его в основной скрипт запуска Zeek. В случае использования standalone инсталяции, достаточно внести директиву “@load <имя модуля>” в файл “префикс_корня_zeek/share/zeek/site/local.zeek”.
С точки зрения загрузчика — пути к модулями начинаются из папки share и share/policy, и идеологически — каждый модуль находится в своей папке. Дефолтный крипт выгрузки всех файлов является частью стандартного модуля FileAnalysis, и находится по пути “frameworks/files/extract-all-files”. Как уже было сказано выше, скрипт будет выдирать все подряд, чего мы хотим избежать. Для этого мы своровали вдохновились более точечной вариацией от Security Onion Solutions, где предварительно создан словарь с mime типами файлов и их расширениями. Так как данный скрипт генерируется при установке самого SOS, мы переопределим свои типы и используем их.
Для того чтобы скрипт стал “модулем”, который мы будем использовать, переместим его в папку (для сохранения истоков — share/policy/securityonion/file-extract/) и создадим файл “__load__.zeek” (по аналогии __init__.py в Python модулях), в которой добавим директиву “@load ./extract”. Соответственно, сам скрипт будет называть extract.zeek и в него мы добавим следующее:
redef FileExtract::prefix = "<путь к папке с вырезанными файлами>"; # Set a limit to the file size redef FileExtract::default_limit = 9000000; # максимальный размер файл для вырезки # These are the mimetypes we want to rip off the networks export { global _mime_whitelist: table[string] of string = { [“application/x-dosexec”] = “exe”, # Здесь можно описывать другие типы } &default = “”; # Start grabbing the file from the network if it matches the mimetype event file_sniff(f: fa_file, meta: fa_metadata) &priority=10 { local ext = ""; if( meta?$mime_type ) { if ( meta$mime_type !in _mime_whitelist ) { return; } ext = _mime_whitelist[meta$mime_type]; local fname = fmt("%s-%s.%s", f$source, f$id, ext); Files::add_analyzer(f, Files::ANALYZER_EXTRACT, [$extract_filename=fname]); } } # Wait for file_state_remove before you do anything. This is when it is actually done. event file_state_remove(f: fa_file) { if ( !f$info?$extracted || FileExtract::prefix == "" ) { return; } # Check if any of the following conditions exist: # - missing MD5 # - total_bytes exists (some protocols aren't populating this field) but is 0 # - missing bytes # - timed out if ( !f$info?$md5 || (f?$total_bytes && f$total_bytes == 0) || f$missing_bytes > 0 || f$info$timedout) { # Delete the file if it didn't pass our requirements check. local nuke = fmt("rm %s/%s", FileExtract::prefix, f$info$extracted); when [nuke] ( local nukeit = Exec::run([$cmd=nuke]) ) { } return; } local orig = f$info$extracted; local split_orig = split_string(f$info$extracted, /\./); local extension = split_orig[|split_orig|-1]; local dest = fmt("%scomplete/%s-%s-%s.%s", FileExtract::prefix, f$source, f$id, f$info$md5, extension); # Copy it to the $prefix/complete folder then delete it. I got some weird results with moving when it came to watchdog in python. local cmd = fmt("cp %s/%s %s && rm %s/%s", FileExtract::prefix, orig, dest, FileExtract::prefix, orig); when [cmd] ( local result = Exec::run([$cmd=cmd]) ) { } f$info$extracted = dest; }
Статья не про Zeek, но в вариации SOS также есть проверка на корректность выгрузки в обработке file_state_remove, где файл будет удален, если во время сбора не были выполнены некоторые требования.
Путь курильщика:
Настройка suricata.yaml:
Чтобы научить сурка сохранять файлы, необходимо добавить следующие строки (из документации самого сурка 1 и 2) в suricata.yaml (оформить код-блоком) :
- eve-log:
enabled: yes
filetype: regular
filename: eve.json
…
types:
…
- files:
force-magic: yes
…
- file-store:
version: 2
enabled: yes
dir: /ваша/директория/
stream-depth: 0
…
-
Правила захвата файлов мы честно решили взять с проекта Security Onion Solutions, вот ссылка на сами правила
-
После изменения конфигов, рестартуем сурикату и проверяем запись файлов по указанной директории в конфиге выше. Должно получиться что-то подобное:

Все эти директории — первые 2 символа в sha-256 хэше, того файла, который был сохранен. (например, если SHA-256 хэш файла начинается с ”00”, то он будет сохранен в директории 00)
-
Готово, теперь файлы будут выдергиваться в эту директорию.
Перейдем к деплою и настройке Strelka.
Деплоймент Strelka
В рамках этой статьи мы выбрали самый простой варинат деплоя — инсталяция всех компонентов в одном экземпляре с помощью docker compose (1 сервер — 1 агент). В большой инсталяции количество сервисов увеличивается по необходимости, а для роутинга и балансировки gRPC запросов используется Envoy. Проще говоря — больше нагрузка, больше сервисов.
Разберем, что в космической собаке зарыто:
-
Strelka-frontend принимает входящие запросы от клиентов по gRPC.
-
Strelka-backend обрабатывает входящие файлы.
-
Strelka-manager смотрит в Redis.
-
Coordinator – Redis сервер, координирующий задачи на анализ и данные между frontend и backend.
-
Gatekeeper – Redis сервер, реализующий временный кэш из событий.
-
Mmrpc — опциональный сервис на базе проекта MaliciousMacroBot, и включающий сканер ScanMmbot
Перейдем к самой установке (далее мы просто копируем из официального гита Strelka):
-
Копируем репозиторий и заходим в него
git clone https://github.com/target/strelka.git && \cd strelka -
Удаляем тестовый файл с yara правилами и качаем правила из Yara-Rules. Стоит отметить, что в Yara-Rules идет в комплекте файл index.yar, который включает в себя все остальные. Его же мы инклюдим в файл configs/python/backend/yara/rules.yara. Вы можете использовать другие правила или использовать свои собственные
rm configs/python/backend/yara/rules.yara && \git clone https://github.com/Yara-Rules/rules.git configs/python/backend/yara/rules/ && \echo 'include "./rules/index.yar"' > configs/python/backend/yara/rules.yara -
Билдим образа докера и поднимаем их, а также собираем один из клиентов — strelka-oneshot.
docker-compose -f build/docker-compose.yaml build && \docker-compose -f build/docker-compose.yaml up -d && \go build github.com/target/strelka/src/go/cmd/strelka-oneshot -
Берем любой пример вредоносного ПО (в примере от самой Strelka решили выбрать Emotet, находящийся в запароленном архиве) и скармливаем его нашей собаке:
./strelka-oneshot -f samples/Win32.Emotet.zip -l - | jq
Вывод будет представлять собой 2 JSON документа, которые с помощью jq будут адекватно отображены. Так как мы скармливаем архив, Strelka автоматом обрабатывает и вложенные файлы.
Как же именно strelka понимает, что за файл перед ней? С помощью пачки yara правил из файлика taste.yara, а с помощью файла конфигурации backend.yaml, будут выбраны сканеры, которые и проанализируют файлы. Все файлы конфигурации всех сервисов нашей собаки лежат в папке configs/<язык сервиса(go или python)>, как и примеры конфигураций для клиентов.
Интеграция Zeek <> Strelka
Итак, вернемся к нашему кейсу — обработка файлов на потоке. Нам нужен клиент strelka-filestream, который будет смотреть указанные шаблоны наименований файлов и отправлять их как задачи на анализ. Давайте также соберем filestream:
go build github.com/target/strelka/src/go/cmd/strelka-filestream
Обработанные файлы он будет перекладывать в другую папку, чтобы необработанные и обработанные не пересекались:
conn: server: '<адрес frontend>:57314' cert: 'ssl при наличии' timeout: dial: 5s file: 1m throughput: concurrency: 8 chunk: 32768 delay: 0s files: patterns: - '<папка с файлами от Zeek>/*' processed: '<любая директория, где будут храниться обработанные файлы>' delete: false ## Удалить ли файлы, после их отпраки на анализ gatekeeper: true response: report: 5s delta: 5s staging: '/path/to/your/staging/directory/' ## Директория, в которую файлы перемещаются ПЕРЕД отправкой
Это настройки, которые мы решили выбрать для себя, но вы всегда можете обратиться к документации, и настроить все под себя. Описание всех конфигураций для всех сервисов — здесь, но документация достаточно скромная (ну, а что мы хотели от opensource).
Также напишем простенький systemd юнит для “правильного” (по мнению бОльшего представительства линуксойдов) запуска strelka-filestream:
[Unit] Description=Strelka Filestream Binary After=network.target [Service] Type=simple Restart=always RestartSec=5 ExecStart=/usr/bin/strelka-filestream-linux -c /etc/strelka/filestream.yaml [Install] WantedBy=multi-user.target
Вы можете более тонко настроить деплой клиента — сделать отдельного пользователя, настроить права на все используемые нами папки, или даже написать SeLinux политику (почему бы и да?).
Настройка доставки логов для анализа
Самое НЕинтересное — доставка логов в ELK, именно на этом этапе мы потратили больше всего времени. Схема JSON документов по результатам анализа файлов нам показалась невероятно монструозной, поэтому выделили самое интересное и основное ниже (документация на схему JSON отсутствует на момент выхода статьи):
{ “file”: … “scan”: { “<название сканера или краткое определение>”: { <пачка объектов (с вложенными объектами), с информации от сканера> } }}
И выглядит все оно конечно просто и понятно, но как только вы сами закинете тестовый Emotet на анализ, вы увидите “немного” больше, чем показывают в примере. Тут по плану должен был быть пример лога, но в нем более 9к строк, поэтому прикладываем только отрывок под скрытый текст.
Часть лога, не смотрите — страшно
«pe»: {
«address_of_entry_point»: 1075979,
«base_of_code»: 4096,
«base_of_data»: 1671168,
«checksum»: 8268887,
«compile_time»: «2023-01-20T18:07:04»,
«debug»: {
«age»: 1,
«guid»: «2d00683a-1f90-0e48-8dc7b915b650eec3»,
«pdb»: «D:\a\1\s\exe\Win32\Public_Release\Sysmon.pdb»,
«type»: «rsds»
},
«dll_characteristics»: [
«DYNAMIC_BASE»,
«NX_COMPAT»,
«TERMINAL_SERVER_AWARE»
],
«elapsed»: 1.431875,
«file_alignment»: 512,
«file_info»: {
«company_name»: «Sysinternals — www.sysinternals.com«,
«file_description»: «System activity monitor»,
«file_version»: «14.14»,
«fixed»: {
«operating_systems»: [
«WINDOWS32»
],
«type»: {
«primary»: «UNKNOWN»
}
},
«internal_name»: «System Monitor»,
«legal_copyright»: «By Mark Russinovich and Thomas Garnier\nCopyright (C) 2014-2023 Microsoft Corporation\nUsing libxml2. libxml2 is Copyright (C) 1998-2012 Daniel Veillard. All Rights Reserved.»,
«product_name»: «Sysinternals Sysmon»,
«product_version»: «14.14»,
«var»: {
«character_set»: «Unicode»,
«language»: «U.S. English»
}
},
«flags»: [
«no_certs_found»
],
«header»: {
«machine»: {
«id»: 332,
«type»: «I386»
},
«magic»: {
«dos»: «DOS»,
«image»: «32_BIT»
},
«subsystem»: «WINDOWS_CUI»
},
«image_base»: 4194304,
«image_characteristics»: [
«EXECUTABLE_IMAGE»,
«32BIT_MACHINE»
],
«image_version»: 0,
«imphash»: «22c706ca771a1849826506040b11d50f»,
«linker_version»: 14.34,
«major_image_version»: 0,
«major_linker_version»: 14,
«major_operating_system_version»: 6,
«major_subsystem_version»: 6,
«minor_image_version»: 0,
«minor_linker_version»: 34,
«minor_operating_system_version»: 0,
«minor_subsystem_version»: 0,
«operating_system_version»: 6,
«resources»: [
{
«id»: 1001,
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «3e725ceddba1b9460f6304986e6248da»,
«sha1»: «8710b02483beac27184dd236209f7d1df864ffe6»,
«sha256»: «d92b848707513894733fe2da0faf7ba7dcfbbb98380d06e07c87521e7fab6bf0»
},
{
«id»: 1002,
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «01124a558ec6d65f6471456da07ab4ea»,
«sha1»: «743e1c0d0495d334c77132640352208f806aeb54»,
«sha256»: «9681d860e84375b95b3d59006dae41b007bca3824bfe10e0c313b72f68ac178a»
},
{
«id»: 1,
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «12a95179b2738a3f37060eacad6bd6a3»,
«sha1»: «1197df76d0a31be7a369b13499f1e73c6b6791d0»,
«sha256»: «3d63feefaf94dc719aa83afc9b25dc8ca317a686cdb617e39f4c1548b060a8ed»
},
{
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «932524ab57ae83176d5596fff967aa52»,
«name»: «SYSMONSCHEMA»,
«sha1»: «691dd0236bc963b1b7528accdba56fee26fce10d»,
«sha256»: «0387426eeb7ea7705c7524e2d6425a7c6fda9923c25650309ae3a6440a0e9971»
},
{
«id»: 1,
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «bfc1566bfd06c8135ab5c3a2e321ebe7»,
«sha1»: «66bd09bd18c6953d6fcea960431dfb6ddd7f9416»,
«sha256»: «db58c2c74246fa1e1c6c504373332303a511be9072ee5b31796c2a837a922f17»,
«type»: «MESSAGETABLE»
},
{
«id»: 1,
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «d901d37a441a56585e2878f8f31fd958»,
«sha1»: «0c60e3a7cc4a9c5726767611fd774c5826690438»,
«sha256»: «695d4d08304fd3377908fb02cb58063052223e391b9ed70da067a9bb3725c53e»,
«type»: «VERSION»
},
{
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «97563aa40292469b3e117adfc66dfcbe»,
«name»: «SYSMONMAN»,
«sha1»: «8c4b4d8d95edc34e21b1723f3badcfaf51ea6dd5»,
«sha256»: «71318e89313c58d15da819be6f89fdc975228cbf82626bfa2c78aa2f28d04ad8»,
«type»: «HTML»
},
{
«id»: 1,
«language»: {
«primary»: «ENGLISH»,
«sub»: «ENGLISH_US»
},
«md5»: «d41d8cd98f00b204e9800998ecf8427e»,
«sha1»: «da39a3ee5e6b4b0d3255bfef95601890afd80709»,
«sha256»: «e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855»,
«type»: «MANIFEST»
}
],
«rich»: {
«clear_data»: {
«data»: «RGFuUwAAAAAAAAAAAAAAAEt4AwETAAAAS3gFAcUAAABPfP0ABAAAAE98BQFWAAAAT3wEARMAAABPfAMBGQAAAEt4BAEZAAAAuHUDAQEAAAC7dQQBCgAAAEt4AQEjAAAAAAABAFIBAADBfAkBPQAAAMF8/wABAAAAAACXAAIAAADBfAIBAQAAAA==»,
«md5»: «fa160a389ccba4f1f5e7ea61c15d319a»
},
«info»: [
{
«count»: 19,
«toolid»: 259,
«version»: 30795
},
{
«count»: 197,
«toolid»: 261,
«version»: 30795
},
{
«count»: 4,
«toolid»: 253,
«version»: 31823
},
{
«count»: 86,
«toolid»: 261,
«version»: 31823
},
{
«count»: 19,
«toolid»: 260,
«version»: 31823
},
{
«count»: 25,
«toolid»: 259,
«version»: 31823
},
{
«count»: 25,
«toolid»: 260,
«version»: 30795
},
{
«count»: 1,
«toolid»: 259,
«version»: 30136
},
{
«count»: 10,
«toolid»: 260,
«version»: 30139
},
{
«count»: 35,
«toolid»: 257,
«version»: 30795
},
{
«count»: 338,
«toolid»: 1,
«version»: 0
},
{
«count»: 61,
«toolid»: 265,
«version»: 31937
},
{
«count»: 1,
«toolid»: 255,
«version»: 31937
},
{
«count»: 2,
«toolid»: 151,
«version»: 0
},
{
«count»: 1,
«toolid»: 258,
«version»: 31937
}
],
«key»: «6220d5e7»,
«raw_data»: {
«data»: «JkG7tGIg1ediINXnYiDV5ylY1uZxINXnKVjQ5qcg1ectXCjnZiDV5y1c0OY0INXnLVzR5nEg1ectXNbmeyDV5ylY0eZ7INXn2lXW5mMg1efZVdHmaCDV5ylY1OZBINXnYiDU5zAh1eejXNzmXyDV56NcKudjINXnYiBC52Ag1eejXNfmYyDV5w==»,
«md5»: «99df8167e636a4e5d03f3a305f56b445»
}
},
«section_alignment»: 4096,
«sections»: [
{
«address»: {
«physical»: 1666038,
«virtual»: 4096
},
«characteristics»: [
«CNT_CODE»,
«MEM_EXECUTE»,
«MEM_READ»
],
«entropy»: 6.636632502553922,
«md5»: «55eac3bed86e853dd7b97ecae392a49c»,
«name»: «.text»,
«sha1»: «d86802270020bf19260c1a0f4c4e46551a9f01d6»,
«sha256»: «7b80a0764abba960a81e444dcc6f5cb3ec8c38c0c4aeb89e518ef40ee0d129d1»,
«size»: 1666048
},
{
«address»: {
«physical»: 786576,
«virtual»: 1671168
},
«characteristics»: [
«CNT_INITIALIZED_DATA»,
«MEM_READ»
],
«entropy»: 4.3805809880051365,
«md5»: «ba57f1bdd64e68192ac99511c004430d»,
«name»: «.rdata»,
«sha1»: «ae67fd775a29fe2e812c04d7fae00fed6cd3f10f»,
«sha256»: «95d49c9c84ddb5bd3fb746000e2be173d51af0a4971d0d2f82a728d769a74778»,
«size»: 786944
},
{
«address»: {
«physical»: 29224,
«virtual»: 2461696
},
«characteristics»: [
«CNT_INITIALIZED_DATA»,
«MEM_READ»,
«MEM_WRITE»
],
«entropy»: 4.474025218651877,
«md5»: «31a647892600452887f8681d5007a2e4»,
«name»: «.data»,
«sha1»: «7b84cf7ccb58aca03a780b60ee731ef458f311d7»,
«sha256»: «6331c1d1e5d08db286a879035ffa9f08f999bf87358938ef184ccaf25fe0b626»,
«size»: 14848
},
{
«address»: {
«physical»: 5686360,
«virtual»: 2494464
},
«characteristics»: [
«CNT_INITIALIZED_DATA»,
«MEM_READ»
],
«entropy»: 1.699918955277781,
«md5»: «bf1b231fd7cebcaf9ce86b18fdcba822»,
«name»: «.rsrc»,
«sha1»: «1e941fdd57610dd433314447b1076f84bad98594»,
«sha256»: «fe21359b2a4ce3fde264344efee4f475b752d192ea1039aad72edf19e764f073»,
«size»: 5686784
},
{
«address»: {
«physical»: 60920,
«virtual»: 8183808
},
«characteristics»: [
«CNT_INITIALIZED_DATA»,
«MEM_DISCARDABLE»,
«MEM_READ»
],
«entropy»: 0,
«md5»: «d41d8cd98f00b204e9800998ecf8427e»,
«name»: «.reloc»,
«sha1»: «da39a3ee5e6b4b0d3255bfef95601890afd80709»,
«sha256»: «e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855»,
«size»: 60928
}
],
«size_of_code»: 1666048,
«size_of_headers»: 1024,
«size_of_heap_commit»: 4096,
«size_of_heap_reserve»: 1048576,
«size_of_image»: 8245248,
«size_of_initialized_data»: 6564352,
«size_of_stack_commit»: 4096,
«size_of_stack_reserve»: 1048576,
«size_of_uninitialized_data»: 0,
«subsystem_version»: 6,
«summary»: {
«resource_md5»: [
«01124a558ec6d65f6471456da07ab4ea»,
«97563aa40292469b3e117adfc66dfcbe»,
«12a95179b2738a3f37060eacad6bd6a3»,
«3e725ceddba1b9460f6304986e6248da»,
«d41d8cd98f00b204e9800998ecf8427e»,
«932524ab57ae83176d5596fff967aa52»,
«d901d37a441a56585e2878f8f31fd958»,
«bfc1566bfd06c8135ab5c3a2e321ebe7»
],
«resource_sha1»: [
«1197df76d0a31be7a369b13499f1e73c6b6791d0»,
«0c60e3a7cc4a9c5726767611fd774c5826690438»,
«691dd0236bc963b1b7528accdba56fee26fce10d»,
«8c4b4d8d95edc34e21b1723f3badcfaf51ea6dd5»,
«743e1c0d0495d334c77132640352208f806aeb54»,
«66bd09bd18c6953d6fcea960431dfb6ddd7f9416»,
«da39a3ee5e6b4b0d3255bfef95601890afd80709»,
«8710b02483beac27184dd236209f7d1df864ffe6»
],
«resource_sha256»: [
«71318e89313c58d15da819be6f89fdc975228cbf82626bfa2c78aa2f28d04ad8»,
«d92b848707513894733fe2da0faf7ba7dcfbbb98380d06e07c87521e7fab6bf0»,
«e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855»,
«3d63feefaf94dc719aa83afc9b25dc8ca317a686cdb617e39f4c1548b060a8ed»,
«db58c2c74246fa1e1c6c504373332303a511be9072ee5b31796c2a837a922f17»,
«0387426eeb7ea7705c7524e2d6425a7c6fda9923c25650309ae3a6440a0e9971»,
«695d4d08304fd3377908fb02cb58063052223e391b9ed70da067a9bb3725c53e»,
«9681d860e84375b95b3d59006dae41b007bca3824bfe10e0c313b72f68ac178a»
],
«section_md5»: [
«55eac3bed86e853dd7b97ecae392a49c»,
«d41d8cd98f00b204e9800998ecf8427e»,
«31a647892600452887f8681d5007a2e4»,
«bf1b231fd7cebcaf9ce86b18fdcba822»,
«ba57f1bdd64e68192ac99511c004430d»
],
«section_sha1»: [
«d86802270020bf19260c1a0f4c4e46551a9f01d6»,
«da39a3ee5e6b4b0d3255bfef95601890afd80709»,
«1e941fdd57610dd433314447b1076f84bad98594»,
«ae67fd775a29fe2e812c04d7fae00fed6cd3f10f»,
«7b84cf7ccb58aca03a780b60ee731ef458f311d7»
],
«section_sha256»: [
«6331c1d1e5d08db286a879035ffa9f08f999bf87358938ef184ccaf25fe0b626»,
«e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855»,
«fe21359b2a4ce3fde264344efee4f475b752d192ea1039aad72edf19e764f073»,
«95d49c9c84ddb5bd3fb746000e2be173d51af0a4971d0d2f82a728d769a74778»,
«7b80a0764abba960a81e444dcc6f5cb3ec8c38c0c4aeb89e518ef40ee0d129d1»
]
}
Самое страшное здесь — секции с импортируемыми функциями из PE заголовков, полная meta информация по yara правилам и массив из информации об энтропии каждой секции исполняемого файла (не пугайтесь, если вы ничего не поняли — мы тоже ничего не поняли).
Нам очень хотелось слать всю информацию о сработках yara правил в Elasticsearch и в дальнейшем использовать в визуализациях, или даже написать правила в Elastic Security.
Но к нашему сожалению — meta данные по yara правилам — массив из несвязанных объектов, поэтому пришлось воспользоваться Vector и написать парсер на VRL, так как писать все это на Painless Script — полное безумие (попробуйте сами).
Анализ
Результатом обработки файлов является лог-файл на ноде захвата и для его последующего анализа требуется его куда-то забирать и визуализировать. Для этого мы решили использовать filebeat + ELK stack (теоретически, можно складывать в ELK Arkime, к которому прикручена Kibana/opensearch, но мы складываем в отдельную инсталяцию). Пример лога в ELK для тестового EICAR файла (мы используем yara правила от Elastic — можно глянуть тут):



Как можно заметить, самые интересные, с точки зрения безопасности, поля — это сработка YARA, хэши, название файла. Внутри тестового файла отсутствуют какие-либо еще интересные данные.
Пару скринов ниже покажут пример анализа internal monologue:
Однако Strelka вытаскивает еще полезную информацию:
-
Тип файла (из заголовка)
-
URL’ы в файлах
-
Импортируемые функции из библиотек
Послесловие
Strelka не единственная в своем роде — коллеги по цеху из Канады разрабатывают AssemblyLine — концептуально похожий проект со Strelka.
Авторы текста:
Тыщенко Иван, tg:@nerebros
Дьячков Иван, tg: @Roosevelt_Rus
ссылка на оригинал статьи https://habr.com/ru/articles/723748/
Добавить комментарий