Компоненты ПО с открытым исходным кодом сейчас встречаются почти в каждом приложении. Это повышает эффективность разработки, но привносит дополнительные риски, в первую очередь связанные с атаками на цепочку поставок. Создавая операционную систему KasperskyOS, мы в «Лаборатории Касперского» задумались: как сделать переиспользование недоверенного кода безопасным? Эта задача особенно актуальна, когда речь идет о системе, на базе которой строятся продукты для отраслей с повышенными требованиями к кибербезопасности.

В этой статье мы расскажем, какие механизмы в KasperskyOS позволяют снизить риски, характерные для распространенных ОС. А также покажем на реальном примере, как системы на базе Linux и KasperskyOS по-разному справляются с киберугрозами.

В качестве примера мы выбрали сценарий вредоносной функциональности, заложенной в open-source-драйвер сетевой карты. В свете роста количества и сложности атак на цепочку поставок сценарий более чем реалистичный. Если вам интересно, почему мы выбрали именно сценарий использования Linux-драйвера и атаку на цепочку поставок, — оставим объяснения под спойлерами.

Почему в примере именно драйвер Linux

Ядро Linux как единая база драйверов и компонентов для новых ОС

Сегодня системы с открытым исходным кодом получили широчайшее распространение и используются практически во всех сферах жизни. Облачные платформы, хостинг-провайдеры, банковские системы, медицинские учреждения, системы управления производствами и множество других сервисов активно используют решения на базе ядра Linux.

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

Популярность и доступность ядра Linux привели к тому, что его компоненты, в первую очередь драйверы, стали использоваться за пределами Linux-экосистемы. Например, FreeBSD позволяет загружать в свое ядро немодифицированные драйверы Linux. Фреймворк для разработки операционных систем Genode предлагает методологию по переносу драйверов Linux в системы на его основе. Huawei заявляет о поддержке в микроядерной HarmonyOS NEXT контейнеров с драйверами Linux. Даже любительские проекты операционных систем, такие как KolibriOS, используют некоторые драйверы ядра Linux, перенесенные в их кодовую базу, например, для работы со встроенной графикой Intel.

Почему именно атака на цепочку поставок

Краткая история атак на цепочку поставок

За последние несколько лет мы видели немало инцидентов, в которых злоумышленники так или иначе атаковали цепочку поставок. Вот самые заметные из них:

2020 год — взлом компании SolarWinds, которая поставляет решения для мониторинга IT-инфраструктуры. Инцидент продемонстрировал серьезность угрозы, так как в результате атаки скомпрометированными оказались тысячи государственных и частных организаций по всему миру.

2021 год — к аналогичным последствиям привел взлом Codecov, когда была скомпрометирована утилита анализа покрытия кода.

2023 год — зафиксировано заражение распространяемых Microsoft артефактов через атаку на JFrog Artifactory, менеджер, использовавшийся в инфраструктуре корпорации.

2024 год — целый букет инцидентов:

Современные атаки на цепочку поставок часто развиваются продолжительное время и используют многовекторный подход. Злоумышленники применяют и социальную инженерию, и перехват доменных имен, и взлом GitHub-аккаунтов разработчиков популярных зависимостей ПО. Причем компрометация происходит через вредоносные изменения сборочной инфраструктуры, подмену динамических библиотек и даже через модификацию исходных кодов оригинального продукта.

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

Вредоносные модификации в системном ПО

Инцидент с XZ/liblzma показывает, что бэкдоры и намеренно внедренные уязвимости могут присутствовать даже в популярном системном ПО. Вредоносная модификация системного кода особенно опасна — это значительно усложняет выявление угроз и повышает потенциальный ущерб от атак.

Но возможно ли существование бэкдоров в таких проектах, как ядро Linux? Казалось бы, код ядра этой ОС проходит через серьезный процесс ревью: предполагается, что мейнтейнеры из публичных списков рассылки не пропустят зловредный патч в релиз. Но на практике даже опытные разработчики, сведущие в вопросах информационной безопасности, могут не заметить опасные изменения. Одна из причин заключается в том, что язык C, на котором разработано большинство системных программ, включая ядра ОС, позволяет скрывать неочевидное поведение за счет принятых умолчаний, undefined/unspecified поведения, неявных преобразований типов и особенностей препроцессора.

Вообще, возможность намеренного внедрения бэкдоров в операционные системы с открытым кодом обсуждается уже много лет. Еще в 2010 году бывший подрядчик ФБР заявил о том, что агентство когда-то внедрило уязвимости в код OpenBSD. Когда про потенциальную закладку стало известно, лидер проекта Тео Де Раадт провел серьезное ревью проблемных мест в коде. За много лет развития системы код, разумеется, серьезно поменялся, но Де Раадт все равно обнаружил потенциальные уязвимости. Сказать однозначно, были ли эти уязвимости добавлены кем-то намеренно или нет, — нельзя. Однако то, что их не заметили при первичном ревью, когда принимали патчи, — факт.

Сокрытие вредоносных изменений

Как ревьюеры могут не заметить внесение вредоносного кода в проект? Существует целый ряд методик, которые помогают злоумышленникам внедрять скрытые изменения в программное обеспечение. Если интересны конкретные примеры, то можно изучить результаты конкурса Underhanded C Contest. В его рамках требуется создать программу, которая выполняет оговоренную злонамеренную активность в дополнение к вполне безобидной функциональности. Важное условие: злонамеренное поведение должно быть трудно определяемым на ревью кода специалистами по информационной безопасности.

Дополнить картину может известная работа Кена Томпсона Reflections on Trusting Trust, поднимающая вопрос о доверии к инструментам разработки, например компиляторам. Ведь компилятор может инструментировать код, оставляя в нем уязвимости, генерируя пути обхода вызовов аутентификации популярных библиотек (например, PAM).

Кроме того, нередко необходимые BSP (Board Support Package) и драйверы ядра не входят в дерево исходного кода ядра Linux, а поставляются непосредственно производителем оборудования (типичная ситуация для китайских устройств). Таким образом, в них можно встретить уязвимости, которые широкое Linux-сообщество даже теоретически не могло заметить. Причем эти драйверы зачастую имеют невысокое качество, содержат специализированные хаки/оптимизации, используют нестабильные интерфейсы ядра и так далее. Так что уязвимости в них можно встретить и без всякого злого умысла.

Модели угроз современных ОС, «песочницы» для приложений и драйверов

Разумеется, при создании собственной операционной системы мы не собирались изобретать велосипед. Поэтому для начала мы провели анализ распространенных стандартов безопасности операционных систем и безопасной разработки, а также изучили подходы, которые применяют создатели современных коммерчески успешных ОС. В числе прочих мы изучили Android, ChromeOS, GrapheneOS, Whonix, Ubuntu Core, Qubes OS, Genode OS Framework, Legato, HarmonyOS NEXT, OpenBSD, seL4.

Большинство этих систем переосмысляют взгляды на модель угроз персональных и профессиональных устройств. То есть устройств, которые круглые сутки подключены к глобальной Сети и обрабатывают контент из недоверенных источников со сложной структурой, а также позволяют расширять функциональность за счет приложений, разрабатываемых третьими сторонами. При этом такие устройства могут быть атакованы с использованием разнообразных беспроводных технологий, таких как NFC, Bluetooth и Wi-Fi. А носимые девайсы вдобавок могут попасть в руки злоумышленников, то есть для их защиты необходимо рассматривать угрозы, предполагающие еще и физический доступ.

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

Наша команда, ответственная за разработку KasperskyOS, пришла к выводу о необходимости распространения этого подхода дальше уровня приложений, на другие, традиционно менее изолированные системные компоненты. В их число входят драйверы устройств и сетевой стек — как раз для снижения рисков, связанных с эксплуатацией потенциальных закладок или уязвимостей в коде Linux-драйверов и подсистем. Это позволит безопасно использовать Linux-драйверы при необходимости ускоренного портирования KasperskyOS на новые аппаратные платформы.

Угрозы и способы их митигации в KasperskyOS

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

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

В популярных операционных системах на основе монолитных ядер для драйвера существует только две границы доверия: между пространством пользователя и ядром ОС и между ядром ОС и контролируемым оборудованием. Это не позволяет рассматривать угрозы драйверов в отрыве от угроз ядру операционной системы. При таких ограничениях крайне трудно митигировать угрозу атак на цепочку поставок драйверов, включающую возможность злонамеренной модификации их исходного кода и обнаружения случайных эксплуатируемых уязвимостей. В отличие от мира Windows, где имеется практика подписывания драйверов и их централизованное распространение, в Linux практически единственным эффективным решением оказывается использование харденингов, затрудняющих эксплуатацию. Как показывает опыт, даже самые продвинутые харденинги не способны остановить настойчивого и изобретательного взломщика. 

Системы на основе микроядра лишены этих ограничений. Благодаря иной организации архитектуры и разделению компонентов системы в некоторых случаях она допускает использование дополнительных границ доверия и дает возможность более детально и эффективно рассматривать угрозы.

Рассмотрим сокращенную модель угроз абстрактному драйверу устройства. К источникам угроз отнесем непосредственно устройства, взаимодействующие с драйвером, пользовательские процессы, для которых драйвер осуществляет абстракцию над устройством и мультиплексирование его ресурсов, стеки и подсистемы, предоставляющие дополнительные уровни абстракции над драйвером, например сетевой стек.

В таблице ниже представлено несколько угроз с указанием возможных компенсирующих мер, применяемых в KasperskyOS.

Угроза

Подугроза

Описание

Желаемое поведение

Митигация

DRV 1*. Отказ в обслуживании

DRV 1.1. Отказ в обслуживании всей операционной системы вследствие нарушения работы драйвера

Ошибка в драйвере эксплуатируется для создания исключительной ситуации, например разыменования нулевого указателя. Ядро операционной системы паникует и переходит в ошибочное состояние.

В большинстве популярных операционных систем эту угрозу невозможно митигировать

Нарушение работы драйвера не приводит к отказу в обслуживании всей системы

Выполнение драйвера в «песочнице» с пониженными привилегиями. Драйвер запускается в отдельном процессе пространства пользователя. API ядра, связанный с выделением физической памяти, должен быть 
доступен только доверенному менеджеру драйверов, сами драйверы должны получать необходимые ресурсы (порты, регионы памяти, номера прерываний) через передачу Object Capability на соответствующие объекты. Возможны разные реакции на ошибочную остановку работы драйвера (завершение процесса): перезапуск, запись в журнал аудита

DRV 1.2. Отказ в обслуживании зависимых сервисов вследствие чрезвычайно длительной активности в ходе работы драйвера

Ошибка в логике драйвера эксплуатируется для того, чтобы снизить его отзывчивость, например, за счет исполнения бесконечного цикла. Процессы и подсистемы, использующие драйвер, могут перестать отвечать из-за блокировки в ожидании событий

Нарушение работы драйвера не приводит к отказу в обслуживании зависимых сервисов

Запуск драйвера в отдельном процессе. Мониторинг здоровья драйвера: «проверка пульса», сторожевой таймер. В ряде случаев подобные меры позволят перезапустить зависший драйвер и восстановить контекст его работы

DRV 2. Утечка информации

DRV 2.1. Утечка данных, размещенных в куче

Вследствие доступа за допустимые границы объекта, неинициализированных значений или иных ошибок в процессе обработки пользовательских данных возможна утечка данных из драйвера и ядра ОС. Такие данные могут содержать секреты, например ключи шифрования, используемые в ядерном Crypto API

Данные не утекают, или утечка ограничена нечувствительными данными

Отделение драйвера от ядра, запуск в пространстве пользователя. Благодаря этому драйвер не разделяет общих секретов с ядром ОС.

Применение практик безопасного программирования, SDL.

Валидация параметров вызовов генерируемым парсером

DRV 2.2. Утечка данных, размещенных в стеке

* Коды угроз являются символическими и используются исключительно для внутренних ссылок в рамках данной таблицы и настоящей статьи.

Демонстрационный сценарий

Рассмотрим простой сценарий из модели угроз, приведенной выше: в драйвер сетевой карты намеренно заложили функциональность, приводящую к отказу в обслуживании. В системе присутствует критический пользовательский процесс, осуществляющий контроль оборудования, драйвер сетевой карты и сетевой стек используются для передачи журнала наблюдения за оборудованием. Полная остановка системы может привести к порче дорогостоящего оборудования. Нарушение в передаче журнала событий рассматривается как инцидент невысокого уровня.

На базе этого сценария мы построили экспериментальный стенд с использованием Radxa ROCK 3A. Стенд состоит из двух образов, выполняющих идентичную бизнес-задачу. При этом один образ реализован на простой сборке GNU/Linux, а другой использует KasperskyOS Community Edition. Обе системы имеют идентичную модельную «закладку» с уязвимостью в сетевом драйвере. Отправка специально сформированного пакета вызывает незамедлительный переход драйвера в ошибочное состояние.

Эксперимент демонстрирует сохранение критической функциональности с KasperskyOS и падение ядра ОС на основе GNU/Linux. Отметим, что данный пример реализует защиту от конкретной уязвимости в конкретном сценарии. Для митигации других угроз следует правильно подходить к архитектуре решения и использовать различные паттерны безопасности.

Продемонстрированные в эксперименте варианты атаки на цепочку поставок, потенциально способные оказать серьезное влияние на работоспособность системы и безопасность данных, сейчас актуальны как никогда. Тем не менее, такого рода угрозы редко рассматриваются разработчиками операционных систем, поскольку без возможности изоляции драйверов в песочнице у них нет возможности серьезно повлиять на реализацию этих угроз. Все что им остается — надеяться на добрые намерения разработчиков открытого системного ПО и качество доступных харденингов. 

Описание стенда и код можно посмотреть в нашем репозитории на GitFlic. Если вам интересно узнать больше о нашей операционной системе и заложенных в ней принципах безопасности, вы можете воспроизвести наш пример, установив KasperskyOS Community Edition.

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