Как сисадмин Алексей ловил хакера на своем сервере Linux

Как сисадмин Алексей ловил хакера на своем сервере Linux

14:37. Пятница.

Алексей, системный администратор с трёхлетним стажем, чуть не пролил кофе. На мониторе его сервера маячил процесс... которого просто не могло быть.

Он знал свои сервера как свои пять пальцев. Каждый процесс, каждая служба – всё было под контролем. Но этот экземпляр был чужим.

Файл назывался systemd-update. Легитимное имя, да и расположение в /tmp не вызывало сразу подозрений. Но Алексей чувствовал: что-то не так. Как если бы вы нашли чужую зубную щётку в своей ванной. Вроде ничего криминального, но душа не на месте.

Он попробовал удалить файл. Ошибка: «Файл занят».

Тогда Алексей ввёл команду:

ps aux | grep systemd-update

Его опасения подтвердились. Процесс висел в фоне и работал.

Может, сетевой мониторинг прольет свет?

sudo nethogs

Алексей увидел, как процесс systemd-update отправляет данные на внешний IP-адрес. Куда? Зачем? Кто это запустил?

«Чёрт возьми, что за хрень?! – вырвалось у него. – Куда он шлёт данные, зараза такая?»

Алексея осенило: обычного багажа системного администратора здесь маловато. Понадобится кое-что серьезнее.

В этой статье расскажу, как Алексей разоблачил systemd-update и другие подозрительные программы, а также какие инструменты использовал. А под конец – спойлер: всё оказалось не совсем тем, чем казалось.

Шаг 1. Инструмент file: определяем тип файла

Первый вопрос, который задал себе Алексей: «Что это за файл?»

В Linux для этого есть команда file. Она смотрит на магические числа – уникальные сигнатуры в начале файла, которые работают как отпечатки пальцев.

file systemd-update

Вывод Алексея:

systemd-update: ELF 64-bit LSB pie executable, x86-64, dynamically linked, stripped

Это не скрипт и не лог. Это настоящая программа.

Вывод: не верьте расширениям в Linux. Всегда проверяйте магические байты.

Шаг 2. Инструмент strings: строки внутри файла

Алексей видел подозрительный трафик. Значит, программа должна знать, куда отправлять данные. Где-то внутри неё зашит IP-адрес или домен.

Для их поиска может иногда помочь команда strings. Она вытаскивает из бинарника все читаемые текстовые строки. Но их может быть тысячи, поэтому для поиска IP-адреса Алексей отфильтровал результат через grep:

strings systemd-update | grep -E '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+'

Он нашёл IP-адрес. Потом так же нашел домен.

Но настоящая находка была в другом. Вот что ещё показал strings:

cp chmod +x /tmp/ > /dev/null 2>&1 & GET / HTTP/1.1 Host: example.com /proc/self/exe

Даже не запуская программу, Алексей понял: она копирует себя в /tmp, делает файлы исполняемыми, запускает процессы в фоне и ходит по сети.

Очень подозрительно.

Шаг 3. Инструмент xxd: просмотр шестнадцатеричного кода

Но что, если строки зашифрованы? Или злоумышленник вшил один файл в другой?

Алексей взял обычную картинку landscape.png с того же сервера. Запустил file, который тоже определил его как PNG. Но Алексей решил проверить глубже. Он запустил поиск сигнатуры ELF-файла внутри этой картинки:

grep -obUaP "\x7f\x45\x4c\x46" landscape.png

Вывод:

597482:ELF 612199:ELF

Внутри обычной PNG-картинки были спрятаны две ELF-программы.

Алексей дополнительно посмотрел на них через xxd – инструмент, который показывает hex-дамп:

xxd -l 64 landscape.png

Первые байты: 89 50 4e 47 – это сигнатура PNG. Всё чисто. Но на смещении 597482 начиналось уже 7f 45 4c 46 – сигнатура ELF.

Вывод: xxd позволяет увидеть то, что скрыто от глаз. А grep помогает найти спрятанное в любом файле, если знать что искать.

Шаг 4. Инструмент dd: извлечение фрагмента программы

Найти – это еще полдела. Как извлечь эти программы из картинки? Алексей использовал инструмент dd для побайтового копирования.

dd if=landscape.png of=program.bin bs=1 skip=597482

Пока Алексей не знал как определить точный размер файла, поэтому скопировал данные с запасом: от сигнатуры и до конца файла landscape.png.

Когда он извлёк программу и запустил file, та показала корректный ELF. Программа ожила.

Шаг 5. Инструмент readelf: анализ структуры ELF-файла

Теперь у Алексея была программа. Но где она заканчивается? Как узнать точный размер?

Для этого нужно понимать структуру ELF (Executable and Linkable Format) – стандартного формата программ в Linux.

Алексей запустил readelf -h program.bin и увидел заголовок. В выводе он нашел строки:

Начало заголовков раздела: 12720 (байт в файле) Number of section headers: 31 Size of section headers: 64 (bytes)

Так Алексей смог вычислить точный размер вшитой первой программы:

size = 12720 + (64 * 31) = 14704 байта

Затем точно так же вычислил размер второй программы.

А потом Алексей заглянул в секцию .rodata, где хранятся строки:

readelf -p .rodata program.bin

Оттуда вылезли всё те же GET / HTTP/1.1, example.com, /tmp/...

Вывод: инструмент readelf быстро анализирует структуру ELF-файла и выводит результат в удобном виде.

Шаг 6. Инструменты strace и ltrace: динамический анализ программы

Но статический анализ не всесилен. Что, если пароль зашифрован? Что, если программа ведёт себя хитро?

Алексей запустил программу в изолированной среде и применил динамический анализ.

Инструмент strace показывает все системные вызовы (обращения к ядру):

strace -f ./systemd-update

Он увидел, как программа:

  • перехватывает сигналы SIGTERM и SIGINT (чтобы её нельзя было завершить);
  • копирует себя в /tmp;
  • создаёт дочерний процесс;
  • подключается к 8.8.8.8 и отправляет HTTP-запрос;

Инструмент ltrace показывает вызовы библиотечных функций. Помимо systemd-update, на сервере нашелся еще один подозрительный файл – backup-launcher, который требовал пароль при запуске:

ltrace -C ./backup-launcher

И тут Алексей после запуска ltrace увидел то, что искал:

fgets("какой-то_пароль", ...) = ... strcmp("какой-то_пароль", "super_secret_password") puts("Неверный пароль")

Пароль был прямо в выводе ltrace.

Вывод: strace показывает, с какими запросами программа обращается к ядру. Инструмент ltrace – какие библиотечные функции она вызывает.

Что же скрывалось в systemd-update?

Алексей собрал всё воедино. Процесс systemd-update оказался не обновлением, а программой, которая:

  • маскируется под системный процесс,
  • копирует себя в /tmp,
  • перехватывает сигналы (защищается от завершения),
  • запускает дочерний процесс в фоне,
  • ходит по сети и отправляет HTTP-запросы.

Это классическое поведение вредоносного ПО.

Но есть один нюанс. Программа стучится только на 8.8.8.8 и example.com – тестовые адреса. Никаких реальных атак. Это учебная программа, которая демонстрирует приёмы маскировки и сетевой активности, но не причиняет вреда.

Алексей выдохнул. Система была чиста. Но опыт он получил колоссальный.

Что дальше

Мы рассмотрели только вершину айсберга под названием «Анализ файлов в Linux». Но даже на этом уровне вы уже научились:

  • определять настоящий тип файла (file),
  • вытаскивать скрытые строки (strings),
  • видеть байты и находить вшитые файлы (xxd, grep -P),
  • извлекать и восстанавливать фрагменты (dd),
  • читать ELF-структуру (readelf),
  • следить за программой в реальном времени (strace, ltrace).

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

Полный курс «Анализ файлов в Linux» с множеством практических заданий, где вы самостоятельно пройдёте путь Алексея и найдёте все флаги, доступен бесплатно на Stepik. Файлы systemd-update, backup-launcher и landscape.png лежат на GitHub.

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

Удачных расследований.

1
5 комментариев