Когда на engagement'е попадается Linux-хост с EDR-агентом, первый рефлекс - понять, что именно этот зверь перехватывает. На Windows ответ давно каталогизирован: ntdll-хуки, ETW-провайдеры, kernel callbacks. На Linux картина другая. Агенты разных вендоров используют принципиально разные источники телеметрии - от auditd до eBPF-сенсоров и проприетарных kernel-модулей. И у каждого подхода свои слепые зоны. Вот их-то мы и будем эксплуатировать.
По данным Kaspersky Incident Response, уязвимости в публично доступных приложениях стали первопричиной 39% состоявшихся инцидентов. При этом, согласно CrowdStrike 2025 Global Threat Report (данные цитирует Vectra AI), 82% детектов приходятся на malware-free активность - credential theft, living-off-the-land и identity-based атаки, которые Linux EDR особенно плохо отслеживает. Обход EDR Linux перестал быть прерогативой APT-групп: готовые EDR bypass-инструменты продаются на подпольных форумах от 300 долларов.
Разберём три фундаментальных вектора обхода EDR на Linux для пентестеров: прямые syscall'ы минуя glibc, злоупотребление io_uring и наступательное использование eBPF. Для каждого - конкретный механизм, почему он работает и что проверять на своих хостах.
Как Linux EDR собирает телеметрию и что именно хукается
Чтобы понять, как работают Linux EDR bypass методы, нужно сначала разобрать, что агент видит. Телеметрия на Linux собирается тремя способами, и у каждого характерные дыры.Три уровня перехвата: auditd, eBPF и kernel modules
Auditd (Linux Auditing System) - самый старый и совместимый механизм. Агент подписывается на события аудита ядра: запуск процессов (execve), открытие файлов, сетевые подключения. Проблема в том, что auditd работает как очередь с ограниченным числом потребителей. Если на хосте уже крутится compliance-система, подписанная на audit events, EDR конкурирует за тот же поток. По данным Kaspersky, даже компании с развёрнутым EDR на серверах вынуждены прописывать широкие исключения в правилах мониторинга ради производительности. Результат - часть syscall'ов тупо не попадает в телеметрию.eBPF-сенсоры - современный подход, который используют Falco, Tracee и коммерческие решения вроде BI.ZONE EDR. Агент загружает eBPF-программы, которые цепляются к kprobes (точки входа в kernel-функции) и tracepoints (предопределённые точки трассировки). Например, kprobe на
__x64_sys_execve перехватит запуск любого процесса, а tracepoint sched:sched_process_exec - событие планировщика. eBPF не так сильно бьёт по производительности, как auditd, но реализация различается между ядрами. По данным Cymulate, для работы BTF и CO-RE (Compile Once, Run Everywhere) целевое ядро должно быть собрано с CONFIG_DEBUG_INFO_BTF=y - а это есть далеко не на всех серверах. Лично я на engagement'ах регулярно встречаю RHEL 7 и CentOS 7, где BTF и не пахнет.Проприетарные kernel-модули - отдельные вендоры идут дальше. Kaspersky внедрил технологию UKLM (Universal Linux Kernel Module), которая обрабатывает события через собственный драйвер уровня ядра и, по заявлению вендора, снижает влияние на производительность в 20 раз по сравнению с auditd. Такие модули дают максимальную видимость, но создают зависимость от конкретной версии ядра и дистрибутива.
Ключевой вывод: определите, какой механизм использует конкретный EDR-агент - от этого зависит, на каком уровне нужно работать, чтобы остаться невидимым.
Syscall hooking Linux evasion: прямые вызовы ядра минуя glibc
Большинство пользовательских программ вызывают syscall'ы не напрямую, а через обёртки glibc:execve() → __libc_execve() → инструкция syscall. Часть EDR-агентов ставит uprobes именно на функции glibc или использует LD_PRELOAD для перехвата вызовов в userspace. Это первый и самый простой барьер, который можно обойти.На Linux, в отличие от Windows, номера syscall'ов стабильны между версиями ядра одной архитектуры. Таблица определена в
arch/x86/entry/syscalls/syscall_64.tbl и практически не меняется. Никакой SysWhispers не нужен - достаточно знать номер.Минимальный пример вызова
execve (syscall 59 на x86_64) напрямую, минуя glibc:
C:
#include <unistd.h>
long raw_execve(const char *path, char *const argv[],
char *const envp[]) {
long ret;
__asm__ volatile (
"syscall\n"
: "=a"(ret)
: "0"(59), "D"(path), "S"(argv), "d"(envp)
: "rcx", "r11", "memory"
);
return ret;
}
gcc -nostdlib -nostartfiles -fno-stack-protector -static (при этом нужно определить собственную точку входа _start, например: void _start() { char *argv[]={"bin",NULL}; raw_execve("/bin/sh",argv,NULL); asm("mov $60,%rax; xor %rdi,%rdi; syscall"); }) - итоговый бинарь не затронет ни одну функцию glibc. Если EDR ставил uprobe на glibc-обёртки (__libc_execve, execvp с PATH-resolution) - он этот вызов не увидит.Что по-прежнему ловит прямой syscall: kprobes на kernel-стороне (
__x64_sys_execve), tracepoints (sys_enter_execve), auditd с правилом -a always,exit -F arch=b64 -S execve, seccomp-BPF фильтры. Они перехватывают на уровне входа в ядро, до dispatch'а в конкретный handler.Прямые syscall'ы - не серебряная пуля. Они обходят userspace-хуки, но не kernel-level мониторинг. Тем не менее на практике я регулярно встречаю агенты, которые полагаются исключительно на LD_PRELOAD или uprobe-перехват - для них этой техники за глаза.
Практический подход для пентеста Linux и обхода защиты: напишите свой лоадер на C или Go с прямыми syscall'ами для критических операций -
execve, openat, connect, mmap, mprotect. Стандартные операции (чтение конфигов, вывод в stdout) оставьте через glibc - они не триггерят алерты.io_uring - слепая зона для обхода EDR на Linux
Если прямые syscall'ы обходят userspace-хуки, но остаются видны ядерному мониторингу, то io_uring создаёт проблему другого масштаба: операции выполняются в ядре, но не через те syscall entry points, на которых стоят kprobes EDR-агента.io_uring - интерфейс асинхронного ввода-вывода, появившийся в ядре Linux 5.1 (2019). Работает через два кольцевых буфера в shared memory: Submission Queue (SQ), куда процесс помещает запросы, и Completion Queue (CQ), откуда забирает результаты. После начальной настройки через
[URL='https://man7.org/linux/man-pages/man2/io_uring_setup.2.html']io_uring_setup[/URL] дальнейшие операции не требуют отдельных syscall'ов - ядро забирает запросы из SQ автономно.И вот тут-то начинается самое интересное для уклонения от обнаружения Linux-хостов. EDR-агенты, использующие kprobes на syscall entry points (
[B]x64_sys_read, [/B]x64_sys_write, [I]_x64_sys_connect) или syscall tracepoints (sys_enter[/I]*), не видят аналогичные операции через io_uring. Агенты, хукающие VFS-уровень (vfs_read, vfs_write) или использующие LSM-hooks, могут перехватить и io_uring-операции, потому что внутри ядра io_uring вызывает те же функции. Но таких агентов - меньшинство. По данным Vectra AI, большинство Linux EDR-решений не мониторят io_uring, что создаёт серьёзный пробел в детектировании для серверных окружений.RingReaper: разбор техник по MITRE ATT&CK
RingReaper - пост-эксплуатационный агент, созданный как PoC для демонстрации этой слепой зоны. По данным Picus Security, он полностью заменяет стандартные утилиты разведки io_uring-аналогами:| Задача | Обычный подход | RingReaper (io_uring) | MITRE ATT&CK |
|---|---|---|---|
| Список процессов | ps aux через /proc | Асинхронное чтение /proc через SQ | Process Discovery (T1057) |
| Сетевые подключения | netstat / ss | Запрос kernel network tables | System Network Connections Discovery (T1049) |
| Активные сессии | who / w | Чтение /dev/pts через io_uring | System Owner/User Discovery (T1033) |
| Чтение /etc/passwd | cat /etc/passwd | Асинхронное чтение через SQ | Data from Local System (T1005) |
| Поиск SUID-бинарей | find / -perm -4000 | Проверка через io_uring | Exploitation for Privilege Escalation (T1068) |
| Самоудаление | rm -f | Асинхронный unlink | Indicator Removal: File Deletion (T1070.004) |
Каждая из этих операций тривиальна по отдельности. Но когда они идут через io_uring, eBPF-based EDR с kprobes на
sys_read, sys_openat, sys_unlink их просто не видит. При этом для базовых io_uring-операций чтения root не нужен - io_uring_setup доступен непривилегированным пользователям на хостах без явного запрета (sysctl kernel.io_uring_disabled появился только в ядре 6.6). Docker default seccomp profile блокирует io_uring_setup начиная с Docker 20.10.10 (октябрь 2021), так что в контейнерах этот фокус обычно не пройдёт.На современных дистрибутивах (Ubuntu 23.04+, RHEL 9, Debian 12) проверьте
cat /proc/sys/kernel/io_uring_disabled - значение 0 разрешает всем, 1 разрешает только процессам с CAP_SYS_ADMIN при создании ring, 2 полностью запрещает. Если 0 - вам повезло, io_uring один из самых практичных методов обхода EDR на Linux при пентесте.eBPF evasion техники: мониторинг как оружие атакующего
eBPF позволяет динамически загружать программы в ядро Linux. По данным Cymulate, через kprobe/tracepoint/LSM hooks он даёт возможность наблюдать syscall'ы, точки входа и выхода функций ядра и userspace, сетевые события. Модификация поведения ограничена:bpf_override_return работает только для функций с ALLOW_ERROR_INJECTION. Но та же мощь делает eBPF идеальным инструментом для атакующего - и тут ирония: EDR-вендоры сами приучили ядро доверять eBPF-программам.С 2023 года появилось несколько руткитов на eBPF:
ebpfkit, TripleCross, Pamspy. Они перехватывают учётные данные, обходят файрволы и слепят EDR-агенты. Разберём три наступательных сценария syscall hijacking Linux через eBPF.Ослепление телеметрии - Indicator Blocking (T1562.006, Defense Evasion). Атакующий загружает eBPF-программу, которая цепляется к тем же kprobes, что и EDR, но с более высоким приоритетом. Она модифицирует данные, которые видит агент: скрывает процессы, фильтрует сетевые события, подменяет содержимое файлов. По анализу Red Canary (цитирует windshock.github.io), однажды загруженное eBPF-вредоносное ПО может скрытно изменять результаты
bpftool и debugfs, делая пост-компрометационное обнаружение крайне затруднительным. По сути, EDR смотрит на мир через линзу, которую контролирует атакующий.Перехват учётных данных.
Pamspy - eBPF-программа, ставящая uprobe на функции PAM (Pluggable Authentication Modules). Перехватывает пароли в момент аутентификации. Для EDR это выглядит как легитимная eBPF-программа, потому что eBPF и есть легитимная технология ядра. Красота.Обход файрвола и скрытый C2.
BPFDoor, использовавшийся в реальных APT-атаках, вставлял пакетный фильтр в ядро. Хост при этом выглядел так, словно не имеет открытых сетевых портов - nmap показывал чистый результат. По данным windshock.github.io (со ссылкой на Trend Micro), BPFDoor внедрял packet filters в ядро для обхода правил файрвола, маскируясь под отсутствие сетевых сервисов.Почему обход антивируса Linux через eBPF так эффективен? eBPF-программы не лежат на диске в традиционном смысле. Они работают в kernel space, недоступном для userspace-сканеров. eBPF-руткит может манипулировать данными, которые видит сам антивирус. Традиционный файловый сканер попросту не имеет точки наблюдения для обнаружения eBPF rootkit - он слепой по определению.
По данным Cymulate, добавление
CAP_PERFMON или CAP_NET_ADMIN расширяет возможности программы. Исключение - BPF_PROG_TYPE_SOCKET_FILTER, которую может загрузить непривилегированный пользователь, если /proc/sys/kernel/unprivileged_bpf_disabled не установлен в 1 или 2.Для полноценного eBPF evasion атакующему нужен root. И тут в игру вступают уязвимости повышения привилегий. В sudo до версии 1.9.17p1 опция
--chroot позволяет использовать /etc/nsswitch.conf из пользовательского каталога. Атакующий подготавливает вредоносный nsswitch.conf, указывающий на подконтрольную NSS-библиотеку, и выполняет произвольный код от root. Эксплуатация требует, чтобы в sudoers пользователю было разрешено выполнение команды с --chroot (или CHROOT=* в Defaults) - на дефолтных конфигурациях многих дистрибутивов это не так. CISA добавила CVE-2025-32463 в каталог KEV (актуально эксплуатируется в дикой среде, добавлена 2025-09-29). EPSS-оценка - 0.4446 (Top 5% по вероятности эксплуатации в ближайшие 30 дней). Публичные PoC доступны - pr0v3rbs/CVE-2025-32463_chwoot на GitHub (521 звезда).Цепочка для пентестера: непривилегированный доступ (при наличии sudo с --chroot в sudoers) → эксплуатация CVE-2025-32463 → root → загрузка eBPF-программы для ослепления EDR → выполнение основной задачи.
Из актуального стоит отметить CVE-2025-31161 в CrushFTP (CVSS 9.8 CRITICAL, CWE-305) - authentication bypass через race condition в AWS4-HMAC авторизации, EPSS 0.8621 (Top 1%). CISA включила эту уязвимость в каталог KEV (актуально эксплуатируется в дикой среде, добавлена 2025-04-07) с пометкой об использовании в ransomware-кампаниях.
Практический сценарий: пентест Linux с обходом защиты хоста
Требования к окружению
- Целевой хост: Linux kernel 5.1+ (для io_uring), дистрибутив с eBPF-поддержкой (ядро 4.4+ с BTF для CO-RE)
- EDR-агент: Falco, Tracee, CrowdStrike Falcon for Linux, BI.ZONE EDR или аналог
- Привилегии: для разведки - любой пользователь; для eBPF evasion - root или CAP_BPF
- Инструменты атакующего: gcc/clang с
-static, библиотека liburing, bpftool
Пошаговый алгоритм
📚 Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
📚 Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Обнаружение eBPF rootkit и защита Linux-хостов
Этот раздел - для blue team и для пентестеров, которые пишут рекомендации по итогам engagement'а.Первое, что нужно проверять - загруженные eBPF-программы и их привязки к сетевым интерфейсам:
Bash:
bpftool prog show && bpftool map show
for iface in $(ls /sys/class/net/); do
ip link show dev "$iface" | grep -q "xdp" \
&& echo "[!] XDP attached: $iface"
done
for iface in $(ls /sys/class/net/); do
tc filter show dev "$iface" 2>/dev/null
done
bpftool prog show показывает программы с типами kprobe, tracepoint или xdp, не принадлежащие известному EDR или мониторингу - повод копать дальше. Но помните: если eBPF-руткит уже активен, он может подменять вывод самого bpftool. Курица и яйцо.Именно поэтому одного мониторинга недостаточно. По данным windshock.github.io, наиболее эффективна комбинация двух инструментов. Tracee (Aqua Security) работает как камера наблюдения - записывает аномальные eBPF-события в реальном времени, сам основан на eBPF и отслеживает загрузку новых программ. LKRG (Linux Kernel Runtime Guard) работает как решётка на окне - активно мониторит целостность структур ядра и предотвращает модификации syscall table, подмену callback'ов и DKOM (Direct Kernel Object Manipulation, техника Rootkit - T1014, Defense Evasion по MITRE ATT&CK).
Tracee без LKRG - записывает, но не блокирует. LKRG без Tracee - блокирует, но не оставляет forensic-следа. Оба вместе дают и детектирование, и предотвращение.
Дополнительные меры для Linux endpoint detection evasion prevention:
- Установите
sysctl kernel.unprivileged_bpf_disabled=1- запретите непривилегированным пользователям загрузку любых eBPF-программ - Обновите sudo до 1.9.17p1+ для закрытия CVE-2025-32463
- Мониторьте процессы с удалёнными исполняемыми файлами, использующие BPF-сокеты: если
readlink /proc/PID/exeвозвращает строку с(deleted), а/proc/PID/net/packetнепуст - это паттерн BPFDoor - На серверах с ядром 5.1+ проверяйте io_uring:
cat /proc/PID/fdinfo/* | grep -i uringдля подозрительных процессов - Seccomp-BPF профили для критических сервисов - они перехватывают syscall'ы на уровне входа в ядро, включая прямые вызовы
Вопрос к читателям
На engagement'ах с Falco или Tracee на целевых Linux-хостах - какие kprobes и tracepoints вы видите черезbpftool prog show в секциях type: kprobe и type: tracepoint? Конкретно интересует: перехватывает ли ваш агент io_uring_submit или __io_submit_sqe, или io_uring остаётся полностью слепой зоной? Если писали кастомные правила Falco для детекта io_uring-операций - поделитесь фрагментом YAML-конфига с полями rule и condition, укажите версию Falco.