Если когда-нибудь хотелось увидеть, на что способен современный LKM-руткит, созданный не для атаки, а для демонстрации пределов невидимости в Linux, то Singularity — как раз тот случай. Это проект исследователя MatheuZSecurity, который задался целью создать модуль ядра, максимально устойчивый к обнаружению стандартными средствами диагностики и форензики. Получился инструмент, который заставляет даже опытных DFIR-аналитиков задуматься, где вообще кончается видимая часть системы.
Singularity работает с современными ядрами серии 6.x, подключается как LKM-модуль и после загрузки полностью скрывает своё присутствие. Автор сразу предупреждает: модуль невозможно выгрузить стандартным способом — чтобы вернуть систему в нормальное состояние, потребуется перезагрузка. Поэтому тестировать рекомендуется только в виртуальной машине.
Как устроен Singularity
Основная логика построена на ftrace-хуках, которые перехватывают ключевые системные вызовы — от getdents и stat до openat и readlinkat. Таким образом, руткит внедряется в сам поток обращений пользовательских программ к ядру, фильтруя результаты и подменяя метаданные. Именно поэтому процессы, каталоги и сетевые порты, помеченные для скрытия, исчезают не только из /proc
, но и из всех утилит мониторинга: ps, top, netstat, ss, lsof и даже /proc/net/*
.
Singularity поддерживает несколько способов сокрытия. Любой процесс можно «спрятать» с помощью сигнала kill -59 PID
— после этого он исчезает из всех таблиц. Директории и файлы фильтруются по шаблону, который задаётся в include/hiding_directory_def.h
. Если создать каталог с указанным именем, он сразу станет невидимым для ls, find и других утилит. При желании пользователь может изменить маску фильтра и тем самым уйти от типичных сигнатур детектирования.
Отдельно реализовано скрытие сетевых портов. Любое соединение, например на порту 8081, будет исключено из вывода всех инструментов, читающих данные из /proc/net
. Снаружи система выглядит так, будто порт не слушает ничего — хотя соединение активно.
Повышение привилегий и маскировка следов
Singularity умеет предоставлять root-доступ, используя «магическую» переменную окружения: MAGIC=mtz bash
запускает shell с правами суперпользователя. Аналогичного эффекта можно добиться, послав процессу тот же сигнал -59
. Этот механизм реализован через модуль become_root.c
, где хук напрямую изменяет структуру cred в памяти ядра.
Для маскировки следов инструмент модифицирует поведение чтения системных логов. Модуль clear_taint_dmesg.c
фильтрует вывод dmesg
и журналов, удаляя строки, которые могли бы указать на загрузку модуля или подозрительные обращения к ядру. В итоге система выглядит «чистой», даже если она уже заражена.
Чтобы избежать обнаружения через sysfs или список модулей, Singularity вырезает собственный kobject из дерева модулей и очищает все связанные структуры. Даже флаг загрязнения ядра (taint) периодически нормализуется отдельной функцией, чтобы скрыть факт вмешательства.
В README автор отдельно предупреждает: хотя Singularity проходит незамеченным для стандартных утилит вроде chkrootkit, unhide и rkhunter, опытный аналитик всё же сможет найти следы — при желании. Например, модуль можно обнаружить через низкоуровневые инструменты работы с файловыми системами, такие как debugfs. Впрочем, разработчик советует размещать артефакты в /dev/shm
— это файловая система в оперативной памяти, куда debugfs не имеет доступа. Такой подход дополнительно усложняет анализ, поскольку данные исчезают после перезагрузки.
Если включить автозагрузку через load_and_persistence.sh
, модуль становится видимым в списке загрузки /etc/modules-load.d/
, поэтому автор советует менять имя файла конфигурации и самого бинаря, чтобы избежать очевидных совпадений.
Техническая архитектура и карта хуков
В основе Singularity лежит модуль ftrace_helper.c
, отвечающий за установку хуков. Через него подключаются перехватчики системных вызовов: getdents
скрывает каталоги и процессы, stat/statx
подменяет метаданные, read
и write
фильтруют обращения к журналам и средствам трассировки, а hiding_tcp.c
исключает записи из сетевых таблиц. Есть и хук на init_module
, блокирующий попытки других модулей внедриться в систему.
Интересно, что разработчик добавил собственный «нормализатор загрязнения ядра»: модуль reset_tainted.c
периодически ищет переменную tainted_mask
и сбрасывает флаги, которые могли бы выдать факт модификации системы. Таким образом, даже при глубокой проверке ядро выглядит «чистым».
Всё это превращает Singularity в наглядный пример того, насколько гибко и глубоко можно вмешиваться в поведение Linux, если работать на уровне ядра. С точки зрения исследовательской демонстрации — это почти «финальный босс» для анализаторов.
Назначение и этическая сторона
Сам автор подчёркивает, что проект предназначен исключительно для образовательных и исследовательских целей. Код открыт, но его использование вне контролируемых лабораторных условий может нарушать законы. Поэтому Singularity — не инструмент атаки, а способ изучить границы возможностей Linux-модулей и лучше понимать, как их детектировать. Для специалистов по кибербезопасности это отличный полигон: можно проследить, какие именно системные вызовы чаще всего перехватываются, как работает фильтрация /proc, и какие признаки всё же позволяют выявить присутствие руткита, несмотря на его усилия по сокрытию.
В итоге Singularity стал не просто очередным примером вредоносного кода, а учебным пособием по архитектуре скрытых модулей. Он демонстрирует, как устроены современные методы обхода форензики и почему борьба с ними требует не только инструментов, но и глубокого понимания механики ядра. Проект активно развивается на GitHub и открыт для исследовательских доработок. Для общения и обсуждения автор приглашает в Discord-сообщество Rootkit Researchers — площадку, где встречаются специалисты по низкоуровневым технологиям и анализу вредоносов.
Для практиков и энтузиастов информационной безопасности Singularity — это редкая возможность посмотреть на внутреннюю кухню ядра глазами того, кто умеет скрываться в нём почти без следа. И именно поэтому изучать его стоит — но только в безопасной среде.