Привет, Хабр! В прошлой статье мы делали обзор на 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% покрытие инфраструктуры указанными тулами)?

Отвечу списком, который раскрою подробнее:

  1. Любой вредонос может бесследно исчезнуть на эндпоинтах до его обнаружения, но не из трафика, который захвачен NTA;

  2. Точное понимание откуда, куда и когда передавался файл;

  3. Модифицировался ли файл при передаче от одного узла к другому;

  4. Обнаружение Lateral Movement (в дальнейшем просто latmov);

  5. Передача файла с машины, которая вошла в 0,00001% без покрытия СЗИ (или вовсе не доменной);

  6. Автоматизация и упрощение рутинных задач Detection Engineering’а (удобно скармливать файл стрелке и большинство полезной информации удобно (почти) раскладывается в JSON’e, отправляется в песочницы и куда только захотите).

TL;DR подробнее:
  1. Как известно, антивирусы не являются серебряной пулей от всех болезней, да и способов обхода их обнаружения известно не мало. Хороший специалист красной команды (этичный хакер) сможет легко обойти антивирус даже для избитого и отлично известного mimikatz’a. А серьезные ребята из АРТ группировок вовсе стараются не оставлять своих следов. При передаче нешифрованным каналом своего инструментария (например smb или любимым psexec’ом) и последующим его запуском с моментальным удалением, вряд ли удастся получить образец файла на целевой системе, однако он осядет на NTA и будет проанализирован strelka. Из этого можно будет написать детект и отслеживать дальнейшее перемещение файла по сети не только с помощью агентов/антивируса и пр, но и на сети. Хочу отметить, что речь идет не о первичном обнаружении, а именно о насыщении инцидента важными подробностями, о последующем респонзе и анализе, что в будущем приведет к своевременному первичному обнаружению.

  2. Агенты на устройствах наверняка расскажут о наличии того или иного файла, максимум - подсветят происхождение файла (вспоминаем о Transfer Zone), но едва ли расскажут, откуда появился файл (если только косвенными признаками при анализе логов с хоста, что требует самого ценного ресурса - времени). В случае же анализа Strelk’ой - у вас будет неоспоримое доказательство о дате, источнике передачи точного файла (ведь Strelka считает хэши). Такой подход существенно сокращает время разбора инцидента, а как мы знаем,  при активном реагировании, скорость анализа является очень критичным показателем - иногда секунды определят, появится ли новый доменный админ или нет.

  3. Некоторые вирусы могут изменять свою структуру с течением времени или иными факторами (разумеется, для избежания обнаружения), но Strelka анализирует все возможные заголовки файлов, в том числе вычисляет imphash и пишет его в лог (imphash - это хэш подключаемых библиотек для исполняемого файла). Кроме imphash для исполняемых файлов записываются: архитектура, для который был написан бинарь, все метаданные исполняемого файла (например версия, цифровая подпись и пр.), ОС, характеристики подключаемых библиотек (их функции) и многие другие заголовки. По таким признакам возможно написать YARA правило (или правило корреляции - ведь логи Strelka отправляются в SIEM), которое будет отслеживать файл, даже если он постоянно изменяется (вы можете справедливо заметить, что в случае продвинутой малвари для избежания обнаружения могут подключаться дополнительные библиотеки для изменения imphash, однако не всегда будут использоваться дополнительные функции новых библиотек). 

  4. Вполне вероятно, что latmov может отслеживаться на логах и самой сети, однако как быть, когда злоумышленники используют легитимные для инфраструктуры инструменты (конечно же, что бы усложнить свое обнаружение защитниками)? Профилирование активности админов может не спасти - ведь с точки зрения логов и сети, активность ничем не отличается от действий администратора. Однако именно тут на помощь приходит Strelka - в случае передачи своих инструментов по сети (а как иначе?), они будут проанализированы. Согласитесь, что администраторы не используют хактулы и малварь при осуществлении ежедневных обязанностей?

  5. Идеальных инфраструктур не существует. Наверняка даже в крупнейших банках мира найдется 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

  1. Правила захвата файлов мы честно решили взять с проекта Security Onion Solutions,  вот ссылка на сами правила

  2. После изменения конфигов, рестартуем сурикату и проверяем запись файлов по указанной директории в конфиге выше. Должно получиться что-то подобное:

    Все эти директории - первые 2 символа в sha-256 хэше, того файла, который был сохранен. (например, если SHA-256 хэш файла начинается с ”00”, то он будет сохранен в директории 00)

  3. Готово, теперь файлы будут выдергиваться в эту директорию.

Перейдем к деплою и настройке 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):

  1. Копируем репозиторий и заходим в него
    git clone https://github.com/target/strelka.git && \

    cd strelka

  2. Удаляем тестовый файл с 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

  3. Билдим образа докера и поднимаем их, а также собираем один из клиентов - 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

  4. Берем любой пример вредоносного ПО (в примере от самой 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 - можно глянуть тут): 

Результаты анализа EICAR в ELK.
Результаты анализа EICAR в ELK.

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

Пару скринов ниже покажут пример анализа internal monologue:

Метаданные
Метаданные
Сработки YARA
Сработки YARA

Однако Strelka вытаскивает еще полезную информацию:

  • Тип файла (из заголовка)

  • URL’ы в файлах

  • Импортируемые функции из библиотек 

Inserting image...
Пример дашбордика в ELK с полезной информацией

Послесловие

Strelka не единственная в своем роде - коллеги по цеху из Канады разрабатывают AssemblyLine - концептуально похожий проект со Strelka.

Авторы текста:
Тыщенко Иван, tg:@nerebros

Дьячков Иван, tg: @Roosevelt_Rus

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