Как мы кибериммуннизировали IoT-контроллер

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

image

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

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

Было. Что мы взяли за основу


Для аппаратной части мы взяли достаточно типовой контроллер с процессором ARM9, который выглядел следующим образом:
ovwlc5t7h2m0szo6b5owhby7kw0.jpeg
Общий вид контроллера

Контроллер использовал Ethernet для взаимодействия с верхним уровнем облачных платформ и приложений и RS-485 для взаимодействия с полевыми устройствами.
Контроллер работал под управлением дистрибутива Debian и предназначался для отработки основных сценариев работы устройства:

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

9ro3brgewvmffp-zkgktb09-loy.png
Общий вид аппаратной платформы

Для реализации этих сценариев использования архитектура контроллера была сделана достаточно минималистичной. Она состояла из нескольких компонентов, основным из которых является брокер Mosquito, который позволял передавать и получать данные по протоколу MQTT. Этот компонент был «сердцем» первой сборки так как через него проходили все информационные потоки:

  • управляющий — от облака к устройству по протоколу TLS;
  • административный — между компонентами устройства (компоненты подписывались на события и обменивались сообщениями для организации работы);
  • полевой — между устройством и датчиками (за трансформацию высокоуровневого протокола MQTT в сигналы отвечало несколько драйверов).

Схематично, архитектуру можно представить следующим образом:
m28whqg_rnmumyj80deriwrelke.png
Общий вид архитектуры контроллера

Что не так с безопасностью контроллера?


Если рассмотреть контроллер с точки зрения безопасности, то можно выделить несколько фундаментальных проблем:

1. Смешение потоков данных. Все потоки обрабатываются внутри одного компонента, MQTT брокера. В случае, если один из потоков данных окажется скомпрометирован, например, при эксплуатации CVE в одном из компонентов, злоумышленник может развить атаку на брокер и получить контроль над всей системой.
Так, проэксплуатировав уязвимость в сетевом стеке (например, RCE-уязвимость Linux CVE-2019–11815 или подобную), злоумышленник может выполнить произвольный код на устройстве.

2. Большая кодовая база брокера. К сожалению, любой код содержит ошибки, некоторые из которых могут привести к уязвимости. Чем больше кода в компоненте, тем выше вероятность уязвимости, поэтому, чтобы гарантировать их отсутствие в брокере, потребуется проделать сложную работу так как кодовая база компонента крайне велика и поставляется в виде компонента open source, а значит каждое обновление так же должно проходить через многочисленные проверки.
Например, злоумышленник может произвести атаку типа «человек посередине» (Man-in-the-middle), заставив жертву подключиться к поддельному MQTT-серверу и проэксплуатировать уязвимость в реализации MQTT-протокола. Пример подобной уязвимости: CVE-2017–2892.

3. Возможность повышения привилегий. При эксплуатации уязвимостей в сетевом стеке (например, той же RCE-уязвимости Linux CVE-2019–11815), либо драйвере внешней сети, злоумышленник может повысить привилегии и получить контроль над устройством.

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

5. Отсутствие защиты от атак полевого уровня. Злоумышленник может подменить исполнительное устройство на полевом уровне собственным и сгенерировать произвольный сигнал, который может быть некорректно обработан драйвером или компонентом бизнес-логики, что может привести к компрометации устройства.
Например, злоумышленник может взломать одно из устройств, подключенных к порту RS-485, и таким образом получить доступ к шине (скорее всего удалённый). После этого злоумышленник может проэксплуатировать уязвимость в протоколе Modbus RTU и получить возможность удалённо выполнить произвольный код в контроллере.

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

w70n6of1_7edivw6kng0qeda3-q.png
Основные векторы атаки

Что мы сделали?


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

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

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

При этом прежде всего необходимо было не только обеспечить безопасность системы на уровне прикладного кода, но и на более глубоком уровне операционной системы. По этой причине первым этапом в проектировании архитектуры мы перенесли решение с Debian на KasperskyOS, которая удовлетворяет требованиям кибериммунитета «из коробки».

Далее мы поработали с архитектурой прикладной части контроллера, устранив те фундаментальные архитектурные проблемы, про которые писали выше: изолировали MQTT-брокер, разделили «восходящие» и «нисходящие» потоки данных, улучшили безопасность администрирования.

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

Далее последовательно рассмотрим шаги, которые мы прошли.

Шаг 1. Цели и предположения безопасности


В основе кибериммунного подхода лежит идеология Secure by Design, которая говорит, что безопасность системы нужно рассматривать не как дополнительное требование, а как неотъемлемую часть дизайна системы. То есть, безопасность нужно закладывать еще на этапе проектирования.

При этом, идеология Secure by Design в чистом виде мало говорит о том, что конкретно должно быть для этого сделано.

Здесь и появляется кибериммунитет, который вносит конкретику:

  1. конкретную методологию — как именно организовать процесс и какие результаты/артефакты необходимо иметь на каждом этапе;
  2. требования к дизайну — как именно должна быть спроектирована система, чтобы реализовать подход Security by Design экономически эффективным способом.

Применяя кибериммунный подход на практике, первым шагом для «кибериммунизации» контроллера была формулировка ответа на вопрос: «а от чего мы его будем защищать?». То есть явно описать ценности контроллера и те потенциальные неприятности, которые для нас неприемлемы — на уровне бизнес-назначения продукта.

Мы поняли, что нам необходимы следующие вещи:

  1. гарантированно безопасное взаимодействие с облачной платформой с сохранением конфиденциальности и целостности передаваемых данных, при любых обстоятельствах;
  2. чтобы команды, полученные от облачной платформы, корректно преобразовывались в сигналы (целостность, аутентичность) и направлялись на полевой уровень;
  3. чтобы хранение и обработка всей системной информации — конфигурации, сертификатов, логинов и паролей, идентификатора устройства — была безопасной (опять же целостность и аутентичность).
  4. чтобы журнал событий и журнал безопасности устройства накапливались и хранились с сохранением целостности, аутентичности и безотказности;
  5. чтобы обеспечивалось безопасное администрирование устройства.

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

Определение того, что для нас важно, стало основой для понимания того, что же мы будем понимать под безопасностью системы в нашем случае. Ведь безопасности «вообще» не бывает. Она всегда конкретная и разная для каждого продукта в зависимости от его бизнес-назначения и контекста использования. Нацелившись на безопасность «вообще», мы будем стараться делать систему неуязвимой, защищая в ней все подряд от всех угроз подряд (что, конечно, сделать не получится — например, из-за ограниченности ресурсов).

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

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

  1. Решение обеспечивает безопасную (конфиденциальность, целостность) передачу данных между ПЛК и облачной платформой.
  2. Решение обеспечивает безопасное (целостность, аутентичность) хранение и обработку конфигурационной информации (файлы и команды конфигурации), идентификационной и аутентификационной информации (сертификаты TLS; логины и пароли; идентификатор устройства).
  3. Решение обеспечивает безопасное (целостность, аутентичность) преобразование и передачу контрольно-измерительной информации (показания полевых устройств), управляющей информации (команды управления) на ПЛК.
  4. Решение обеспечивает накопление и безопасное (целостность, аутентичность, неотказуемость) хранение журнала событий (факт изменения системного времени; факт получения и статус исполнения команды телеуправления; факт подключения и отключения от облачной платформы; факт изменения конфигурации) и журнала безопасности (факт осуществления доступа при локальной диагностике; содержание действий при локальной диагностике).
  5. Решение обеспечивает безопасную диагностику (получение информации без возможности конфигурирования) ПЛК при авторизации пользователя посредством сертификата при установке безопасного канала.

Для определения предположений безопасности мы зафиксировали ряд ограничений. В частности:

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

Шаг 2. Портирование решения на KasperskyOS


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

Системный уровень решения — необходимая основа, без доверия к которой все дальнейшие усилия по построению безопасной системы в целом будут напрасны. Поэтому первым шагом проектирования было портирование решение с исходной операционной системы Debian на KasperskyOS, которая удовлетворяет требованиям кибериммунитета «из коробки». Благодаря поддержке большинства POSIX вызовов и большому многообразию базовых компонентов в SDK (к примеру — сетевых и файловых подсистем), портирование не означало полное переписывание всего кода.

Основной задачей, которая была решена при этом, стала замена административного потока данных (способа взаимодействия компонентов внутри решения) с протокола MQTT на IPC (inter process communication — основной механизм взаимодействия внутри KasperskyOS). Это позволило решить сразу несколько задач:

  1. Так уязвимости в отдельных компонентах не смогут привести к автоматическому распространению атаки на другие компоненты и на ядро операционной системы. Это происходит благодаря тому, что каждый компонент решения запускается в отдельной сущности и работает в изолированном адресном пространстве, в пользовательском режиме (user mode), включая драйвера.
  2. Развитие атаки в случае успешной компрометации компонента крайне затруднено. Каждое взаимодействие между сущностями контролируется монитором безопасности на основании политик безопасности, заложенных архитектором на стадии проектирования. Это позволяет описать все допустимые взаимодействия между компонентами и передаваемые по ним данные. В случае, если эти правила будут нарушены (например если компонент будет взломан, и злоумышленник попытается развить атаку через него), то такие запросы будут отклонены ядром операционной системы, а в журнале событий аудита появится соответствующая запись.
  3. Теперь конфигурация системы не может быть изменена в процессе работы. В системе установлен запрет на запуск новых сущностей, модификацию связей и изменение политик безопасности — это делается автоматически средствами операционной системы.

В результате был соблюдён принцип NEAT:

  • Non-bypassable — механизмы защиты невозможно обойти;
  • Evaluatable — все политики безопасности хранятся внутри монитора, их легко можно проанализировать и убедиться в корректности и достаточности;
  • Always-invoked — политики безопасности применяются к любому взаимодействию в системе;
  • Tamperproof — система защищена от модификации в процессе работы.

Шаг 3. Изоляция брокера


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

MQTT брокер обладает самой большой поверхностью атаки (из-за большой кодовой базы, и взаимодействия с внешней сетью), при этом от корректности его работы зависит всё решение. Так же данный компонент реализует TLS соединение — основной механизм обеспечения безопасности при взаимодействии с облаком.

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

Для повышения защищенности брокера и упрощения верификации корректности TLS соединения мы не стали «изобретать» какой-то способ защиты «по месту», а вместо этого воспользовались одним из множества паттернов проектирования на KasperskyOS — TLS Terminator.

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

Паттерн TLS Terminator предусматривает применение отдельного компонента для установления TLS, что позволяет:

  1. Обеспечить простоту и прозрачность — TLS terminator предоставляет сетевой сокет на уровне операционной системы, таким образом MQTT брокер не видит разницы между защищённым TLS соединением и обычным сетевым подключением, что снижает требования по точности настройки брокера.
  2. Снизить поверхность атаки — подключение брокера возможно только через TLS terminator, установление нешифрованного соединения невозможно за счёт политик безопасности, таким образом, единственным объектом, с которым может взаимодействовать брокер, является облако.
  3. Упростить верификацию — компонент TLS terminator базируется на небольшой современной библиотеке mbedTLS, кодовая база которой намного меньше, чем у популярной OpenSSL. Подробнее об этом вы можете узнать в выступлении нашей коллеги Дарьи Зимариной.

В результате получилась следующая схема взаимодействия:
afhxirgj72nka9ppgzqstcau9qc.png
Применение TLS Terminator

То есть:

  1. брокер перестал взаимодействовать с внешней сетью напрямую;
  2. атака на брокер из внешней сети напрямую стала невозможной;
  3. доступ к брокеру стал возможен только авторизированным абонентам.

При этом, все взаимодействия с TSL-терминатором мы строго контролируем на основе политик безопасности, гибко настроенных специально для этого компонента.

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

Шаг 4. Разделение потоков данных


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

Это было сделано следующим образом:

  1. Компоненты бизнес-логики были разделены на три группы:
    a) общие — отвечающие за работу устройства (логирование, сетевой стек, конфигурирование и так далее);
    b) взаимодействующие с облаком — отвечающие за выработку команд на основании данных, полученных от облака в том числе общим компонентам;
    c) взаимодействующие с полевым уровнем — отвечающие за преобразование данных, полученных от исполнительных устройств в сообщения, которые необходимо передать облаку.
  2. Компонент MQTT брокер был запущен в двух экземплярах в отдельных, изолированных сущностях. Первый компонент общался исключительно с облаком и общими компонентами бизнес-логики. Второй компонент взаимодействовал только с компонентами бизнес-логики полевого уровня.
  3. За счёт политики безопасности система была сконфигурирована таким образом, чтобы компоненты, взаимодействующие с облаком, могли передавать данные драйверам устройств полевого уровня только в однонаправленном режиме.
  4. Такое же правило однонаправленной передачи данных было настроено между компонентами полевой бизнес-логики и сетевым стеком.
  5. Логика проверки данных, поступающих от устройств полевого уровня, была вынесена в отдельный компонент.

В итоге получилась следующая схема взаимодействия:
3ajigg6bh9vmbj-qpuslzqbivna.png
Разделение потоков данных

В результате проделанной работы устройство оказалось защищено от атак злоумышленника, расположенного во внутренней сети.

Шаг 5. Повышение безопасности администрирования


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

В частности, важная цель безопасности, поставленная перед контроллером — обеспечить безопасное администрирование устройства. Но как устроено администрирование? К примеру, при диагностике состояния устройства, авторизованный пользователь отправляет запрос на веб-сервер. Веб-сервер, в свою очередь, отправляет диагностический запрос компонентам, чтобы они поделились своим состоянием, и затем отправляет результат обратно пользователю. При обновлении конфигураций веб-сервер передаёт набор данных компоненту, ответственному за проверку и установку пакета обновления. То есть злоумышленник, взломав веб-сервер, который имеет большую поверхность атаки, может нанести ущерб другим компонентам решения.

Изолировав веб-сервер в отдельном компоненте, мы решили множество проблем, связанных с повышением привилегий, однако остался вопрос авторизации администратора. Наиболее надёжным является авторизация с использованием сертификата, но если реализовать этот механизм в самом веб-сервере, то возникают те же проблемы, что и в случае применения TLS в MQTT брокере.

Для решения этой проблемы мы так же использовали паттерн TLS terminator, но уже не в клиентском (устанавливающим соединение по запросу компонента), а в серверном исполнении.

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

dqdnjgxrlseyil4ln0dyswei0bo.png
Безопасное администрирование

Что мы получили в результате?


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

Для кибериммунизации контроллера была проделана большая работа, в результате которой архитектура решения преобразовалась от такой:

h_ymmyxseasd_2khaultv17nsuw.png
Исходная архитектура контроллера

К такой:
v3htkwycrpj4zn0rb5w-utnv9yi.png
Итоговая архитектура кибериммунного контроллера

Как видно на схеме, в итоговой архитектуре все компоненты разделены на три группы, в соответствии с целями безопасности системы:

  1. Зеленые — доверенные. То есть те, от которых непосредственно зависит достижение целей безопасности системы.
  2. Желтые — высокодоверенные. Которые повышают доверие к данным, которые через них проходят.
  3. Красные — недоверенные. То есть все остальные.

Красные недоверенные компоненты размещены на границе системы, зеленые доверенные — в самом центре, а желтые высокодоверенные — между ними.

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

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

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

© Habrahabr.ru