"Хирургическая" атака на Linux 6.9: руткит FlipSwitch взломал «непробиваемое» ядро

Уязвимость нашлась не в структуре, а в самой логике системных операций.


p4omrwir5btxbwrw3g8ifcbke97up455.jpg

На фоне постоянного противостояния между разработчиками ядра Linux и создателями вредоносных модулей, каждая новая версия системы меняет расстановку сил. Свежий пример — руткит-модуль FlipSwitch , который использует необычный способ перехвата системных вызовов в условиях жёстких ограничений, введённых в ядре 6.9. Этот приём основан не на привычной подмене указателей в sys_call_table, а на точечном вмешательстве в машинный код самого ядра — и работает даже после того, как классическая техника стала бесполезной.

Долгое время руткиты вроде Diamorphine или PUMAKIT маскировались, переписывая указатели на системные вызовы в sys_call_table, отключив защиту от записи и подменяя, например, sys_kill на свою вредоносную функцию. Но начиная с версии 6.9 ядра для архитектуры x86‑64, системные вызовы больше не обрабатываются через эту таблицу — вместо неё теперь используется конструкция на основе switch, напрямую вызывающая соответствующие обработчики через жёстко зашитые инструкции. В результате любые изменения sys_call_table больше не влияют на поведение системы, лишая руткиты привычной точки входа.

Однако логика вызова нужных функций при этом никуда не исчезла — она просто была скрыта внутри x64_sys_call. На этом и построена методика FlipSwitch: сначала извлекается адрес оригинальной функции, например sys_kill, через kallsyms_lookup_name, который сам по себе обычно недоступен, но может быть найден косвенно с помощью механизма kprobe. Получив указатель на нужный символ, руткит анализирует байт-код функции x64_sys_call, пока не находит конкретную инструкцию call с сигнатурой 0xe8 и смещением, точно указывающим на нужную цель.

Обнаружив этот вызов, модуль временно отключает защиту памяти, манипулируя 16‑ым битом регистра CR0, что позволяет изменять защищённые участки кода. Затем подменяется всего четыре байта — и вызов переадресуется с оригинального sys_kill на вредоносный аналог, в точности имитирующий легитимную функцию, но с возможностью фильтрации или подмены результатов. При этом остальная часть обработчиков системных вызовов остаётся нетронутой, что делает вмешательство практически незаметным.

Главная особенность FlipSwitch — в его избирательности и аккуратности. Изменения обратимы: при выгрузке модуля всё возвращается в исходное состояние, следов не остаётся. Однако это также означает, что обнаружить такой руткит после его загрузки крайне сложно. Для поиска прототипа FlipSwitch команда Elastic подготовила сигнатуру YARA , способную выявить наличие характерных шаблонов в памяти или на диске.

FlipSwitch стал наглядным примером того, как эволюция системной архитектуры провоцирует разработчиков вредоносных модулей на новые изобретения. Даже отказ от прямого обращения к sys_call_table не смог полностью закрыть лазейки — достаточно точечного вмешательства в нужную инструкцию, чтобы вернуть себе контроль над ядром.