Уязвимость systemd-journald и CVE: как злоумышленник чистит логи Linux до прихода DFIR

На расследовании инцидента в хостинг-провайдере я обнаружил странную вещь: за два часа до прибытия нашей команды атакующий точечно вычистил записи из journal-файлов systemd-journald. Сервис перезапустился штатно, на первый взгляд всё выглядело нормально. Единственная зацепка — расхождение между размером .journal-файла и количеством записей: файл оказался подозрительно мал для двухнедельного окна ротации. Уязвимости в journald известны с 2018 года (CVE-2018-16864, CVE-2018-16865, CVE-2018-16866 — systemd вплоть до версии 240), а в сентябре 2026 бюллетень безопасности РЕД ОС зафиксировал CVE-2026-29111 в systemd (CVSS 5.5 MEDIUM, NVD-присвоенный CWE-269 — Improper Privilege Management; NVD формально присвоил CWE через призму privilege management, хотя технический примитив на версиях ≤249 — stack memory corruption; фактически — DoS через assert/freeze; на версиях ≤249 возможна перезапись стека, с v250 — только assert). Поверхность атаки не сужается, а техники очистки логов Linux становятся всё аккуратнее.
Зачем атакующему уничтожать журналы systemd-journald
systemd-journald — демон журналирования в составе systemd. Если вы только начинаете разбираться в Linux: systemd — система инициализации, которая управляет запуском сервисов на большинстве современных дистрибутивов. journald собирает сообщения от ядра, системных сервисов, приложений и пользователей и сохраняет всё в бинарных .journal-файлах. Для DFIR-специалиста (Digital Forensics and Incident Response — цифровая криминалистика и реагирование на инциденты) журналы journald — первый и часто единственный источник хронологии атаки на Linux-хосте.
Мотивация злоумышленника конкретна: если из логов исчезнут записи о SSH-сессиях, запусках подозрительных процессов, изменениях конфигурации — расследование замедлится на часы или дни. В терминологии MITRE ATT&CK (открытая база тактик и техник атак; T-коды вроде T1070 — идентификаторы конкретных техник) зачистка логов — техника Indicator Removal (T1070, тактика Defense Evasion). Нюанс: хотя MITRE ATT&CK описывает T1070 как платформонезависимую технику, публичные тесты Atomic Red Team для базовой T1070 доступны только для Windows. Для Linux-специфичных сценариев очистки логов применима субтехника T1070.002 (Clear Linux or Mac System Logs), и вот для неё Atomic Red Team уже предоставляет тесты. Это целенаправленное уничтожение улик, напрямую влияющее на способность SOC-команды (Security Operations Center — центр мониторинга безопасности) восстановить цепочку атаки.
По классификации OWASP Top 10 (2021) проблема попадает под A09:2021 — Security Logging and Monitoring Failures: если логи скомпрометированы, нарушения невозможно обнаружить ни в реальном времени, ни ретроспективно.
Бизнес-логика атаки укладывается в три шага. Атакующий получает доступ к хосту (initial access), повышает привилегии до root — например, через Exploitation for Privilege Escalation (T1068; MITRE ATT&CK описывает эту технику как применимую к Linux, Windows и macOS, хотя публичные тесты Atomic Red Team для T1068 доступны только для Windows) — выполняет целевые действия, а перед уходом уничтожает или модифицирует журналы. По данным CrowdStrike Global Threat Report 2025, среднее время от первичного доступа до lateral movement в 2024 году составило 62 минуты (рекорд — 51 секунда). За это время атакующий успевает и отработать, и убрать за собой.
Как journald хранит данные: ликбез для начинающего форензика
Прежде чем разбирать техники антифорензики Linux, нужно понять, что именно атакующий ломает.
Journald пишет в бинарные .journal-файлы, а не в текстовые (в отличие от классического syslog). Хранилища два:
/var/log/journal/<machine-id>/— постоянное хранилище, переживает перезагрузку/run/log/journal/<machine-id>/— временное хранилище в RAM, исчезает при ребуте
Каждый journal-файл содержит заголовок с метаданными: версия формата, идентификатор машины, размер, состояние (ONLINE, OFFLINE, ARCHIVED) и контрольные суммы. Записи внутри файла — объекты с полями: _PID, _UID, _COMM (имя процесса), MESSAGE, временная метка с точностью до микросекунд.
Для просмотра журналов используется утилита journalctl. Например, journalctl -u sshd --since "2026-01-01" покажет записи сервиса SSH с начала года. Команда journalctl --disk-usage выведет объём занятого хранилища. Бинарный формат не позволяет парсить журналы через grep или cat напрямую — это одновременно плюс (структурированные данные, встроенные метаданные) и минус (если файл повреждён, стандартные средства не помогут — приходится разбирать байт за байтом через Python-скрипты).
Ротация и vacuum
journald автоматически удаляет старые записи по настройкам в /etc/systemd/journald.conf: SystemMaxUse (максимальный размер хранилища), SystemMaxFileSize (максимальный размер одного файла), MaxRetentionSec (максимальный срок хранения). Запомните эти параметры — они одновременно и механизм управления дисковым пространством, и потенциальный вектор антифорензики. Дальше увидите почему.
Уязвимости systemd-journald: разбор CVE-2018-16864, CVE-2018-16865, CVE-2018-16866
Системные уязвимости в journald позволяют атакующему получить привилегии самого демона журналирования. Три CVE, обнаруженные исследователями Qualys в январе 2019 года, затрагивают systemd вплоть до версии 240.
CVE-2018-16864: переполнение стека через syslog (CVSS 7.8 HIGH)
Программа с длинными аргументами командной строки (несколько мегабайт) вызывает syslog — journald падает из-за неконтролируемого выделения памяти. Классификация — CWE-770 (Allocation of Resources Without Limits or Throttling). Стек сталкивается с соседней областью памяти (stack clash), атакующий получает контроль над указателем выполнения.
CVSS-вектор CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H — расшифрую для тех, кто ещё не набил руку на чтении этих строк: AV:L — атака локальная (нужен shell на машине); AC:L — сложность низкая; PR:L — достаточно обычного пользователя; UI:N — действия жертвы не требуются; S:U — область воздействия не выходит за пределы уязвимого компонента (journald); C:H/I:H/A:H — полный ущерб конфиденциальности, целостности и доступности.
Уязвимость появилась в 2013 году (systemd 203), стала эксплуатируемой с версии 230 (февраль 2016). EPSS (Exploit Prediction Scoring System — оценка вероятности, что уязвимость начнут эксплуатировать в ближайшие 30 дней) на октябрь 2026 — 0.0071 (percentile 52%, выше медианы). Интерес сохраняется.
Патчи: Debian — DSA-4367-1 (systemd 232-25+deb9u7 для stretch); Ubuntu — USN-3855-1 (январь 2019); Red Hat — RHSA-2019:0049 для RHEL 7 (systemd 219-62.el7_6.2). RHEL 8 не затронут.
CVE-2018-16865: переполнение через journal socket (CVSS 7.8 HIGH)
Аналогичная проблема (CWE-770), но другой вектор: атакующий отправляет огромное количество записей в /run/systemd/journal/socket. Часть сообщения выходит за пределы стека и попадает в область mmap, что позволяет перезаписать сегмент read-write библиотеки libc и выполнить произвольный код с привилегиями journald.
Критичная деталь: если используется systemd-journal-remote (приём журналов по сети), эксплуатация CVE systemd возможна удалённо. EPSS — 0.0302 (percentile 87%) — значительно выше медианы.
По данным Qualys (цитируемым opennet.ru и habr.com), комбинация CVE-2018-16865 и CVE-2018-16866 позволяла получить root за 10 минут на i386 и 70 минут на amd64 (проверено на Debian 9.5).
CVE-2018-16866: чтение за пределами буфера (CVSS 3.3 LOW)
Ошибка в парсере syslog-сообщений: CWE-125 (Out-of-bounds Read) и CWE-200 (Exposure of Sensitive Information). Если отправить journald сообщение, заканчивающееся двоеточием :, парсер отбросит завершающий нулевой байт \0, и в лог попадёт фрагмент памяти за пределами буфера. Само по себе не критично, но раскрывает адреса стека и mmap — а это именно та информация, которая нужна для обхода ASLR при эксплуатации CVE-2018-16865.
Уязвимость существовала с systemd 221 (2015) по systemd 239. Случайно закрыта в systemd 240 — да, бывает и так.
Антифорензический потенциал
Зачем атакующему эксплуатировать journald? Ответ — привилегии. journald работает от systemd с правами root. Эксплуатация CVE-2018-16865 даёт исполнение кода от имени демона, а это: прямой доступ к journal-файлам на запись, возможность модифицировать бинарные структуры без вызова journalctl и создание «окна тишины» — периода, когда демон не работает и события не записываются.
В 2026 году systemd продолжает получать CVE. По данным бюллетеня РЕД ОС, в сентябре 2026 зафиксирована CVE-2026-29111 в systemd (CWE-269, CVSS 5.5 MEDIUM, влияние ограничено DoS — отказ в обслуживании через assert/freeze). Также зафиксирована CVE-2026-16742 — уязвимость повышения привилегий в systemd-homed через добавление пользователя в произвольную системную группу (CWE-269, CWE-347 — Improper Verification of Cryptographic Signature; CVSS 6.7 MEDIUM, согласно NVD). Поверхность атаки systemd не сужается, а journald остаётся целью для удаления логов злоумышленником.
Антифорензика Linux: техники очистки логов journald
Все техники ниже требуют root-доступа на хосте (полученного, например, через T1068 — Exploitation for Privilege Escalation, тактика Privilege Escalation в MITRE ATT&CK; техника применима к Linux, хотя тесты Atomic Red Team для неё доступны только для Windows).
Прямое удаление journal-файлов. Самый грубый подход: rm -rf /var/log/journal/*. После этого journald создаст новые файлы, но история утеряна. Грубо, но работает — если DFIR-команда не проверяет inode-метаданные файловой системы.
Штатные средства vacuum. journald сам предоставляет механизмы очистки — и вот это по-настоящему коварно. Команда journalctl --vacuum-time=1h удалит записи старше часа. journalctl --vacuum-size=10M удалит архивные (ARCHIVED) journal-файлы, пока их суммарный размер не опустится ниже 10 мегабайт; активный (ONLINE) файл при этом не затрагивается, поэтому итоговый размер хранилища может превышать указанный порог. Если всё хранилище занимает один активный файл, vacuum-size не даст эффекта, пока не произойдёт ротация. С точки зрения файловой системы — легитимная операция, без повреждённых заголовков и подозрительных паттернов. Отличить от плановой ротации сложно, и именно поэтому техника опасна.
Модификация конфигурации ротации. Атакующий меняет /etc/systemd/journald.conf: ставит SystemMaxUse=1M и MaxRetentionSec=1h, затем перезапускает journald через systemctl restart systemd-journald. Журналы легитимно ротируются, нужные записи исчезают. След минимален — только изменение конфигурационного файла.
Краш демона journald. Эксплуатация CVE-2018-16864 или аналогичных уязвимостей для принудительного падения демона. Пока journald не работает, события не записываются — «окно тишины». Если атакующий выполняет целевые действия в этом окне (exfiltration, lateral movement), записей о них просто не будет.
Затопление логов (log flooding). Вместо удаления — генерация огромного объёма мусорных записей через цикл с утилитой logger или прямую запись в journal socket. Если SystemMaxUse ограничен (типично для серверов), легитимные записи вытесняются ротацией. По данным одного из академических исследований производительности tamper-evident logging систем, такие системы могут терять значительную часть записей при высокой нагрузке — log flooding эксплуатирует именно этот механизм.
Детектирование очистки логов systemd: делай раз, делай два, делай три
Практический блок для DFIR-расследования Linux. Предпосылки: доступ к исследуемому хосту с правами root, установленный journalctl (есть по умолчанию на systemd-дистрибутивах).
Шаг 1: проверка целостности journal-файлов. Запустите journalctl --verify. Команда проверяет контрольные суммы каждого объекта в каждом .journal-файле. Ожидаемый вывод — строка PASS для каждого файла. Видите FAIL — файл модифицирован или повреждён. Конкретное сообщение укажет, какой объект не прошёл проверку. Это первое, что я делаю при выезде на инцидент.
Шаг 2: поиск временных разрывов. Выполните journalctl --list-boots — команда покажет все зафиксированные загрузки системы с датами. Если хост работал непрерывно (проверьте через uptime), а в списке видны пропуски между boot-записями — индикатор перезапуска journald или удаления файлов. Дальше прицельно проверяйте записи ядра: journalctl -k --output=short-precise | head -50 и tail -50. На работающем сервере пробелы свыше 5–10 минут между записями ядра — аномалия, которая требует объяснения.
Шаг 3: проверка метаданных файлов на диске. Команда stat покажет время создания (Birth), модификации (Modify) и доступа (Access) для каждого journal-файла. Если дата создания — сегодня, а хост работает месяцами — индикатор пересоздания файла (удаление старого + создание нового journald при рестарте).
# Проверка целостности и поиск аномалий в journal-файлах
journalctl --verify 2>&1 | grep -E "FAIL|PASS"
journalctl --list-boots
stat /var/log/journal/*/system.journal | grep -E "Birth|Modify"
Ожидаемый результат при чистой системе: только строки PASS, список boot-записей без пропусков, даты файлов соответствуют uptime. Любое отклонение — повод копать глубже.
Шаг 4: перекрёстная проверка с wtmp и auditd. journald — не единственный источник. Файл /var/log/wtmp (бинарный, читается через утилиту last) хранит историю логинов независимо от journald. /var/log/btmp (читается через lastb) — неудачные попытки. Если в wtmp есть SSH-сессия, а в journald записи о ней отсутствуют — логи journald были почищены.
# Перекрёстная проверка: логины в wtmp против journald
last -F | head -20
journalctl -u sshd.service --since "2026-09-01" --until "2026-10-01" | wc -l
Если last показывает сессии, а journalctl по sshd за тот же период пуст — красный флаг. Проверяйте также /var/log/audit/audit.log (если auditd настроен) и /var/log/auth.log (если параллельно работает rsyslog).
Шаг 5: мониторинг через Sigma-правила. В репозитории SigmaHQ (github.com/SigmaHQ/sigma — набор универсальных правил детектирования, которые можно конвертировать в формат вашего SIEM) есть правило lnx_buffer_overflows.yml для обнаружения признаков переполнения буфера в Linux-системах. Правило lnx_shell_susp_commands.yml ловит общие паттерны подозрительных shell-команд (T1059.004), однако специализированного правила для детекции именно journalctl --vacuum или аналогичных команд очистки журналов в публичном репозитории SigmaHQ на момент написания нет. Для конвертации Sigma-правил в формат конкретного SIEM используется sigma-cli или pySigma.
Защита логов journald от удаления злоумышленником
Forward-Secure Sealing (FSS)
journald поддерживает криптографическое запечатывание записей — Forward-Secure Sealing. Суть: демон периодически подписывает накопленные записи, после чего «забывает» текущий ключ и генерирует новый. Даже если атакующий получит актуальный ключ, он не сможет модифицировать старые записи, потому что ключи, которыми они подписаны, уже уничтожены. По данным Netdata (netdata.cloud), FSS обеспечивает Integrity (обнаружение любой модификации) и Authenticity (подтверждение подлинности записей).
Включить несложно: выполните journalctl --setup-keys. Команда сгенерирует пару ключей и выведет verification key — его нужно сохранить на отдельном носителе или в защищённом хранилище. В файле /etc/systemd/journald.conf установите Seal=yes и перезапустите journald. Проверка запечатанных логов: journalctl --verify-key=<ваш-verification-key>. Если записи модифицированы после запечатывания, команда покажет момент нарушения целостности.
Удалённое хранение журналов
Если логи копируются на отдельный сервер в реальном времени, локальная очистка логов Linux не уничтожает все улики. systemd-journal-remote принимает журналы по HTTPS и складывает в отдельное хранилище. На сервере сбора запускается systemd-journal-remote, на клиенте — systemd-journal-upload с указанием URL. Альтернатива для существующей инфраструктуры — пересылка через rsyslog или syslog-ng на удалённый коллектор (параметр ForwardToSyslog=yes в journald.conf).
Момент, который часто упускают: если используется systemd-journal-remote, убедитесь, что версия systemd на принимающей стороне не подвержена CVE-2018-16865 — эта уязвимость позволяет удалённую атаку именно через journal-remote.
auditd как второй источник
auditd (Linux Audit Framework) работает на уровне ядра и пишет в /var/log/audit/audit.log независимо от journald. Настройка мониторинга journal-файлов:
# /etc/audit/rules.d/journal-protect.rules
-w /var/log/journal/ -p wa -k journal_tamper
-w /etc/systemd/journald.conf -p wa -k journald_conf_change
Первое правило отслеживает запись (w) и изменение атрибутов (a) в каталоге журналов. Второе — изменение конфигурации journald. Ключ -k позволяет быстро фильтровать: ausearch -k journal_tamper. Что произойдёт при попытке удалить или изменить journal-файл: auditd зафиксирует PID процесса, UID пользователя и точное время. Даже если атакующий почистит journald — записи auditd об этих действиях останутся в отдельном файле.
Для полноты: из D3FEND (MITRE-база защитных техник, которая маппит ATT&CK-техники на контрмеры) контрмера D3-FIM (File Integrity Monitoring) напрямую применима к journal-файлам. Инструменты: AIDE, OSSEC, Wazuh или встроенные средства SIEM. D3-SFCV (Stack Frame Canary Validation) и D3-SAOR (Segment Address Offset Randomization) помогают защитить сам процесс journald от эксплуатации уязвимостей класса CVE-2018-16864/65.
За восемь лет с публикации CVE-2018-16864/65/66 systemd-journald получил патчи, FSS стал стабильнее, среда мониторинга Linux выросла. Но на практике мало кто из администраторов включает FSS, настраивает удалённое хранение или мониторит целостность journal-файлов через auditd. На расследованиях я регулярно вижу одну и ту же картину: journald в дефолтной конфигурации, FSS выключен, удалённого логирования нет, auditd стоит с базовыми правилами. Атакующему достаточно выполнить journalctl --vacuum-time=1h — и половина улик исчезает совершенно легитимно, без единого FAIL в проверке целостности.
NIST CSF v2.0 в подкатегории DE.AE-01 прямо указывает: baseline ожидаемых данных для пользователей и систем должен быть установлен и управляем. Без целостных журналов этот baseline невозможен.
Проблема не в уязвимостях. CVE-2018-16864/65/66 давно пропатчены на поддерживаемых дистрибутивах. Проблема в том, что journald по умолчанию не защищён от собственного администратора или атакующего с root. FSS — три команды для настройки, но в проде за пределами финтеха я встречаю его крайне редко. Удалённое хранение — ещё проще, но даже хостинг-провайдеры с тысячами серверов полагаются на один локальный journald. Когда атакующий получает root (а 62 минуты от initial access до lateral movement — это среднее, не максимум), первое, что он сделает — уберёт за собой. Если защита логов не настроена до инцидента, DFIR-команда придёт на чистую систему с нулём артефактов. На курсе IB Basics учат не «что такое CIA-triad», а как делать первые задачи в SOC / blue team — включая работу с логами, от которой зависит весь дальнейший анализ.
Эту тему и смежные навыки разбирают на практике в курсе «Цифровая криминалистика и реагирование на инциденты (DFIR)» Codeby Academy.
