Как приручить руткит. Предотвращаем загрузку вредоносных модулей в Linux

Уже давно (как минимум с 1997 года) известно, что для Linux существуют вредоносные программы, хотя и слышно о них не так часто, как про виндовые. Тем не менее даже спустя двадцать с лишним лет руткиты на основе модулей ядра все еще представляют вполне реальную угрозу. Несмотря на столь большой срок, наиболее частым советом при заражении «ядерным» руткитом до сих пор остается полная переустановка системы. Неужели нельзя без этого обойтись? Иногда можно.

Какие бывают руткиты для Linux

Руткиты помогают злоумышленнику закрепить доступ ко взломанной системе, при этом акцент сделан на максимальной незаметности вредоноса. Для этого они скрывают сетевые соединения, процессы, папки, файлы, подделывают их содержимое. Обычно руткит несет в себе хакерские утилиты для управления зараженной машиной, с помощью которых злодей может установить и прятать в системе DDoS-бота или майнер (кстати, один такой, Skidmap, обнаружили сравнительно недавно). Чаще всего в эти утилиты входят бэкдоры, и не только те, что можно запросто обнаружить внешним сканером портов, а использующие технологию Port knocking (что-то вроде «простукивания портов»), когда порт открывается только после правильной и заранее определенной последовательности запросов к закрытым портам.

Традиционно все руткиты делят на работающие в пространстве пользователя и работающие в пространстве ядра. Против первых уже есть утилиты, способные обнаружить многие из них: chkrootkit, rkhunter, Antidoto и проект с незамысловатым названием linux-malware-detect. Поэтому «ядерные» руткиты, которые сложнее обнаружить непосредственно на зараженной системе, представляют больший интерес, хотя часть из них эти утилиты тоже могут выявить (но не удалить).

Руткиты уровня ядра в Linux, как правило, реализуются в виде загружаемых модулей ядра (LKM, Loadable Kernel Modules), но есть еще более экзотические способы: вредоносный код записывается прямо в память ядра через файл устройства /dev/kmem или внедряется на ранних этапах загрузки с модификацией initrafms (если ты знаком с такими руткитами, дай знать — попадаются только теоретические описания, а найти образцы мне не удалось). Сейчас, впрочем, о случаях заражения «ядерными» руткитами пишут нечасто, но все тот же недавно выявленный Skidmap говорит о том, что об этой угрозе забывать не стоит.

INFO

Загружаемые модули ядра (*.ko, до ядра 2.6 — *.o) позволяют динамически расширять функциональность ядра без необходимости перекомпилировать его целиком. Очень полезный механизм для повышения гибкости системы и очень подходящий для создания руткитов, которые обладали бы максимально возможными привилегиями.

Жизненно важные задачи каждого руткита

В ядре имеется множество структур, описывающих текущее состояние системы. Например, это список запущенных процессов, состоящий из указателей на дескрипторы процессов, который используется планировщиком. Другой важный объект — список загруженных модулей ядра, где каждый элемент указывает на дескриптор загруженного модуля. Он используется командами, оперирующими LKM: lsmod, rmmod, modprobe и подобными. Эти списки относятся ко внутренним объектам ядра.

Всякий вредоносный модуль первым делом удаляет себя из списка загруженных модулей, ведь если LKM в нем не описан, то ядро считает, что такой модуль не загружен. Это значит, что он не отобразится в выводе lsmod и не будет выгружен с помощью rmmod. Такая техника называется манипулированием внутренними объектами ядра (DKOM, Direct Kernel Object Manipulation) и подробно описана в статье на Хабре.

Также любой хороший руткит заботится о том, как остаться в строю после перезапуска системы. Например, Snakso, обнаруженный в 2012 году, для этого прописывает команду загрузки модуля в /etc/rc.local, rkduck предпочитает файл /etc/rc.modules, а Reptile в зависимости от целевой системы может использовать и /etc/rc.modules, и /etc/modules. Skidmap вносит разнообразие в этот список и закрепляется в сценариях планировщика задач cron. Вообще, для этой цели могут подойти и другие файлы, влияющие на загрузку Linux, в том числе загрузочные скрипты. Далее будем называть такие файлы файлами автозагрузки.

INFO

  • /etc/rc.local содержит команды, которые необходимо выполнить при запуске системы. Руткиты добавляют туда команду insmod <путь к вредоносному LKM>.
  • /etc/rc.modules содержит список модулей ядра, которые нужно загрузить при запуске — на более раннем этапе загрузки ОС, чем при использовании /etc/rc.local. Данный файл характерен для RPM-дистрибутивов.
  • /etc/modules также содержит список модулей, но используется в deb-системах.

И все вроде бы просто: проверяй содержимое этих файлов на подозрительные строки, и в твоей системе все будет хорошо. Но руткит не руткит, если не скрывает еще и что эти файлы модифицированы. Он может перехватывать системные вызовы и даже функции самого ядра, которые за этими вызовами стоят: например, Snakso и Reptile перехватывают функции файловой подсистемы ядра VFS (Virtual File System). Руткиты проверяют, было ли среди прочитанного что-то, что необходимо скрыть от глаз пользователя или администратора, и при необходимости модифицируют буфер со считанными данными.

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

Матчасть: как LKM-руткиты заметают следы

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

Продолжение доступно только участникам

Материалы из последних выпусков становятся доступны по отдельности только через два месяца после публикации. Чтобы продолжить чтение, необходимо стать участником сообщества «Xakep.ru».

Присоединяйся к сообществу «Xakep.ru»!

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», увеличит личную накопительную скидку и позволит накапливать профессиональный рейтинг Xakep Score! Подробнее

Ксения Кирилова: Desperately in love with Linux and C

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

  • "проверить, нет ли по адресу функции байта со значением 0x90, соответствующего jmp"

    Извините, а давно у нас опкод 0x90 стал jmp? Вроде, еще с утра был NOP...
    Или разговор не про х86?

    • Да-да, мозг не оттуда считал данные и решил, что 0x90. Там 0xe9, конечно, должно быть. Спасибо, что заметили)

  • > Для сплайсинга можно проверить, нет ли по адресу функции байта со значением 0x90, соответствующего jmp

    Только не jmp, а nop.

  • > или внедряется на ранних этапах загрузки с модификацией initrafms (если ты знаком с такими руткитами, дай знать — попадаются только теоретические описания, а найти образцы мне не удалось)

    Magisk?.. Андроид, конечно, но формально все же линух.