Вредоносное ПО уже долгое время является одной из основных угроз в области информационной безопасности. Подходы к анализу и защите от такого рода атак бывают разные. В общем случае разделяют два подхода: статический и динамический анализ.
Задача статического анализа — поиск шаблонов вредоносного содержимого в файле или памяти процесса. Это могут быть строки, фрагменты закодированных или сжатых данных, последовательности скомпилированного кода. Может производиться поиск не только отдельных шаблонов, но и их комбинаций с дополнительными условиями (например, с привязкой к месту нахождения сигнатуры, проверкой относительного расстояния в местоположении друг от друга).
Динамический анализ — это анализ поведения программы. Стоит отметить, что программа может быть запущена в так называемом эмулируемом режиме. Предполагается безопасное интерпретирование действий без нанесения повреждений операционной системе. Другой способ — запуск программы в виртуальной среде (песочнице). В таком случае будет честное выполнение действий на системе с последующей фиксацией вызовов. Степень подробности логирования — это своего рода баланс между глубиной наблюдения и производительностью анализирующей системы. На выходе получается журнал действий программы в операционной системе (трасса поведения), который поддается дальнейшему анализу.
Динамический или поведенческий анализ дает ключевое преимущество — независимо от попыток запутывания программного кода и стремлений скрыть намерения злоумышленника от вирусного аналитика вредоносное воздействие будет зафиксировано. Сведение задачи обнаружения ВПО к анализу действий позволяет выдвинуть гипотезу об устойчивости продвинутого алгоритма обнаружения вредоноса. А воспроизводимость поведения, благодаря одному и тому же изначальному состоянию среды для анализа (слепка состояния виртуального сервера), упрощает решение задачи классификации легитимного и вредоносного поведения.
Часто подходы в поведенческом анализе основаны на наборах правил. Экспертный анализ переносится в сигнатуры, на основе которых инструмент детекта вредоносного ПО и файлов делает выводы. Однако в таком случае может возникнуть проблема: могут учитываться лишь те атаки, которые строго соответствуют написанным правилам, а атаки, которые не выполняют эти условия, но все еще являются вредоносными, можно пропустить. Та же проблема возникает в случае изменений одного и того же вредоносного ПО. Решить это можно либо с помощью более мягких критериев срабатывания, то есть можно написать более общее правило, либо с помощью большого количества правил под каждый вредонос. В первом сценарии мы рискуем получить много ложных срабатываний, а второй требует серьезных затрат по времени, что может привести к запаздыванию необходимых обновлений.
Появляется потребность в распространении уже имеющихся знаний на другие похожие случаи. То есть те, которые до этого мы не встречали и не обрабатывали правилами, но на основе схожести некоторых признаков можем сделать вывод, что активность может быть вредоносной. Здесь и приходят на помощь алгоритмы машинного обучения.
ML-модели при корректном обучении имеют обобщающую способность. Это значит, что обученная модель не просто выучила все примеры, на которых обучалась, а способна принимать решения для новых примеров на основе закономерностей из обучающей выборки.
Однако для того чтобы обобщающая способность работала, необходимо учитывать два основных фактора на этапе обучения:
Набор признаков должен быть как можно более полным (чтобы модель могла видеть как можно больше закономерностей, соответственно, лучше распространяла свои знания на новые примеры), но не избыточным (чтобы не хранить и не обрабатывать признаки, которые не несут в себе полезную информацию для модели).
Набор данных должен быть репрезентативным, сбалансированным и регулярно обновляемым.
Так как у нас была возможность собрать необходимое количество данных и была гипотеза, что машинное обучение может расширить существующее решение, мы решили заняться этим исследованием: сформировать набор признаков, обучить на них модель и добиться точности, позволяющей доверять выводам модели о вредоносности файлов.
Как экспертное знание переносится в модели машинного обучения
В контексте анализа вредоносного ПО исходные данные — это сами файлы, а промежуточные данные — это созданные ими вспомогательные процессы. Процессы, в свою очередь, производят системные вызовы. Последовательности таких вызовов и есть данные, которые нам необходимо преобразовать в набор признаков.
Составление датасета началось на экспертной стороне. Были выбраны признаки, которые, по мнению экспертов, должны быть значимыми с точки зрения обнаружения ВПО. Все признаки можно было свести к виду n-грамм по системным вызовам. Далее с помощью модели оценили, какие признаки вносят наибольший вклад в обнаружение, отбросили лишнее и получили итоговую версию датасета.
Исходные данные:
{"count":1,"PID":"764","Method":"NtQuerySystemInformation","unixtime":"1639557419.628073","TID":"788","plugin":"syscall","PPID":"416","Others":"REST: ,Module=\"nt\",vCPU=1,CR3=0x174DB000,Syscall=51,NArgs=4,SystemInformationClass=0x53,SystemInformation=0x23BAD0,SystemInformationLength=0x10,ReturnLength=0x0","ProcessName":"windows\\system32\\svchost.exe"}
{"Key":"\\registry\\machine","GraphKey":"\\REGISTRY\\MACHINE","count":1,"plugin":"regmon","Method":"NtQueryKey","unixtime":"1639557419.752278","TID":"3420","ProcessName":"users\\john\\desktop\\e95b20e76110cb9e3ecf0410441e40fd.exe","PPID":"1324","PID":"616"}
{"count":1,"PID":"616","Method":"NtQueryKey","unixtime":"1639557419.752278","TID":"3420","plugin":"syscall","PPID":"1324","Others":"REST: ,Module=\"nt\",vCPU=0,CR3=0x4B7BF000,Syscall=19,NArgs=5,KeyHandle=0x1F8,KeyInformationClass=0x7,KeyInformation=0x20CD88,Length=0x4,ResultLength=0x20CD98","ProcessName":"users\\john\\desktop\\e95b20e76110cb9e3ecf0410441e40fd.exe"}
Промежуточные данные (последовательности):
syscall_NtQuerySystemInformation*regmon_NtQueryKey*syscall_NtQueryKey
Вектор признаков представлен в таблице:
… | syscall_NtQuerySystemInformationregmon_NtQueryKey | regmon_NtQueryKeysyscall_NtQueryKey | syscall_NtQuerySystemInformation*syscall_NtQueryKey | … |
… | 1 | 1 | 0 | … |
Как накапливались знания модели, как этот процесс менялся, почему важно вовремя остановить накопление данных
Как было сказано выше, основные требования к данным — это репрезентативность, сбалансированность и регулярная обновляемость. Поясним все три пункта в контексте поведенческого анализа вредоносных файлов:
Репрезентативность. Распределение данных по признакам должно быть близким к распределению в реальной жизни.
Сбалансированность. Исходные данные для тренировки модели поступают с разметкой «легитимные» или «вредоносные», и эта информация передается в модель, то есть мы решаем задачу, когда число вредоносных примеров будет близко к числу чистых примеров.
Регулярная обновляемость. Во многом связана с репрезентативностью. Поскольку тренды в области вредоносных файлов постоянно меняются, необходимо регулярно актуализировать знания модели.
С учетом всех вышеперечисленных требований был выстроен следующий процесс накопления данных:
Данные делятся на два типа — основной поток данных и эталонные примеры. Эталонные проверяются экспертами вручную, корректность их разметки гарантирована. Они нужны для валидации модели и управления тренировочной выборкой за счет добавления эталонов. Основной поток размечается правилами и автоматизированными проверками. Нужен для обогащения выборки разнообразными примерами из реальной жизни.
Все эталоны сразу добавляются в обучающую выборку.
Кроме того, добавляется некоторый изначальный набор данных из потока для необходимого объема данных для обучения. Под необходимым объемом данных здесь понимается тот объем, при котором тренировочная выборка оказывается достаточно полной (с точки зрения разнообразия данных) и репрезентативной. Поскольку эталонные примеры проверяются экспертами вручную, нет возможности собрать несколько десятков тысяч только из эталонов, отсюда и потребность добрать разнообразие данных из потока.
Периодически модель тестируется на новых данных из потока.
Точность должна гарантироваться в первую очередь для эталонных примеров, если возникнут противоречия, предпочтение отдается именно эталонным данным, они сохраняются в любом случае.
Со временем данных из потока было накоплено достаточно много, и возникла потребность избавиться от автоматизированного накопления на основе ошибок в пользу более контролируемой обучающей выборки:
Фиксируется обучающая выборка, накопленная на текущий момент;
Данные из потока теперь используются только для тестирования модели, в обучающую выборку ни один экземпляр не добавляется;
Обновление обучающей выборки возможно только в случае обновления набора эталонных примеров.
Таким образом, мы смогли добиться следующего:
Убедились, что обученная и зафиксированная модель может быть достаточно устойчивой к дрифту данных;
Контролируем каждый новый пример, добавляемый в обучающую выборку (эталонные примеры проверяются экспертами вручную);
Можем отслеживать каждое изменение и гарантировать точность на эталонном наборе данных.
Как гарантировать улучшение качества модели с каждым обновлением
После описанного процесса накопления данных, может возникнуть вполне закономерный вопрос: почему мы так уверены, что каждое обновление модели именно улучшает ее?
Ответом является все та же эталонная выборка. Мы считаем ее наиболее корректной, потому что примеры из этой выборки проверяются и размечаются экспертами вручную, и с каждым обновлением проверяется в первую очередь то, что мы все еще гарантируем 100% точности на этой выборке.Тестирование in the wild подтверждает, что точность улучшается.
Достигается это за счет очистки обучающей выборки от противоречащих эталонных данных. Под противоречащими данными мы понимаем примеры, накопленные из потока, которые достаточно близки по векторному расстоянию к трассам из эталонной выборки, но при этом имеют противоположную метку.
Наши эксперименты показали, что такие примеры являются выбросами даже с точки зрения данных из потока, так как после удаления их из обучающей выборки с целью повышения точности на эталонной выборке, возрастала и точность на потоке.
Взаимодополнение ML-подхода и поведенческих детектов в виде корреляций
ML-модель очень хорошо проявила себя в сочетании с поведенческими детектами в виде корреляций. Важно заметить, что именно в сочетании, так как обобщающая способность модели хороша в случаях, когда необходимо расширить решение обнаружением схожих и близких инцидентов, но не в случаях, когда нужен детект в рамках четкого понимания правил и критериев того, что является вредоносным ПО.
Примерами, где ML-подход смог действительно расширить решение, стали:
Аномальные цепочки подпроцессов. Само по себе большое число ветвистых цепочек — явление легитимное. Но аномальность в количестве узлов, степени вложенности, повторяемости или не повторяемости каких-то конкретных имен процессов модель замечает, а человек заранее такое не нафантазирует найти вредоносным.
Нестандартные значения параметров вызовов по умолчанию. В большинстве случаев аналитика интересуют значимые параметры функций, в которых ищут зловред. Остальные параметры, грубо говоря, — значения по умолчанию, они не особо интересуют. Но в какой-то момент так получается, что вместо, допустим, пяти значений по умолчанию встречается шестое. Аналитик мог не предположить, что такое возможно, а модель заметила.
Нетипичные последовательности вызовов функций. Тот случай, когда каждая функция по отдельности не делает ничего вредоносного. Да и в совокупности — тоже. Но так вышло, что их последовательность не встречается в легитимном ПО. Аналитику потребуется гигантский опыт, чтобы самостоятельно заметить такую закономерность. А модель замечает (и не одну), решая нестандартно задачу классификации по признаку, который вообще-то не закладывался как показатель вредоносности.
Примеры, где важен именно сигнатурный поведенческий анализ:
Использование конкретного компонента одним вызовом для вредоносного действия. Система использует сотни объектов в разной вариативности, в разной степени. Уловить использование одного на фоне миллиона других едва ли удастся — гранулярность аномалии все же низковата.
Проактивный детект по модели угроз. Решили, что некое действие на некий объект в системе хотя бы один раз, недопустимо. Модель может с первого раза не понять, что это значимое явление, и будет шанс ошибки или неуверенного решения на этапе классификации чего-то похожего.
Обфускация последовательности действий. Например, может быть известно, что нужно сделать 3-4 действия в определенном порядке. Неважно, что будет между ними. Если накидать мусорные действия между 3-4 ключевыми — это собьет модель, решение будет принято неверно. При этом размерность числа признаков не позволяет учитывать такие запутывания хранением всех комбинаций последовательностей вызовов, а не только общего количества.