Перейти к содержимому

Анализ auth.log для расследования privesc: восстанавливаю цепочку по логам Linux без SIEM

Анализ auth.log для расследования privesc: восстанавливаю цепочку по логам Linux без SIEM
Время чтения: 13 мин.

75% вторжений в 2024 году начались с действительных учётных данных — CrowdStrike приводит эту цифру в Global Threat Report 2025. IBM X-Force фиксирует: число атак с валидными кредами выросло на 71% за год, а в Dark Web ежедневно всплывает более 6 000 свежих пар логин-пароль. Когда атакующий попадает на Linux-сервер с паролем из утёкшей базы, его действия в первые минуты неотличимы от обычного входа администратора. Подозрительным всё становится позже — когда в auth.log появляются строки sudo, смена UID и открытие сессий от root. На серверах без EDR (endpoint detection and response — агент, который следит за активностью прямо на хосте) и SIEM (система, которая собирает логи со всей инфраструктуры и ищет корреляции между ними) единственные свидетели — текстовый auth.log и бинарный wtmp. Ниже — пошаговый разбор: как из этих файлов восстановить полную цепочку privesc (privilege escalation — повышение привилегий) вручную, без готового таймлайна.

Зачем атакующему повышение привилегий и как это выглядит для аналитика

Атакующий, получивший initial access (первичный доступ) через SSH с украденным паролем, работает от имени обычного пользователя. Этого мало: он не прочитает /etc/shadow (файл с хэшами паролей всех учётных записей), не подправит cron и не положит бэкдор в системный каталог. Privesc нужен ради UID 0 — идентификатора root, который снимает все ограничения.

MITRE ATT&CK (открытая база тактик и техник атак; T-коды — её уникальные идентификаторы, по которым аналитики ссылаются на конкретные приёмы) классифицирует перебор паролей как технику T1110 — Brute Force (тактика Credential Access). Brute force — отправная точка: подобрав пароль, атакующий получает SSH-доступ. Дальше он повышает привилегии — и именно эти следы мы ищем в логах аутентификации.

Mandiant в M-Trends 2025 фиксирует: медианное время обнаружения злоумышленника — 11 дней. CrowdStrike уточняет: среднее время lateral movement (горизонтального перемещения по сети) после initial access — 62 минуты, рекорд — 51 секунда. Между первым SSH-входом и полным контролем над хостом может пройти меньше часа. Если мониторинга в реальном времени нет, расследование auth.log и wtmp после инцидента — единственный способ восстановить хронологию.

Артефакты аутентификации Linux: auth.log, secure и journalctl

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

Артефакт Путь Дистрибутивы Чем читать
auth.log /var/log/auth.log Debian, Ubuntu grep, awk
secure /var/log/secure RHEL, CentOS, Rocky, Fedora grep, awk
wtmp /var/log/wtmp Все last, utmpdump
btmp /var/log/btmp Все lastb
lastlog /var/log/lastlog Все lastlog
journal /var/log/journal/<machine-id>/ systemd (Ubuntu 18+, RHEL 8+) journalctl

auth.log и secure содержат одинаковые данные — различается только путь. Записи генерируют две подсистемы: демон SSH (sshd) и PAM (Pluggable Authentication Modules — модули, которые проверяют учётные данные, управляют сессиями и применяют политики). Один SSH-вход порождает несколько строк лога. Это не дубликаты — каждая строка от своего компонента одного процесса.

Четыре категории событий в auth.log, которые нужны при расследовании компрометации Linux:

  • Неудачные попытки — строки Failed password for... (видно brute force или подбор)
  • Успешные входы — Accepted password for... или Accepted publickey for... (момент получения доступа)
  • Открытие и закрытие сессий — pam_unix(sshd:session): session opened/closed (границы активности)
  • Смена привилегий — записи sudo: и su:, изменение EUID (Effective User ID — действующий идентификатор, по которому ядро решает, что процессу разрешено)

Для расследования privesc ключевые — последние два типа. По ним видно, когда обычный пользователь стал root.

Когда auth.log пуст — journalctl как основной источник

На современных дистрибутивах (Ubuntu 18+, Debian 11+, RHEL 8+) auth.log может оказаться почти пустым. Не спешите списывать это на зачистку атакующим — systemd-journald перехватывает поток событий, а rsyslog может не пересылать записи в текстовый файл (или вообще не быть установлен).

Реальные данные лежат в бинарных журналах: /var/log/journal/<machine-id>/system.journal. Текст внутри поля MESSAGE идентичен тому, что было бы в auth.log: Accepted publickey for admin from 10.0.1.50 port 52341 ssh2. Те же регулярные выражения работают, нужен только journalctl для извлечения.

Команда sudo journalctl -u ssh --since "2025-04-01" --until "2025-04-08" покажет SSH-события за период. При работе с монтированным образом: journalctl --directory=/mnt/evidence/var/log/journal/<machine-id>/.

Если на руках дамп хоста и auth.log пуст — проверяйте journal. Пропустить этот шаг — пропустить 100% следов аутентификации на системах с systemd.

Wtmp и btmp — анализ бинарных следов сессий

auth.log — текстовый файл, а wtmp, utmp и btmp — бинарные. Через cat их не откроешь: нужны last, lastb и utmpdump.

utmp (/var/run/utmp) хранит текущие активные сессии — то, что показывают who и w. При закрытии сессии запись уходит в wtmp.

wtmp (/var/log/wtmp) — кумулятивная история всех входов, выходов и перезагрузок. Главный артефакт для построения таймлайна сессий.

btmp (/var/log/btmp) — все неудачные попытки входа. Если знакомы с Windows — это аналог Event ID 4625.

last -f /var/log/wtmp выводит таблицу сессий: пользователь, терминал (pts/0, pts/1…), IP-адрес источника, время начала и конца, длительность. Типичная подозрительная строка — root pts/1 10.0.1.100 Mon Apr 7 03:15 - 03:17 (00:02): сессия root с внутреннего IP в 3 ночи, длительность 2 минуты. Это паттерн автоматизированного действия или быстрого ручного privesc с конкретной целью.

lastb -f /var/log/btmp покажет неудачные попытки. Множество записей с одного IP и разными именами пользователей — password spraying. Все попытки под одним именем root от одного IP — brute force (T1110). Всплеск неудачных попыток, а следом Accepted password в auth.log от того же адреса — brute force, перешедший в успешный доступ.

Сервисные аккаунты с интерактивным входом. lastlog показывает дату последнего входа для каждого системного пользователя. Если www-data, postgres или nobody показывают свежую дату — это серьёзный индикатор компрометации. Эти учётки в норме не имеют интерактивных сессий. Появление входа означает: атакующий эксплуатировал уязвимость веб-приложения с выходом в shell или подобрал пароль.

utmpdump /var/log/wtmp выдаёт расширенный формат с числовыми кодами типов записей (7 — вход, 8 — выход, 2 — загрузка). Полезна, когда last обрезает длинные имена пользователей или IP-адреса.

Анализ sudo логов: поиск следов повышения привилегий

Это ядро расследования. Записи sudo и su в auth.log — прямое свидетельство перехода между уровнями привилегий.

Apr  7 14:28:01 srv sudo:   admin : TTY=pts/0 ; PWD=/home/admin ; USER=root ; COMMAND=/bin/bash
Apr  7 14:28:01 srv sudo: pam_unix(sudo:session): session opened for user root(uid=0) by admin(uid=1001)
Apr  7 14:35:12 srv su[4521]: Successful su for root by admin
Apr  7 14:35:12 srv su[4521]: + pts/0 admin:root
Apr  7 14:35:12 srv su: pam_unix(su:session): session opened for user root(uid=0) by admin(uid=1001)

Разбор каждой строки:

Первая — пользователь admin выполнил sudo /bin/bash из каталога /home/admin, запросив выполнение от имени root. Поле TTY=pts/0 указывает на псевдотерминал: это интерактивная SSH-сессия, не cron-задание.

Вторая — PAM зафиксировала открытие sudo-сессии. uid=0 — root, uid=1001 — admin. Связка этих двух строк подтверждает факт повышения привилегий.

Третья-пятая — тот же пользователь использовал su (switch user) для перехода в root. PAM записала событие отдельно. Обратите внимание: su требует знания пароля root (в отличие от sudo, который использует пароль текущего пользователя).

Подозрительные паттерны в sudo-логах, которые указывают на privesc:

Нестандартные команды в COMMAND. Легитимный администратор обычно выполняет sudo systemctl restart nginx или sudo apt update. Если в логе — sudo /tmp/exploit, sudo python3 -c '...' или sudo awk 'BEGIN {system("/bin/sh")}' — это злоупотребление sudo-правами. Последний пример — техника из GTFOBins (каталог стандартных Unix-утилит, через которые можно повысить привилегии, если они разрешены в sudoers без ограничений). Через системный вызов из awk атакующий запускает произвольный shell с правами root.

Переход в root-shell без видимой причины. COMMAND=/bin/bash — переход в интерактивный shell root. Если это первое действие после SSH-входа нового пользователя — зачем root-shell, если задача перезапустить сервис?

Пользователь не в sudoers. auth.log зафиксирует: admin : user NOT in sudoers ; TTY=pts/0 ; COMMAND=/bin/bash. Само по себе это не privesc, но показывает разведку — атакующий проверяет, есть ли sudo-права. Несколько таких строк подряд с разными COMMAND — попытка нащупать разрешённые команды.

Нестандартный PATH в COMMAND. Вместо /usr/sbin/service в логе — COMMAND=/home/admin/.local/bin/service. Вероятна подмена PATH: атакующий создал вредоносный бинарник с именем системной утилиты в каталоге, приоритетном в переменной PATH.

Прямой su без sudo. Строка su[PID]: Successful su for root by admin без предшествующей sudo-записи означает: пользователь знал пароль root. Слабый пароль root, совпадение с кредами скомпрометированного аккаунта — или пароль вытащили из конфигов на том же хосте.

sudo с флагом -u и сервисной учёткой. USER=postgres вместо USER=root — переход в сервисный аккаунт для доступа к базе данных. Такой privesc менее очевиден, но даёт доступ к данным приложения.

Построение таймлайна инцидента вручную

Практический блок: восстановление цепочки privesc шаг за шагом. Предпосылки: доступ к файловой системе хоста (живой доступ или монтированный образ), права root или sudo для чтения auth.log, btmp и journal.

Шаг 1 — извлечение ключевых событий из auth.log

Задача: собрать все строки, связанные с аутентификацией и сменой привилегий, в хронологическом порядке.

grep -E "(Accepted|Failed|sudo:|su\[|session opened|session closed)" /var/log/auth.log \
  | awk '{print $1, $2, $3, $5, $0}' \
  | sort -k1,3

grep -E фильтрует строки по ключевым словам: успешный и неудачный вход, sudo, su, открытие и закрытие сессии. awk извлекает дату, время и имя процесса для упорядочивания. sort -k1,3 сортирует по первым трём полям (месяц, день, время).

Что вы увидите: хронологический список событий аутентификации. Цепочка privesc выглядит так: строка Accepted password for admin → через несколько минут → sudo: session opened for user root → далее session closed. Промежуток между входом и получением root — окно, в котором произошло повышение привилегий.

Если auth.log ротирован, проверьте архивы: zgrep -E "(sudo:|su\[)" /var/log/auth.log.*.gz ищет по всем сжатым копиям. На RHEL-системах замените путь на /var/log/secure. Оба файла пусты — переходите к journalctl: sudo journalctl -u ssh --no-pager | grep -E "(Accepted|Failed|sudo:|su\[)".

Шаг 2 — сопоставление с wtmp-сессиями

Задача: привязать sudo-события к конкретным SSH-сессиям и IP-адресам.

last -f /var/log/wtmp — находите сессии, совпадающие по времени с sudo-событиями из предыдущего шага. Критерий сопоставления — поле TTY. Если auth.log показывает TTY=pts/0 для sudo, а last отображает admin pts/0 10.0.1.50 Mon Apr 7 14:23 - 14:45 (00:22) — картина складывается: атакующий пришёл с IP 10.0.1.50, сессия длилась 22 минуты, privesc произошёл внутри неё.

Параллельно проверьте lastb -f /var/log/btmp — наличие неудачных попыток перед успешным входом. Всплеск Failed password от того же IP, который затем появляется в Accepted — подтверждение brute force как вектора initial access.

Как понять, что шаг выполнен правильно: у вас есть таблица с колонками «время — IP — пользователь — действие — TTY — длительность сессии». Это ваш ручной таймлайн инцидента.

Шаг 3 — корреляция с bash_history и crontab

Задача: определить, что атакующий делал после получения root.

cat /home/admin/.bash_history и cat /root/.bash_history — история команд покажет действия после privesc: загрузку файлов (wget, curl), изменение конфигурации, создание новых учётных записей (useradd).

Признаки зачистки истории — сами по себе артефакт. bash_history пуст, содержит unset HISTFILE, является символической ссылкой на /dev/null (проверка: ls -la ~/.bash_history) или содержит history -c — всё это подозрительно. Нормальные администраторы не чистят историю после каждого сеанса. Отсутствие истории — находка, а не тупик.

Механизмы persistence: crontab -l -u root, содержимое /etc/crontab, каталоги /etc/cron.d/ и /var/spool/cron/crontabs/. Новые задания, созданные в период активности атакующего (по временным меткам: stat /var/spool/cron/crontabs/root), — вероятный бэкдор.

Дополнительно просмотрите:

  • /etc/passwd — появление пользователей с UID 0 (второй root-аккаунт)
  • /root/.ssh/authorized_keys и /home/*/.ssh/authorized_keys — добавленные ключи для бэкдор-доступа без пароля
  • Файлы в /tmp, /dev/shm, /var/tmp — временные каталоги, где атакующие любят размещать инструменты

Финальная корреляция: bash_history содержит wget с внешнего адреса и chmod +x, а в cron обнаруживается запись с датой создания, совпадающей с sudo-сессией — цепочка замыкается: initial access (SSH) → privesc (sudo /bin/bash) → persistence (cron-бэкдор).

DFIR Linux сервера без EDR: компенсация пробелов

auth.log и wtmp — минимум, который есть почти на любом Linux-хосте. Но у этого минимума свои границы.

auditd (демон аудита ядра Linux). Если он был активен ДО инцидента, файл /var/log/audit/audit.log содержит записи с точными Unix-timestamps и структурированным форматом. Записи типа USER_AUTH и USER_LOGIN фиксируют аутентификацию с pid процесса — это позволяет привязать событие к конкретной SSH-сессии точнее, чем через TTY. На практике: на большинстве серверов auditd либо не установлен, либо работает с дефолтными правилами, которые не покрывают нужные системные вызовы.

SUID-бинарники. find / -perm -4000 -type f 2>/dev/null покажет все файлы с SUID-битом — правом выполнения от имени владельца (обычно root). Нестандартные SUID-файлы в /tmp, /home или /opt — вероятный инструмент privesc. Сравните список с эталоном свежей установки ОС.

Временные метки файловой системы на ext4 менее информативны, чем NTFS на Windows. Опция монтирования noatime отключает обновление времени доступа. В форензике аутентификации Linux логи первичнее файловых timestamps.

Ротация и сохранность логов. auth.log на дефолтных настройках Ubuntu ротируется еженедельно с хранением 4 файлов (около месяца). Если инцидент обнаружен позже — данные утрачены по расписанию, не действиями атакующего. Настройки ротации: /etc/logrotate.d/rsyslog.

AbuseIPDB. Если в ходе расследования нашли внешние IP-адреса — проверьте их через AbuseIPDB. Поле abuseConfidenceScore (0–100) показывает репутацию адреса: значение выше 75 — вероятный вредоносный источник. Tor exit nodes и CGNAT-адреса часто дают ложные срабатывания — учитывайте это.

OWASP в категории A09:2021 (Security Logging and Monitoring Failures) говорит прямо: без логирования нарушения невозможно обнаружить. Расследование инцидента без EDR — работа с тем, что осталось. Чаще всего остаётся ровно то, что описано выше: auth.log, wtmp и bash_history.

Девять из десяти расследований на Linux-серверах без EDR начинаются одинаково: grep "sudo" /var/log/auth.log. В семи случаях цепочка privesc видна в первые 15 минут работы. Не потому что атакующие неаккуратны — auth.log пишет всё, пока его не очистили целиком.

Проблема не в технике анализа. На большинстве серверов никто не заглядывает в auth.log до инцидента. auditd не настроен. Ротация агрессивная. К моменту расследования данные за нужный период могут быть уже удалены по расписанию — logrotate сработал раньше, чем SOC (Security Operations Center — центр мониторинга безопасности) заметил аномалию. Mandiant фиксирует медианное время обнаружения в 11 дней, а auth.log на дефолтной ротации Ubuntu хранится примерно 4 недели. Если инцидент замечен вовремя — данные есть. Если нет — аналитик работает с пустотой.

Отдельная боль — серверы на systemd без rsyslog. Я встречал случай: аналитик карвил auth.log с ext4-образа, нашёл пустой файл, написал в отчёте «следов компрометации не обнаружено». А journal с полной историей SSH-входов и sudo-сессий лежал рядом, в /var/log/journal/. Никто не проверил. Это не вопрос квалификации — вопрос чек-листа: auth.log, secure, journal — всегда все три, без исключений. Если разбираешь свой первый инцидент и хочешь закрыть базу по ИБ системно — на IB Basics показывают не теорию, а как джуны реально решают рабочие задачи.

Эту тему и смежные навыки разбирают на практике в курсе «Цифровая криминалистика и реагирование на инциденты (DFIR)» Codeby Academy.