SecureExec
Главная
Решения
ЦеныБлогО нас
ВойтиРегистрация
← Назад к блогу

Ловим эксплойты повышения привилегий в ядре Linux

24 октября 2026 г.

Большинство детектов повышения привилегий смотрят на парадную дверь: вызов sudo, syscall setuid, SUID-бинарь в домашнем каталоге, pkexec с пустым argv. Это ловит мисконфиги и злоупотребление инструментами, и это нужно делать — у SecureExec есть правила на всё перечисленное. Но эксплойт ядра не делает ничего из этого. Use-after-free в netfilter, out-of-bounds запись в io_uring, баг в ksmbd — он портит память ядра, пока не сможет выполнить один примитив, commit_creds(&init_cred), и вызывающий процесс мгновенно становится root. Ни setuid, ни SUID-бинаря, ни sudo. Детекты парадной двери не срабатывают — атакующий к двери и не подходил.

Поэтому мы смотрим на то, что эксплойт действительно меняет: учётные данные процесса в том виде, в каком их держит ядро. В статье — три отпечатка, которые оставляет LPE в ядре, почему нормальная активность их никогда не порождает и как мы провалидировали это на реальных ядрах.

Что на самом деле делает LPE в ядре

Как только у эксплойта есть примитив записи в память ядра, получение root — почти формальность. Техник немного, и все они заканчиваются одним и тем же небольшим набором состояний:

  • Перезаписать учётные данные текущей задачи. Классический payload — commit_creds(prepare_kernel_cred(NULL)) или, короче, указать cred задачи прямо на глобальный init_cred ядра. Все id становятся 0. Процесс — root, и он не выполнил ни одного syscall привилегий.
  • Перезаписать строку, которую ядро запускает как root. modprobe_path и core_pattern — это строки, которые ядро исполняет (как root, из контекста ядра), когда автозагружается модуль или процесс дампит core. Перезапиши строку, спровоцируй событие — и ядро запустит твой бинарь за тебя.
  • Злоупотребить call_usermodehelper напрямую. Ряд недавних LPE (ksmbd, серия багов в netfilter) заставляют ядро породить helper по выбору атакующего. Результат тот же: root-процесс, родитель которого — само ядро.

Ни один из этих путей не порождает syscall setuid, SUID-exec или процесс sudo. EDR, смотрящему только на syscall'ы, не на что реагировать. Но каждый оставляет структурный след, которого на нормальной системе не бывает.

Отпечаток 1: указатель cred, который смотрит на init_cred

Легитимный userspace-процесс никогда не разделяет init_cred. На каждом fork ядро вызывает prepare_creds() — отдаёт потомку свежую копию учётных данных, а не глобальный объект. &init_cred держит только idle-задача, и твой shell она не запускает.

Поэтому проверка точная: на execve читаем указатель cred текущей задачи и сравниваем с init_cred ядра. Если они равны — что-то перезаписало учётные данные этой задачи, отпечаток commit_creds(&init_cred). Агент читает адрес init_cred из /proc/kallsyms, а смещение task->cred — из собственного BTF ядра, так что захардкоженных смещений нет; это работает между версиями ядра и само отключается (а не гадает) на ядре, где нет ни того, ни другого. Это правило cred_tamper, срабатывает critical.

Отпечаток 2: root, которым нельзя было стать

Проверка указателя точная, но узкая. Более широкий сигнал — поведенческий: процесс, который UID 0 на момент execve, но

  • не запускал setuid-root бинарь (ядро фиксирует setuid-бит на диске, и его нет), и
  • не делал syscall setuid/setreuid/setresuid, и
  • имеет родителя, которого SecureExec зафиксировал работающим под не-root пользователем.

Root-shell, появившийся под не-root родителем, без setuid-бинаря и без setuid-вызова между ними, не получил root ни одним механизмом, который предлагает система. Он получил его в ядре. Это silent_privilege_escalation — оно ловит перезапись учётных данных, которую cred_tamper пропустит (эксплойт, обнуляющий cred->uid на месте, а не подменяющий весь указатель), и опирается на родословную процессов, которую SecureExec и так отслеживает, так что лаунчеры sudo, su, pkexec и контейнерные рантаймы исключены по построению.

Отпечаток 3: ядро запускает программу, которую не должно

Техники modprobe_path / core_pattern / call_usermodehelper объединяет один родитель — ядро. Родитель usermodehelper'а — это kthreadd (PID 2) или kworker, а не init, не shell и не сервис.

Ядро легитимно порождает лишь небольшой фиксированный набор helper'ов: modprobe, request-key, key.dns_resolver, обработчик coredump и ещё несколько — всегда из системного каталога. kernel_spawned_process срабатывает, когда ядро запускает что-то ещё: бинарь из /tmp, shell, helper из пользовательского каталога. Это ровно та форма, которую оставляет перезапись modprobe_path, и LPE в ksmbd и netfilter последних лет заканчиваются именно здесь.

Почему нормальная активность это не триггерит

Для правила с severity critical значим именно false positive, поэтому каждое из них построено на инварианте ядра, а не на эвристике:

  • cred_tamper — это точное равенство указателей с init_cred, а ядро структурно никогда не отдаёт этот указатель userspace-процессу.
  • silent_privilege_escalation требует отсутствия сразу всех легитимных путей к root — setuid-бинаря, setuid-syscall, привилегированного родителя — что совпадает только когда ничего из этого не было.
  • kernel_spawned_process — это allowlist собственных helper'ов ядра; всё вне него по определению не то, что ядро поставляет.

Мы не принимаем это на веру. Мы прогнали агент на реальном хосте Ubuntu 24.04 (ядро 6.8) под несколькими сотнями обычных запусков процессов — shell'ы, id, date, пакетные инструменты, всё подряд — и проверка учётных данных сработала ноль раз на 353 execve. Она загорается только на том, чего само по себе случиться не может. И поскольку вся проверка идёт от tracepoint на execve, ей не нужен BPF-LSM — она работает на стоковых дистрибутивах, где bpf нет в активном списке LSM, а это большинство из них.

Что это даёт вашему SOC

Детекты повышения привилегий «с парадного входа» — злоупотребление sudo, SUID-дропы, PwnKit, GTFOBins — говорят, когда кто-то прошёл по собственным путям эскалации системы. Эти три правила говорят, когда кто-то их полностью обошёл и взял root в ядре. Это разница между тем, чтобы поймать мисконфиг, и тем, чтобы поймать 0-day, применённый против вас.

Они ничего не стоят, когда не могут разрешить свои смещения (тихо остаются выключенными), не дают false positive на нагруженном хосте и превращают самый тихий и самый опасный шаг вторжения — тот, к которому большинство endpoint-инструментов слепы, — в critical-алерт с полным деревом процессов.

Разбор на вашей инфраструктуре — запросите демо. Мы запускаем на реальном Linux-хосте, без слайдов.

SecureExec

SecureExec — Linux-first EDR для детекции, расследования и реагирования на инциденты на серверах. Cloud или self-hosted.

Продукт
  • Цены
Компания
  • О нас
  • Блог
  • Связаться с отделом продаж
  • Поддержка
Аккаунт
  • Войти
  • Регистрация
Правовая информация
  • Политика конфиденциальности
  • Условия использования

© 2026 SecureExec. Все права защищены.

Built with Rust & Next.js