Это вторая часть статьи про Linux Incident Response — разбор live response на работающем Linux-хосте с подозрением на компрометацию.

Если вы не читали первую часть, лучше начать с неё: в ней разобрали принципы расследования, изоляцию хоста, trusted toolkit, фиксацию исходного состояния, сетевые соединения и процессы. Без этого контекста часть команд и логика дальнейшего анализа будут менее понятны.

Первая часть здесь.

В этой части процесс идет далее — к менее изменчивым артефактам. Рассмотрим механизмы закрепления и следы на диске: systemd-сервисы и timers, cron, автозапуск, пользователи, группы, пакеты, логи, kernel-артефакты. В финале расскажем о построении таймлайна, оформлении IOC и действия с системой после завершения расследования.

Шаг 6. Службы и сервисы

sudo systemctl list-units --type=service --state=running

Даёт полный список запущенных сервисов. Задача — найти то, что не вписывается в нормальную активность системы. На тестовой машине среди запущенных сервисов один привлекает внимание: sysupdate.service с описанием «System Update Service». Звучит легитимно, но атакующие намеренно называют свои сервисы как системные, чтобы усложнить обнаружение.

systemctl status дает детали:

А unit-файл их подтверждает. Сервис в статусе enabled, а Restart=always. Это указывает на закрепление, поскольку если убить процесс вручную, systemd его перезапустит. Команда kill не даст результата. Main PID совпадает с тем что мы нашли через ss, в CGroup прямо видна команда nc -lp 4444.

В данном случае это просто listener. В реальных сценариях на этом месте можно было бы обнаружить ExecStart=/usr/bin/nc.traditional -l -p 4444 -e /bin/shbind shell, когда атакующий подключается к порту 4444 и получает командную строку.

journalctl -u sysupdate.service даст хронологию запуска для таймлайна инцидента.

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

systemctl list-timers --all

sudo find /etc/systemd/system -name "*.timer"

Шаг 7. Cronjobs

Задачи cron — классический способ закрепления. Задача выполняется автоматически по расписанию, не требует активного присутствия атакующего и легко теряется среди легитимных системных задач.

В Linux есть несколько мест с задачами для cron:

# Системный crontab

sudo cat /etc/crontab

# Пользовательские crontabs

sudo ls -la /var/spool/cron/crontabs/

sudo cat /var/spool/cron/crontabs/*

# Системные директории

sudo ls -la /etc/cron.d/

sudo ls -la /etc/cron.hourly/

sudo ls -la /etc/cron.daily/

sudo ls -la /etc/cron.weekly/

sudo ls -la /etc/cron.monthly/

# Содержимое всех файлов в cron.d

sudo grep -r "" /etc/cron.d/

#Анакрон

sudo cat /etc/anacrontab

В отличие от классического cron, Anacron гарантирует, что пропущенные из-за выключения или спящего режима компьютера задачи выполнятся при первом включении системы.

В /etc/crontab есть находка. Два отдельных правила для одного файла — @reboot запускает его при каждой загрузке системы, * * * * * запускает каждую минуту. Путь /tmp/.update достаточно тривиален, потому что /tmp/ доступен на запись всем, а точка в начале имени файла делает файл скрытым от обычного ls.

При проверке cron надо смотреть не только на содержимое записей, но и на временны́е метки и права файлов. ls -la показывает сразу оба артефакта. Дата последнего изменения /etc/crontab в подозрительное время — вклад в timeline инцидента.

Права доступа — отдельная история: /etc/crontab должен быть доступен на запись только root (-rw-r--r--). Если права шире — это либо misconfiguration, которую атакующий мог использовать для повышения привилегий, либо намеренное изменение чтобы закрепиться без root. То же касается файлов которые cron запускает: скрипт в /tmp/.update с правами rwxrwxrwx означает что любой пользователь системы может подменить его содержимое и получить выполнение от root через минуту.

Найденный подозрительный файл можно исследовать с помощью команд:

ls -la /tmp/.update

sha256sum /tmp/.update

strings /tmp/.update | grep -E 'https|bash|exec|curl|wget'

file /tmp/.update

Контрольная сумма пойдет в TI, strings даст представление о назначении файла и также данные для TI, ls -la покажет права и временну́ю метку. В нашем случае -rwxr-xr-x 1 root root, Jun 24 15:07 — файл создан в момент компрометации, принадлежит root, исполняемый. Поскольку файл вредоносный условно, вывод strings показывает sleep, nanosleep и легитимные URL GNU — это копия системного sleep, ничего вредоносного. На реально вредоносном файле здесь можно было бы найти IP-адреса C2, URL, имена функций типа execve, system, popen.

file дает тип — ELF 64-bit.

Шаг 8. Другие механизмы автозапуска

Это скрипты или команды, выполняемые автоматически при загрузке системы или входе пользователя в систему. Этим они отличаются от cron, которые запускаются по расписанию.

sudo ls -la /etc/init.d/

/etc/init.d/ — legacy-механизм запуска сервисов, предшественник systemd. На современных системах почти вытеснен, но проверять нужно.

sudo find /home -name "*.desktop" 2>/dev/null

Скрипты автозапуска для desktop-окружений. Выполняются когда пользователь логинится в систему.

На нашей машине в домашней директории пользователя backdoor обнаружен подозрительный файл. Поле Exec запускает скрипт из домашней директории пользователя backdoor. Изучим файл подробнее.

Каждый раз когда backdoor логинится в систему, будет скачиваться скрипт с внешнего сервера и выполняться в bash.

Удалённый адрес и название файла должно уйти в TI, а если адрес принадлежит другому хосту в инфраструктуре компании — это следующий кандидат на анализ.

sudo find /home \( -name ".profile" -o -name ".bashrc" \) | \ xargs grep -l "curl\|wget\|nc\|bash -i" 2>/dev/null

Файлы .bashrc и .profile выполняются автоматически при каждом открытии терминала или логине пользователя. Атакующий может дописать в конец любого из них вредоносную команду — и она будет выполняться незаметно каждый раз когда пользователь открывает терминал.

sudo find /home -name "authorized_keys" | xargs cat 2>/dev/null

~/.ssh/authorized_keys — этот файл содержит список публичных ключей которым разрешён SSH-доступ к аккаунту без пароля. Атакующий может добавить сюда свой ключ и получить вход в любое время, если конфигурация sshd разрешает аутентификацию по ключам.

Шаг 9. Пользователи, группы и привилегии

Использование учетных записей — еще один способ закрепления. Кроме того, при наличии достаточных привилегий у аккаунта атакующий способен значительно развить свой успех.

sudo cat /etc/passwd

/etc/passwd — первое место, где смотрим на пользователей. Формат каждой строки: имя:пароль:UID:GID:описание:домашняя_директория:shell. Нас интересуют пользователи с интерактивным shell (/bin/bash или /bin/sh) в первую очередь. С этими shell пользователь пригоден для интерактивной сессии — системные аккаунты намеренно ограничены /usr/sbin/nologin или /bin/false

Можно отфильтровать всех пользователей с реальным шеллом командой:

grep -v "nologin\|/bin/false\|/bin/sync" /etc/passwd

Backdoor — очевидно вредоносный аккаунт, встречавшийся ранее. В реальных инцидентах backdoor-аккаунты называют менее очевидно: support, svc-monitor, git и т.д.

Также надо обращать внимание на UID 0, кроме root:

awk -F: '$3 == 0 {print}' /etc/passwd

Следующий вопрос — какие привилегии у найденных аккаунтов. Смотрим на группу sudo в /etc/group:

sudo grep sudo /etc/group (sudo grep wheel для RHEL)

Заглянем в /etc/sudoers и /etc/sudoers.d

%sudo   ALL=(ALL:ALL) ALL

Означает, что каждый юзер в группе sudo может запускать команды от любого пользователя, включая root, после ввода своего собственного пароля.

Ещё одна проверка — /etc/shadow. Аккаунт может существовать в /etc/passwd но быть заблокированным: символы * или ! в поле пароля означают что войти по паролю невозможно. Команда, выводящая аккаунты с установленным паролем:

sudo awk -F: '$2 !~ /^[*!]/ {print $1}' /etc/shadow

Атакующий мог разблокировать существующий системный аккаунт вместо создания нового — это менее заметно чем новый пользователь.

Если подозрительный аккаунт был обнаружен, целесообразно проверит историю его входов через last. last читает /var/log/wtmp и показывает историю логинов. Неудачные попытки логина смотрим отдельно:

sudo last -f /var/log/btmp (или sudo lastb на RHEL)

Шаг 10. Пакеты, файловая система и артефакты приложений

grep " install " /var/log/dpkg.log

dpkg.log фиксирует каждую операцию с пакетами: установку, удаление, обновление — с точным временем. На тестовой машине видна масса легитимных пакетов установленных 2026-06-24 в процессе развёртывания системы. Но в самом конце списка — аномалия:

Два момента. Первый — имя пакета malware. В реальности атакующие называют их менее очевидно, но принцип тот же: пакет появившийся после начальной установки системы без явной причины — подозрителен. Если необходимо, поднимите заявки на установку ПО для анализируемого хоста, чтобы установить легитимность того или иного пакета.

Второй — дата 2024-06-24 при том что вся система установлена в 2026-06-24.

Далее нужно проверить недавно измененные файлы. Следует исключать из проверки /proc и /sys — там изменений всегда будет много. Команда:

sudo find / -mtime -3 -type f \

    -not -path "/proc/*" \

    -not -path "/sys/*" 2>/dev/null | head -30

-mtime -3 показывает файлы изменённые за последние 3 дня. Порог подбирается под контекст: если система работает месяц без обновлений, свежеизменённый файл в /usr/bin — немедленный флаг.

sudo find / -perm -4000 -type f 2>/dev/null

Эта команда ищет файлы с установленным SUID-битом. SUID-бит позволяет запускать файл с правами его владельца, а не запускающего пользователя. Нужно обращать внимание на SUID-файлы в нестандартных местах — /tmp, /home, /opt.

В нашем выводе два нестандартных файла: /mnt/usb/bin/sudo — наш trusted sudo, которому мы сами выставили бит, и /opt/VBoxGuestAdditions-7.0.26/bin/VBoxDRMClient — легитимный компонент VirtualBox.

sudo find /opt /tmp /var/tmp /home -name ".*" -type f 2>/dev/null

Поиск скрытых файлов в пользовательских директориях. Как известно, точка в начале названия файла делает файл скрытым от обычного ls. На некоторых серверах вывод может быть большой. Чтобы облегчить работу, можно использовать фильтры по времени -time и -min. 

Отдельный пункт — артефакты приложений. Поскольку приложений много, как пример здесь можно привести два артефакта: .viminfo и ~/.mozilla/firefox/ .

sudo find /home -name ".viminfo" 2>/dev/null

sudo find /home -type d -path "*/.mozilla/firefox" 2>/dev/null

.viminfo хранит историю команд в Vim. Также можно попытаться поискать подобные файлы для других текстовых редакторов: .nano_history и .emacs.

В реальном расследовании .bash_history и .viminfo могут содержать прямые следы действий атакующего: команды которые он выполнял, файлы которые редактировал, IP-адреса к которым подключался. Браузерные артефакты в ~/.mozilla/firefox/ или ~/.config/google-chrome/ — история посещений, загрузки, cookies — особенно ценны, если линуксовый хост — это десктоп, а не сервер.

Шаг 11. Логи

Первое, что нужно определить на незнакомой системе — какой механизм логирования используется. На Debian 13 по умолчанию установлен только systemd-journald без rsyslog. Это означает, что привычных /var/log/auth.log и /var/log/syslog не существует — все логи идут в бинарный journal и читаются через journalctl. На системах с rsyslog оба механизма работают параллельно. Итоговый набор источников логов зависит от политики логирования конкретной организации. Помимо journald и rsyslog на системе может быть настроен auditd. Если auditd настроен с правилами (/etc/audit/audit.rules) — это золотой источник для расследования. Короче говоря, первый шаг — выяснить, как работает логирование.

Аутентификация и управление пользователями

sudo journalctl _COMM=useradd --no-pager

sudo journalctl _COMM=sudo --no-pager

journalctl _COMM=useradd фильтрует все события создания пользователей. В нашем выводе хронология сразу показывает ивент:

Пользователь backdoor создан Jun 24 15:07:28 — вклад в таймлайн инцидента. Поле from показывает терминал с которого была выполнена команда. none означает что пользователь создан не интерактивно — скриптом или сервисом.

journalctl _COMM=sudo фиксирует все команды выполненные через sudo: пользователь, рабочая директория, точная команда.

Cron

sudo journalctl -u cron --no-pager

Journald подтверждает, что обнаруженный ранее /tmp/.update выполняется каждую минуту от root:

Сервисы

Поведение подозрительных сервисов можно посмотреть командой:

sudo journalctl -u sysupdate.service --no-pager

Некоторые службы не будут писать все свои сообщения в journald. Например, веб-сервер Apache не будет писать в journald по умолчанию, он пишет в собственные файлы в /var/log/apache2/. Эта директория будет содержать два файла: access.log и error.log. Просматривать эти файлы и файлы других подобных служб лучше через cat, less, или grep.

Другие способы фильтрации

Для фильтрации по времени через journald используйте различные флаги, такие как --since или -S и --until или -U:

sudo journalctl -S "2026-06-24 00:00:00" -U "2026-06-26 02:29:59"

Работает также более простой способ, с указанием «today», «yesterday», «N hours ago».

Важно помнить, что journald хранит временны́е метки в UTC внутри бинарного журнала. Но journalctl при выводе автоматически конвертирует в локальный часовой пояс системы.

Именно поэтому в начале расследования важна команда timedatectl — она показывает и системное время, и UTC. Тем не менее, можно вывести лог без поправки на часовой пояс с помощью флага --utc.

Хочется еще раз подчеркнуть важность понимания работы логирования перед просмотром журналов. Например, при настроенном auditd можно оперировать ausearch и aureport.

На rsyslog-системах логи ротируются и сжимаются: auth.log → auth.log.1 → auth.log.2.gz. Обычный grep не читает сжатые файлы — нужен zgrep:

# Поиск по всем логам включая архивные

zgrep -i "backdoor" /var/log/auth*

zgrep "session opened" /var/log/auth*

zgrep "Failed password" /var/log/auth*

Kernel-логи и признаки руткита ядра

В начале статьи упоминался kernel-level compromise. Например, атакующий мог внедрить свой kernel object (.ko) через insmod. Если он подтверждается — live response теряет смысл. Результаты любых команд могут быть искажены на уровне системных вызовов. Единственный надёжный путь — offline-анализ с загрузкой с внешнего носителя.

Можно попытаться установить факт такого вмешательства командами:

sudo journalctl -k | grep -i "module\|taint\|loading"

Ожидая вывод

kernel: loading out-of-tree module taints kernel.

kernel: module verification failed: signature and/or required key missing

Посмотреть все загруженные модули прямо сейчас:

lsmod

Подозрительный модуль можно изучить подробнее:

modinfo <имя_модуля>

Шаг 12. Построение таймлайна и сбор IOC

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

….

Jun 24 14:06 — установлены гостевые дополнения VirtualBox

Jun 24 15:07 — создан backdoor-аккаунт (from=none)

Jun 24 15:07 — установлен пароль для backdoor

Jun 24 15:07 — backdoor добавлен в группу sudo

Jun 24 15:07 — запущен sysupdate.service

Jun 24 15:07 — в /etc/crontab добавлены вредоносные записи

Jun 24 15:07 — создан /tmp/.update

Jun 24 15:07 — создан autostart-скрипт в /home/backdoor/

Jun 24 15:12 — сетевая изоляция хоста

….

Индикаторы компрометации оформляются в структурированный список:

# Файлы

SHA256(/tmp/.update)            = 0637e6d47579929cb72efa46f361861b...

# Аккаунты

Backdoor account: backdoor / UID=1002 / GID=1002 / sudo group

# Persistence

Service:  sysupdate.service — ExecStart=/bin/bash -c 'nc -lp 4444'

Cron:     @reboot root /tmp/.update

Cron:     * * * * * root /tmp/.update

Autostart: /home/backdoor/.config/autostart/dev-setup.desktop

# Сеть

Port:     TCP 4444 LISTEN

URL:      http://192.168.56.105/shell.sh

# Пакеты

Package:  malware:amd64 1.0 (2024-06-24 12:00:00)

Каждый из этих артефактов имеет конкретное применение. Хэши файлов загружаются в VirusTotal и проверяются по базам threat intelligence — если хэш известен, сразу становится понятно с каким инструментом или группой мы имеем дело. Хэши и строки вредоносных файлов становятся основой YARA-правил для threat hunting по другим хостам инфраструктуры. IP-адреса и домены блокируются на периметре. Паттерны поведения становятся корреляционными правилами в SIEM.

Шаг 13. Действия после IR

Систему нельзя просто вычистить и вернуть в эксплуатацию. Мы нашли backdoor-аккаунт, malicious service, cron-задачи, autostart-скрипт — но можем ли мы утверждать что нашли всё? Нет. Атакующий мог оставить десятый persistence механизм который мы не обнаружили. Именно поэтому третий принцип расследования, сформулированный в начале статьи, звучит так: цель IR — понять, а не вылечить.

Правильная последовательность действий после завершения расследования:

1.   Восстановление из резервной копии. Переразвёртывание системы из бэкапа сделанного до момента компрометации. Таймлайн даёт нам точку отсчёта: компрометация произошла в районе Jun 24 — значит, нужна резервная копия строго до этого времени. Бэкап после точки компрометации потенциально уже содержит артефакты атаки.

2.   Смена всех секретов. Пароли всех пользователей системы, SSH-ключи, API-токены, credentials сервисов которые были доступны с этого хоста. Атакующий мог прочитать их из памяти, конфигурационных файлов или истории команд. Ну и в целом, требуется проверка конфигурации системы. Вероятно, именно мисконфиг, типа дефолтного пароля, мог послужить причиной успешной атаки.

3.   Проверка соседних систем. Timeline показывает что атакующий работал с Jun 24 15:07. За это время он мог использовать скомпрометированный хост как плацдарм для атаки на другие машины в сети. Все системы к которым имел доступ этот хост — под подозрением.

4.   Усиленный мониторинг после восстановления. Собранные IOC загружаются в SIEM и EDR. Если атакующий вернётся — он будет обнаружен немедленно.

Мини-плейбук

0. Изолировать хост от сети (EDR / VLAN / NAC)

1. Подключить trusted toolkit, переключить PATH

2. Запустить script для логирования сессии

3. Зафиксировать состояние системы (uname, hostnamectl, timedatectl)

4. Сеть: ip a, ss -tulnp, ss -tunp

5. Процессы: ps aux, pstree, lsof

6. Сервисы: systemctl list-units --type=service --state=running

7. Cron: /etc/crontab, /var/spool/cron/crontabs/, /etc/cron.*

8. Autostart: /etc/init.d/, ~/.config/autostart/, ~/.bashrc, ~/.profile

9. Пользователи: /etc/passwd, /etc/group, /etc/sudoers, артефакты пользователей и приложений

10. Пакеты и файлы: dpkg.log, find -mtime, find -perm -4000

11. Логи: journalctl / auth.log / syslog / audit.log

12. Построить timeline, собрать IOC

13. Восстановить из бэкапа до точки компрометации

14. Сменить все секреты

15. Загрузить IOC в SIEM/EDR, проверить соседние хосты

Чего не делать:

Не перезагружать систему до завершения анализа волатильных данных

Не устанавливать пакеты через apt во время расследования

Не писать результаты на диск жертвы

Не возвращать систему в эксплуатацию


НЛО прилетело и оставило здесь промокод для читателей нашего блога:
-15% на заказ нового VDS — HABRFIRSTVDS.

Положение об акции

Комментарии (0)