Как реализовать поведенческий анализ в Linux на уровне гипервизора
Привет, Хабр! Меня зовут Алексей Колесников, я работаю в отделе обнаружения вредоносного ПО экспертного центра безопасности Positive Technologies (PT Expert Security Center, PT ESC). Недавно я выступил на международной конференции AVAR 2023, которая проходила в Дубае. Рассказывал про новые плагины, разработанные PT Expert Security Center для опенсорсной системы динамического анализа вредоносного программного обеспечения DRAKVUF, и показывал, как с их помощью в песочнице PT Sandbox детектировать актуальные угрозы для Linux.
Под катом мини-обзор популярных инструментов для мониторинга вредоносов в Linux, о работе наших плагинов в DRAKVUF и анализ ВПО с их использованием.
Инструменты мониторинга в Linux
Зачастую события из операционной системы необходимо собирать либо для построения endpoint detection and response, либо для анализа ВПО в песочнице. На втором варианте мы остановимся подробнее, поговорим о недостатках популярных инструментов мониторинга вредоносов в Linux.
auditd
Auditd — одно из популярнейших решений в комьюнити, благодаря простому процессу инсталляции, понятному синтаксису, возможности анализировать системные вызовы и события файловой системы. К сожалению, auditd неидеален, у него есть недостатки:
Отсутствие единого формата сообщений. Программа, работающая с auditd, может отправлять сообщения в любом формате. Это не так удобно, как, например, исключительное использование формата JSON.
События отображаются не по порядковому номеру идентификатора. Например, сначала 645, после 646, а затем снова 645. Это затрудняет и замедляет работу.
Низкая гибкость правил. Auditd не позволяет получить доступ ко всему ядру, а дает возможность работать исключительно с API. Это неудобно, когда есть необходимость написать что-то сложнее программы перехвата системных вызовов.
Риск компрометации системы. Вредоносная программа, получив root-права, может отключить систему журналирования. В таком случае вся система анализа будет бесполезной.
inotify и fanotify
Есть и другие инструменты мониторинга ВПО в Linux. Например, inotify и fanotify, но они тоже несовершенны. Так, структура inotify_event не позволяет узнать полную информацию о процессе: специалист получит уведомление о произошедшем событии, но какая программа его инициировала — останется загадкой. В качестве решения этой проблемы разработчики ядра Linux предлагают использовать fanotify: событие имеет дескриптор файла и процесса. Однако и этой информации будет недостаточно: имя программы, инициировавшей событие безопасности, по-прежнему останется неизвестным.
eBPF
Еще один инструмент для построения изолированной среды — eBPF (extended Berkley Packer Filter). Сегодня это не просто набор фильтров пакетов, а полноценная виртуальная машина, позволяющая писать программы любой сложности на языке программирования C — от мониторинга сетевого трафика до анализа производительности и безопасности системы. Взаимодействуют такие программы с помощью BPF_MAP, который представляет из себя общий hashmap для программ в user space и kernel space.
eBPF объединяет в себе функциональность auditd, inotify и fanotify. С помощью механизма Linux kprobe можно перехватить любую функцию ядра, а с помощью uprobe — любую функцию из User Space. Но даже это не избавляет пользователей от явных недостатков инструмента:
жесткая привязка к специальным BPF-функциям, которые называются helpers;
наличие гарантии на время выполнения программы, не позволяющей использовать какие-либо циклы, кроме константных;
ограничение количества инструкций — 4096 для версий ядра Linux до 5.2 и до 1 млн для более новых версий.
Какие плагины мы сделали
DRAKVUF — система динамического анализа вредоносных файлов. Она работает в связке с гипервизором Xen, позволяя анализировать одновременно несколько машин в изолированной среде. За анализ состояния системы отвечает компонент LibVMI (Virtual Machine Introspection). Он позволяет не только читать виртуальную память, но и модифицировать ее. Такой подход дает возможность безопасно запускать в ней вредоносный код.
Совершенствовать модульную систему DRAKVUF можно с помощью различных плагинов, что позволяет добиться большой гибкости при анализе потенциально опасного кода. Если существующих плагинов недостаточно для анализа ВПО, то их можно написать самим, как мы в Positive Technologies и сделали.
Procmon
Procmon — новый плагин для DRAKVUF, разработанный PT Expert Security Center с целью отслеживания появления новых процессов в системе под управлением Linux. Чтобы объяснить логику его работы, я напомню, как в ядре Linux порождается процесс, и какая в нем хранится информация.
Для запуска любой программы в Linux нужно вызвать одну из функций семейства exec. При этом следует помнить, что системные вызовы execve и execveat не создают нового процесса, а замещают текущий экземпляр программы с помощью замены стека, кучи и сегмента данных. За создание независимых процессов отвечают вызовы fork и clone. Вот как схематично выглядит порождение нового процесса в Linux:
Запущенный процесс хочет вызвать команду whoami, для чего он обращается к функции system из библиотеки libc, которая вызывает fork. Системный вызов execve происходит только после получения нового идентификатора процесса.
Для хранения информации обо всех процессах ядро Linux использует структуру task_struct — связный список, позволяющий получить доступ к каждому процессу в системе. Структура является абстракцией процесса, благодаря которой можно получить PID (Process ID, идентификатор процесса), Parent PID (идентификатор родительского процесса), информацию о дочерних процессах, короткое имя и другую информацию о запущенном процессе.
Еще одна структура, участвующая в запуске процесса, называется linux_binrpm (Linux Binary Program). Она позволяет получить указатель на дескриптор файла, имя интерпретатора, а также данные о факте повышения привилегий. Ключевое отличие этой структуры от task_struct — ее назначение. Linux_binrpm хранит информацию о процессе, который будет запущен, а task_struct описывает уже работающий в системе процесс.
Плагин procmon перехватывает не системный вызов execve, а функцию begin_new_exec. Это объясняется малым количеством информации о запускаемой программе в execve. Тело функции begin_new_exec, в свою очередь, выполняет замещение процесса, ожидаемое от вызова execve. Таким образом, перехватывая функцию в начале вызова, мы имеем информацию о родительском процессе вместе со структурой linux_binprm, из которой можем получить информацию о дочернем процессе, а на момент выхода из функции — информацию уже о новой запущенной программе.
В качестве примера работы плагина procmon я запустил в Ubuntu 20.04 с ядром Linux 5.15 два процесса: uname и whoami. В поле ProcessName — имя запускающего процесса, а в ImagePathName — имя запускаемого процесса. С помощью плагина дополнительно извлекается и командная строка, и прочие поля из структуры linux_binprm. Этой информации достаточно, чтобы, например, построить граф процессов.
filetracer
Еще один плагин для системы DRAKVUF — filetracer. Он позволяет фиксировать события файловой системы в Linux. При его разработке и тестировании мы столкнулись с задачей автоматического определения версии ядра Linux. Дело в том, что порядок параметров в функциях изменился после выпуска версии ядра 5.12. В качестве решения мы добавили в код специальный метод drakvuf_get_kernel_version, который позволяет узнать текущую версию ядра.
В качестве примера работы плагина предлагаю рассмотреть код обработчика для перехваченного метода do_truncate. Наш метод определения версии ядра, помимо выполнения основной задачи, дает возможность управлять процессом получения аргументов из функции.
Что касается логики работы filetracer, то она намного проще procmon. Результат не может не радовать: события имеют необходимую информацию о действиях программы, что позволяет вынести вердикт о ее возможном вредоносном поведении. Так, с помощью плагина мы получаем имя процесса, читающего файл, имя файла и его метод, разрешения, а также его местонахождение в системе.
А что еще?
Я рассказал всего о двух плагинах, которые мы с командой разработали для DRAKVUF, но на самом деле их гораздо больше. Все они, разумеется, направлены на получение полной информации о работе вредоносного ПО. Например, syscalls — для мониторинга системных вызовов, rebootmon — для мониторинга событий перезагрузки.
Кроме того, в разработке сейчас еще два плагина:
filextractor — для извлечения из виртуальной машины файлов, которые образец создает или скачивает в процессе своей работы.
socketmon — для отслеживания сетевой активности программ. Этот плагин станет хорошим дополнением к трафику, потому что позволит специалисту отследить, какой процесс создал тот или иной запрос.
Как наши плагины для DRAKVUF анализируют вредоносное ПО, попадающее в PT Sandbox
В качестве примера работы плагинов рассмотрим, как они детектируют три семейства ВПО в Linux — XorDDoS, BPFDoor и Mirai. Анализ вредоносного ПО — небыстрая задача, поэтому для демонстрации я сфокусировался на ключевых особенностях в поведении вредоносов.
XorDDoS
Одно из основных свойств работы XorDDoS — закрепление ВПО во временной директории tmp.
Слева на картинке — событие, которые фиксирует filetracer. Здесь видно, что анализируемый процесс делает системный вызов write, но поскольку мы перехватываем функции ядра, то метод vfs_write записывает файл со случайным именем в tmp. Справа — псевдокод из декомпилятора, демонстрирующий факт вызова функции для записи файла. Закрепление в tmp зафиксировано, а значит ВПО обнаружено.
BPFDoor
Особенность BPFDoor — умение фильтровать сетевые соединения, устанавливая BPF-фильтр на сетевой сокет Linux.
Слева на картинке показано, какое событие фиксирует syscalls. Плагин позволяет видеть имя процесса, метод, а также строковые идентификаторы для enum-значений сокетов SOL_SOCKET и SO_ATTACH_FILTER. Справа — псевдокод, где показана работы плагина по детекту ВПО.
Mirai
Mirai — бэкдор для распространения ботнетов. Один из примеров его работы — неявное исполнение системного вызова prctl с параметром PR_SET_NAME. Вызов prctl позволяет изменить имя процесса для его сокрытия от администратора сети, когда тот, например, будет проверять список запущенных процессов.
Для детектирования такой активности понадобятся события двух плагинов DRAKVUF — filetracer и syscalls. Поэтому я дополнительно выделил функцию, с помощью которой образец ВПО делает запись в поток stdout.
Событие, получаемое от плагина syscalls, дает возможность увидеть имя системного вызова — prctl, а также параметр PR_SET_NAME. Плагин filetracer, в свою очередь, позволяет узнать значение поля FileName — 1, а в ThreadName другое значение — /var/Sofia. Поскольку все эти события инициируются одним процессом в системе, их можно соотнести друг с другом по идентификаторам и сделать вывод: запуск процесса был инициирован Mirai.
Заключение
Итак, реализовать безагентный поведенческий анализ ВПО в системах под управлением Linux — непростая, но все-таки выполнимая задача. Сложность во многом вызвана отсутствием готовых решений, которые полностью бы нам подошли. Благодаря такому подходу мы получили большую гибкость при анализе вредоносов.
Все разработанные мной и моими коллегами из команды PT ESC плагины доступны каждому пользователю DRAKVUF. Сам опенсорсный инструмент сейчас в процессе активной разработки, поэтому любой может внести свой вклад в сообщество и сделать анализ ВПО в Linux доступнее и полнее.
Cпециалист отдела обнаружения вредоносного ПО PT ESC
Еще полезные статьи о наших плагинах для DRAKVUF и не только: