blog
Есть пост в Telegram

Короткая версия, обсуждение и комментарии — в канале.

Открыть →

eBPF для SOC: мониторинг Linux, Tetragon, Falco и кейс eBPF-руткита

Практический разбор eBPF для SOC: как работает технология, чем мониторить Linux без готовых сенсоров, когда выбирать Falco или Tetragon и как расследовать eBPF-руткит.

Иллюстрация про eBPF, мониторинг Linux и работу SOC

🔥 eBPF для SOC: мониторинг Linux, Tetragon, Falco и кейс eBPF-руткита

Linux давно перестал быть «чёрным ящиком, который живёт где-то у админов». Для SOC это полноценная плоскость боя: контейнеры, веб-сервисы, CI/CD, jump-хосты, bare metal, Kubernetes-ноды. А значит, чем глубже мы видим поведение системы, тем раньше ловим атаку.

И вот тут на сцену выходит eBPF. Для кого-то — магия ядра. Для кого-то — новый источник телеметрии. А для атакующего это вообще почти легальный rootkit-конструктор.

Разберём без лишней академичности:

  • что такое eBPF и почему о нём говорят все, кто трогает Linux security;
  • как мониторить «сырой» Linux, если Tetragon и Falco пока не завезли;
  • чем Falco и Tetragon отличаются глазами SOC;
  • как превратить eBPF-события в нормальные алерты, а не в мусорный конвейер;
  • и как расследовать кейс, где злоумышленник дошёл до eBPF-руткита.

🧠 eBPF: что это вообще такое

eBPF (extended Berkeley Packet Filter) — это механизм ядра Linux, который позволяет загружать небольшие программы и выполнять их внутри ядра в ответ на определённые события.

Если совсем по-человечески: это как плагины для ядра Linux, которые можно подключать без пересборки ядра и без перезагрузки хоста.

Почему это важно:

  • телеметрию можно собирать почти у источника события;
  • не нужно каждый раз гонять данные в userspace на каждый чих;
  • можно делать не только наблюдение, но и контроль поведения;
  • eBPF подходит и для network visibility, и для security, и для performance monitoring.

💡 Зачем eBPF вообще придумали

Старый мир выглядел так:

  1. Хочешь глубоко смотреть в ядро — пиши модуль ядра.
  2. Хочешь управлять поведением — патчи, костыли, риск уронить прод.
  3. Хочешь телеметрию — собирай её выше по стеку и мирись с потерей контекста.

Проблема в том, что продакшен не любит такие эксперименты. Нужен был механизм, который:

  • даёт глубокую видимость;
  • работает быстро;
  • не требует ломать аптайм;
  • не превращает каждое изменение в спецоперацию с перезагрузкой.

eBPF как раз и стал таким компромиссом: достаточно гибкий, достаточно быстрый и при этом контролируемый через верификатор.

⚙️ Как это работает

Типовой жизненный цикл eBPF-программы выглядит так:

  1. Пишем код — обычно на C, либо используем высокоуровневые инструменты вроде bpftrace или bcc.
  2. Компилируем в BPF-байткод.
  3. Загружаем программу в ядро.
  4. Верификатор проверяет, что код безопасен.
  5. Привязываем программу к нужному hook’у.
  6. Ядро исполняет её при наступлении нужного события.
# Список загруженных eBPF-программ
bpftool prog show

# Список eBPF-карт
bpftool map show

Куда можно подцепиться

Упрощённо, самые полезные для SOC точки такие:

  • kprobes / kretprobes — перехват функций ядра;
  • uprobes — наблюдение за функциями в userspace;
  • tracepoints — встроенные точки трассировки;
  • XDP / TC — ранняя фильтрация и анализ сетевого трафика;
  • LSM hooks — контроль безопасности и доступов;
  • syscall visibility — отслеживание системных вызовов и их контекста.

🔐 Почему это одновременно подарок и проблема для ИБ

С точки зрения защиты eBPF — роскошь. С точки зрения атакующего — тоже.

Вот где начинаются риски:

  • эксплуатация багов в механизмах eBPF и ядре;
  • скрытые eBPF-программы для перехвата файловых и сетевых операций;
  • обход мониторинга за счёт собственных hooks и фильтрации данных;
  • шпионаж за чтением файлов, сетевыми вызовами и поведением процессов;
  • DoS через тяжёлые программы или неаккуратную работу с BPF maps.

💀 Проще говоря: eBPF — это как rootkit, только легальный и с документацией. Поэтому SOC должен хотя бы стремиться видеть каждую попытку его использования.

🎯 Что именно должен делать SOC

Минимальный набор здравого смысла:

  • логировать факты вызова bpf();
  • регулярно проверять загруженные eBPF-программы и карты;
  • ограничивать возможность загрузки eBPF не тем процессам и аккаунтам;
  • отслеживать изменения политик и hooks;
  • собирать контекст: кто загрузил, откуда, в каком контейнере, на каком хосте.
# Логировать системный вызов bpf()
auditctl -a always,exit -F arch=b64 -S bpf

🐾 Когда Linux «сырой»: мониторинг без Tetragon и Falco

Иногда реальность простая и неприятная: у тебя есть Linux-хосты, прод уже шумит, а нормального eBPF-сенсора ещё нет. Тогда приходится собирать наблюдаемость «на коленке».

Это не красиво. Но это лучше, чем слепота.

1. Ловим загрузку eBPF и модулей ядра

# Загрузка eBPF-программ
auditctl -a always,exit -F arch=b64 -S bpf

# Загрузка модулей ядра
auditctl -a always,exit -F arch=b64 -S init_module -S finit_module

2. Видим подозрительный exec

# Исполнение из /tmp
auditctl -a always,exit -F dir=/tmp -F perm=x

# Исполнение из /dev/shm
auditctl -a always,exit -F dir=/dev/shm -F perm=x

3. Контролируем смену UID/GID

auditctl -a always,exit -F arch=b64 -S setuid -S setgid

4. Добавляем сетевой контекст

Если повезло — ставим Sysmon for Linux и получаем JSON-события по exec, connect, file create/delete.

Если совсем пустыня — хотя бы:

# Поток событий conntrack
conntrack -E

# Или сырое снятие трафика
tcpdump -nn -i any

Мини-кейс: exec в /tmp → алерт в SIEM

  1. Включаем правило в auditd:
auditctl -a always,exit -F dir=/tmp -F perm=x
  1. Получаем событие:
type=EXECVE msg=audit(1723450105.123:456): argc=1 a0="/tmp/m.sh"
  1. Пишем правило в SIEM, например в KQL:
event.dataset:"linux.auditd" and process.executable:/tmp/*
  1. Дальше уже начинается нормальная работа:
  • ловим запуск скриптов и бинарей из временных директорий;
  • коррелируем с исходящим соединением;
  • получаем очень внятный кандидат на initial access, payload launch или C2.

Минусы ручного подхода

Их много, и они неприятные:

  • шумных событий будет вагон;
  • enrichment почти отсутствует;
  • цепочки событий приходится клеить руками;
  • на десятках и сотнях хостов всё это превращается в филиал страдания;
  • централизованного управления почти нет.

И вот в этот момент ты понимаешь, что пора вылезать из режима «скотч и auditd».

🛠 Falco vs Tetragon: кто нужен SOC

Когда базового Linux-мониторинга уже мало, обычно начинаешь смотреть в сторону двух знакомых имён: Falco и Tetragon.

Оба решают реальную боль SOC, но делают это немного по-разному.

Что это за инструменты

Falco — один из самых известных сенсоров для runtime security. Исторически особенно силён в контейнерных и Kubernetes-сценариях. Слушает события, применяет правила и отдаёт алерты туда, куда ты скажешь.

Tetragon — инструмент от экосистемы Cilium, ориентированный на глубокое наблюдение и enforcement на базе eBPF. Хорошо чувствует себя там, где важны контекст, гибкие селекторы и работа ближе к ядру.

Коротко для SOC

  • Falco — проще стартануть, особенно если у тебя контейнеры и нужен быстрый результат.
  • Tetragon — глубже телеметрия, богаче контекст и сильнее сценарии для bare metal и продвинутого Linux monitoring.
  • Оба — не серебряная пуля. Если у атакующего полный root и время, он попытается убить или обойти любой сенсор. Значит, надо мониторить ещё и вмешательство в сами датчики.

📊 Сравнение Falco и Tetragon

Falco vs Tetragon — коротко для SOC

Что важно запомнить

  • Для Kubernetes и быстрого старта Falco часто оказывается проще.
  • Для bare metal, deep visibility и Linux-level расследований Tetragon обычно интереснее.
  • Для зрелого SOC нормальный сценарий — не «или/или», а комбинирование сигналов и корреляция в SIEM.

Пример: ловим exec из /tmp

Falco rule

- rule: Exec from tmp
  desc: Detect process execution from temporary directories
  condition: >
    evt.type in (execve, execveat) and
    (
      proc.exepath startswith /tmp or
      proc.exepath startswith /var/tmp or
      proc.exepath startswith /dev/shm
    )
  output: >
    Exec from temp dir | user=%user.name proc=%proc.name exe=%proc.exepath
    parent=%proc.pname cmdline=%proc.cmdline
  priority: WARNING

Tetragon policy

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: suspicious-exec
spec:
  kprobes:
    - call: "do_execveat_common"
      args:
        - index: 0
          type: "string"
      selectors:
        - matchArgs:
            - index: 0
              operator: "Prefix"
              values:
                - "/tmp/"
                - "/var/tmp/"
                - "/dev/shm/"

🕵️ Falco vs Tetragon глазами атакующего

Если на хосте Falco, атакующий часто пытается:

  • мимикрировать под легитимные процессы;
  • пройти «под шумом» дефолтных правил;
  • использовать нестандартные бинарники, пути и связки процессов, которые никто не детектит.

Если на хосте Tetragon, становится сложнее за счёт более глубокой наблюдаемости и богатого контекста. Но магии нет: при полном контроле над хостом атакующий будет стараться убить датчик, обойти hooks или ослепить канал доставки событий.

💡 Практический вывод простой: детектить надо не только атаку, но и попытки отключить то, что её детектит.

🧩 Как превратить eBPF-события в боевые алерты

Видеть событие мало. Нужен сценарий, при котором событие становится понятным сигналом для SOC.

Возьмём классический пример: запуск бинаря из временной директории.

1. Включаем политику

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
  name: suspicious-exec
spec:
  kprobes:
    - call: "do_execveat_common"
      args:
        - index: 0
          type: "string"
      selectors:
        - matchArgs:
            - index: 0
              operator: "Prefix"
              values:
                - "/tmp/"
                - "/dev/shm/"

2. Смотрим, что приходит в лог

{
  "process_exec": {
    "parent": "bash",
    "binary": "/tmp/payload",
    "uid": 1000,
    "pod": "web-frontend-42",
    "namespace": "prod"
  }
}

Вот за что eBPF-сенсоры любят даже те, кто обычно всё ненавидит: событие уже несёт контекст. Видно, кто, что, где и в каком окружении сделал.

3. Пишем правило в SIEM

process_exec.binary: "/tmp/*" AND NOT process_exec.parent: "systemd"

4. Снижаем фолсы

Если просто алертить любой exec из /tmp, очень быстро получишь ненависть от DevOps. Поэтому:

  1. Исключай известные namespace и CI/CD-сценарии.
  2. Обогащай события по CMDB или inventory.
  3. Строй цепочки поведения, а не живи одним событием.

Например, гораздо вкуснее выглядит не просто exec, а вот такая связка:

  • exec из /tmp
  • затем setuid
  • затем connect наружу

Вот это уже пахнет не билдом, а приключениями.

5. Что это даёт SOC

  • меньше бессмысленного шума;
  • больше контекста в одном событии;
  • проще строить корреляции;
  • можно ловить не отдельные действия, а целое поведение атакующего.

🔥 Кейc: расследование eBPF-руткита

Теперь к самому интересному. Представим реалистичную цепочку:

web-приложение с RCE → payload в /tmp → загрузка eBPF-программы → hooks на чтение файлов и сетевые операции → маскировка активности и эксфильтрация.

Ниже — не художественный фильм, а вполне рабочий SOC-сценарий.

1. Первичный сигнал

Сработали два алерта:

  1. exec-in-tmp/tmp/.kworker запущен от nginx
  2. bpf-load — процесс почти сразу вызывает bpf(BPF_PROG_LOAD)

Пример событий:

{
  "time": "2025-11-06T03:42:10Z",
  "event": "exec",
  "process": {
    "pid": 4123,
    "ppid": 2890,
    "exe": "/tmp/.kworker",
    "args": ["/tmp/.kworker"],
    "user": "www-data"
  },
  "container": {
    "id": "c9a3...",
    "name": "web-frontend-3",
    "pod": "web-frontend-3"
  },
  "policy": "exec-in-tmp"
}
{
  "time": "2025-11-06T03:42:12Z",
  "event": "bpf_load",
  "process": {
    "pid": 4123,
    "exe": "/tmp/.kworker"
  },
  "bpf": {
    "type": "kprobe",
    "target": "vfs_read,tcp_sendmsg",
    "id": 57
  }
}

2. Быстрая корреляция в SIEM

(
  event.dataset:"tetragon.exec" and process.pid:4123
) or (
  event.dataset:"tetragon.bpf" and process.pid:4123
) or (
  event.dataset:"tetragon.net" and process.pid:4123
)

Дальше в Discover или в своём пайплайне сортируешь по @timestamp и получаешь цепочку:

exec (/tmp/.kworker) → bpf_load → connect(dst=185.41.23.22:443)

Если ещё видно активность вокруг vfs_read, картина становится совсем некрасивой.

3. Containment: первые 15 минут

Главная ошибка здесь — начать героически всё перезапускать и потерять артефакты.

Что делать правильно:

  1. Изолировать хост или контейнер.
  2. Заблокировать egress на выявленные IP и порты.
  3. Не рестартить систему до снятия артефактов.
  4. Снять процессы, соединения и открытые файлы.
  5. Скопировать бинарник в отдельное forensics-хранилище.
ps auxf | grep 4123
ss -tunap | grep 4123
lsof -p 4123

cp /tmp/.kworker /srv/forensics/host123/.kworker.bin
sha256sum /srv/forensics/host123/.kworker.bin

4. Forensics: ревизия eBPF-артефактов

Сначала смотрим, что вообще загружено:

# Показать eBPF-программы
bpftool prog show

# Найти программу вокруг нужного PID или attach type
bpftool prog show | grep 4123 -B4 -A4

# Снять дамп представления программы
bpftool prog dump xlated id 57 > /srv/forensics/host123/bpf_prog_57.txt

# Сохранить список карт
bpftool map show > /srv/forensics/host123/bpf_maps.txt

Дальше смотрим сам бинарник:

strings /tmp/.kworker
readelf -h /tmp/.kworker
file /tmp/.kworker

Что ищем:

  • упоминания vfs_read, tcp_sendmsg, bpf;
  • URL, домены, IP, строки C2;
  • упаковщики и признаки self-extracting ELF;
  • обращение к BPF maps;
  • странные символы и импорты.

5. Проверяем persistence

Если атакующий уже дошёл до eBPF, надеяться, что он ограничился одним бинарём, довольно наивно.

Проверяем:

  • crontab
  • systemd units
  • init scripts
  • /etc/ld.so.preload
  • shell-профили
  • контейнерные image layers
  • автозапуски и sidecar-логики

6. Снимаем память и /proc, если можно

gcore 4123

cp /proc/4123/maps /srv/forensics/host123/proc_maps.txt
ls -la /proc/4123/fd > /srv/forensics/host123/proc_fd.txt

Это не всегда возможно и не всегда безопасно, но если процесс ещё живой — артефактов там часто больше, чем в логах.

7. Network forensic: C2 и exfil

tcpdump -n -s 0 -w /srv/forensics/host123/conn_185.41.23.22.pcap \
  host 185.41.23.22 and port 443

Типовые признаки:

  • короткие регулярные соединения;
  • странный или пустой TLS SNI;
  • однотипный размер пакетов;
  • нетипичная частота beaconing;
  • трафик, не похожий на приложение, от имени которого он идёт.

8. Root cause

В нашем сценарии корень проблемы выглядит так:

  1. Уязвимый веб-компонент дал RCE.
  2. Через RCE payload загрузили в /tmp.
  3. Сделали chmod +x и запустили бинарь.
  4. Бинарь вызвал bpf() и загрузил eBPF-программы.
  5. Hooks начали перехватывать файловые и сетевые операции.
  6. Дальше пошли маскировка и эксфильтрация.

Классическая цепочка, от которой SOC обычно страдает так:

RCE → /tmp exec → bpf_load → connect → exfiltration

Если ты видишь её целиком — у тебя уже очень хорошие шансы остановить атаку до полноценного развития.

🧯 Remediation: что делать после фиксации

После сбора артефактов и containment начинается менее романтичная, но обязательная часть:

  1. Патчим или удаляем уязвимый компонент.
  2. Реимеджим контейнер или хост из known-good источника.
  3. Ротируем все секреты, которые могли быть прочитаны.
  4. Удаляем вредоносные eBPF-программы и карты только после снятия дампов.
  5. Проверяем IOC по остальной инфраструктуре.
  6. Проводим post-mortem и добиваем детекты.

Пример команд:

bpftool prog detach id 57
bpftool prog pin id 57 /sys/fs/bpf/old_57

lsmod | grep suspicious
cat /proc/modules

📋 Playbook для SOC

Вот компактный чеклист, который можно реально превратить в внутренний runbook:

  • триггер: exec из /tmp или bpf_load;
  • поднять приоритет до High, если события рядом по времени;
  • коррелировать по pid, hostname, container, timestamp;
  • изолировать хост/контейнер и заблокировать egress;
  • сохранить бинарь, /proc, сетевые артефакты и дампы;
  • снять bpftool, ss, lsof, ps;
  • проверить persistence;
  • определить root cause;
  • ротировать секреты;
  • распространить IOC и hunting-запросы по инфраструктуре.

✅ Что внедрять в первую очередь

Если хочется не просто вдохновиться статьёй, а реально улучшить защиту, начни с этого:

  1. Логируй вызовы bpf() всегда.
  2. Лови exec из /tmp, /var/tmp, /dev/shm.
  3. Ограничивай права на загрузку eBPF-программ.
  4. Собирай enrichment: container ID, pod, namespace, image hash, host role.
  5. Строй автокорреляцию: exec → bpf_load → connect.
  6. Периодически ревизируй bpftool prog show и bpftool map show.
  7. Мониторь сенсоры, а не только то, что они должны детектить.

🧠 Итог

eBPF — это не просто ещё одна модная аббревиатура из мира Linux. Это слой, где у защитника появляется шанс увидеть атаку раньше, чем она дошла до привычных логов. Но и у атакующего появляется шанс спрятаться глубже, чем привыкли многие SOC’и.

Поэтому зрелый подход выглядит так:

  • понимать, что у тебя происходит на уровне ядра;
  • уметь начать хотя бы с auditd, если сенсоров пока нет;
  • дальше переходить к Falco, Tetragon или их комбинации;
  • и самое главное — собирать не отдельные события, а цепочки поведения.

Потому что один exec из /tmp — это ещё не конец света.
А вот exec → bpf_load → connect — уже вполне себе заявка на очень плохой день.


Финальные теги: ebpf, soc, linux, tetragon, falco, siem, incident-response, forensics, linuxsecurity, detection

Продолжение — в Telegram

Если материал был полезен, в канале есть короткая версия, обсуждение и новые тексты про SOC, incident response, процессы и безопасность без лишней косметики.

Перейти в Telegram →
← Более новая статья
Корпоративная аутофагия: как «эффективные менеджеры» съедают команды и добивают бизнес
22.04.2026
Более старая статья →
А что вообще требует рынок от SOC-специалистов?
09.04.2026