• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Не глупи - это всего лишь лампочка

yashechka

Генератор контента.Фанат Ильфака и Рикардо Нарвахи
Эксперт
Регистрация
24.11.2012
Сообщения
2 344
Реакции
3 563
Все знакомы с концепцией IoT, Интернета вещей, но кто слышал об умных лампочках? Вы можете управлять светом в доме и даже откалибровать цвет каждой лампочки, просто используя мобильное приложение или своего цифрового помощника по дому. Умное управление лампочкой осуществляется через Wi-Fi или даже ZigBee, протоколу радиосвязи с низкой пропускной способностью.

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

Мы здесь, чтобы сказать вам ответ: да.

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

Ниже представлена видео-демонстрация этой атаки:


Это исследование было проведено с помощью Института информационной безопасности Check Point (CPIIS) Тель-Авивского университета.

Введение

После того, как мы закончили наше предыдущее исследование (Say Cheese: How I Ransomwared Your DSLR Camera), мы решили расширить наш отладчик (Scout) для поддержки дополнительных архитектур, таких как MIPS. Поскольку лучший способ сделать это - начать исследование архитектуру MIPS, я попросил в Твиттере предложить нам хорошую цель для исследования уязвимостей.

Как правило, люди ответили несколькими многообещающими предложениями, и самый многообещающей из них был от моего старого коллеги: Eyal Ronen (@eyalr0), который сейчас занимает должность исследователя в CPIIS. Eyal Ronen предложил мне продолжить его исследования умных лампочек. В своем первоначальном исследовании его группа смогла взять под контроль только сами лампочки. Он считал, что можно использовать эту позицию в сети ZigBee для развертывания атаки на мост, соединяющий сеть ZigBee с IP-сетью. По сути, этот новый вектор атаки позволяет злоумышленнику проникнуть в IP-сеть из сети ZigBee, используя беспроводную атаку.

Предыдущая работа

В статье "Интернет вещей становится ядерной ягрозой: создание цепной реакции ZigBee группа исследователей под руководством Eyal Ronen (@eyalr0), Colin O’Flynn (@colinoflynn) и Adi Shamir проанализировала аспекты безопасности интеллектуальных лампочек ZigBee. В частности, они сосредоточились на бридже Philips Hue и лампочках, продемонстрировав серию эксплоитов:

- Злоумышленники могут удаленно "украсть" лампочку из данной сети ZigBee и заставить ее присоединиться к своей сети (продемонстрировано с помощью беспилотного летательного аппарата, летящего с расстояния 400 метров):

- Из-за ошибки реализации даже обычная лампочка может использоваться для развертывания этого типа атаки и "похищения" лампочек из соседних сетей ZigBee.

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

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

Из-за характера атак поставщик смог заблокировать только вторую атаку, что позволило нам:

- "Украсть" лампочку из данной сети ZigBee в непосредственной близости (400 метров).
- Обновить прошивку этой лампочки и использовать ее для запуска следующей фазы нашей атаки.

Получив подробное объяснение из первоначального исследования и вооружившись Philips Hue Bridge, которую Eyal R удалось получить из их лаборатории, мы были готовы начать это многообещающее новое исследование.

ZigBee 101

Согласно Википедии, "ZigBee - это основанная на IEEE 802.15.4 спецификация для набора высоко-уровневых протоколов связи, используемых для создания… маломощных, низко-скоростных беспроводных одноранговых сетей непосредственной близости". Не путать с IEEE 802.11 (WiFi), согласно модели OSI, IEEE 802.15.4 является техническим стандартом для сетевого протокола на основе радио, который действует как уровни 1-2 сетевого стека ZigBee.

Чтобы получить представление об этом протоколе с низкой скоростью передачи данных, максимальная единица передачи (MTU) для кадра на нижележащем MAC-уровне IEEE 802.15.4 составляет 127 байтов. Это означает, что, если не используется фрагментация, сообщения сетевого стека ZigBee очень ограничены по размеру. Надеюсь, это ограничение не слишком сильно ограничит нас в поиске, а затем и в использовании уязвимостей в реализации ZigBee.

Поверх уровня радиосети ZigBee определяет полный стек сетевых уровней, как видно на этом рисунке, взятом из (более старой версии) спецификаций ZigBee:


1.png


Короче говоря, мы можем примерно разделить сетевой стек на 4 уровня (в порядке возрастания):

- Физический/MAC-уровень - Кадры на основе радио, определенные IEEE 802.15.4.
- Сетевой уровень (NWK) - отвечает за маршрутизацию, ретрансляцию и безопасность (шифрование).
- Подуровень поддержки приложений (APS) - направляет сообщение в правильное приложение верхнего уровня.
- Уровень приложения (ZDP/ZCL/ и так далее) - Логический прикладной уровень, зависящий от входящего сообщения (одновременно присутствует на нескольких уровнях).

ZDP = ZigBee Device Profile
ZCL = ZigBee Cluster Library

Для тех из вас, кто знаком с протоколом SNMP, ZCL выглядит как другая кодировка того же логического интерфейса. Уровень ZCL позволяет устройствам запрашивать (READ_ATTRIBUTE) и устанавливать (WRITE_ATTRIBUTE) набор значений конфигурации (кластеры), что в конечном итоге позволяет оператору (мосту) управлять лампочками. Например, атрибуты кластера управления цветом включают:

- Цветовая температура Минимальная/Максимальная
- Цвет Красный/Зеленый/Синий

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

Достичь нашей цели

Нашей целью в этом исследовании является линейка продуктов Philips Hue, а точнее Philips Hue Bridge. В качестве примечания: линейка продуктов Hue возникла в подразделении Philips-Lighting компании Philips и теперь выпускается под торговой маркой третьей компании под названием Signify.

Хотя "умные" световые решения пока не так популярны в Израиле, мы обнаружили, что во многих других странах это не так. Например, в этой статье за 2018 год говорится (https://essentialinstall.com/news/smart-home/philips-hue-takes-top-spot-for-smart-lighting-in-uk-but-market-remains-competitive/#:~:targetText=In fact, nearly 5% of,with Philips Hue smart bulbs.), что Philips Hue занимает 31% доли рынка интеллектуального освещения в Великобритании, которым пользуются более 430000 домашних хозяйств. Фактически, когда мы представили результаты нашего исследования некоторым вице-президентам нашей компании, они сказали нам, что все светильники в их доме произведены брендом Philips Hue.

На следующем рисунке, взятом из оригинального исследования, показана сетевая архитектура дома или офиса, в котором используется этот продукт:


2.png



ZLL - это аббревиатура от ZigBee Light Link, который представляет собой уровень настройки сетевого стека ZigBee, ориентированный на световые устройства: как лампочки, так и мост, который ими управляет.

С одной стороны, у нас есть устройства ZigBee: лампочки, коммутатор и бридж. А с другой стороны, у нас есть IP-устройства в "обычной" компьютерной сети: наш мобильный телефон, маршрутизатор и снова бридж. Как следует из его имени, бридж - единственное устройство, которое присутствует в обеих сетях, и его роль заключается в переводе команд, которые мы отправляем из мобильного приложения, в радиосообщения ZigBee, которые затем отправляются на лампочки.

Архитектура Бриджа

Мы уже знали, что мост использует процессор MIPS (поэтому мы изначально выбрали его), но оказалось, что его архитектура еще сложнее. На рисунке 3 мы показываем плату моста (модель 2.0) после того, как мы извлекли его из пластикового корпуса:

3.png


- Справа, отмеченный синим цветом, находится основной ЦП: QCA4531-BL3A.
- Слева, отмеченный красным, находится процессор Atmel (ATSAMR21E18E), который реализует нижние уровни стека ZigBee.

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

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

На своем веб-сайте Colin O’Flynn (@colinoflynn) описывает, как подключиться к открытому последовательному порту и получить права root на плате. Это отличное руководство для всех, кто имеет дело со встроенными устройствами Linux и, в частности, имеет дело с загрузчиком U-Boot. К сожалению, у меня не было необходимого оборудования для подключения к последовательному интерфейсу. К счастью, я посоветовался со своим младшим братом, который помог мне, и сказал, какие последовательные кабели мне нужно заказать. Итак, мы начали реверс инжиниринг старой версии прошивки (от 2016 года), которую я получил от Eyal R, пока я ждал, пока прибудут кабели.

ipbridge

Основным процессом в главном процессоре является процесс ipbridge. Базовая разведка показывает, что это классический случай файла ELF:


- Сам код компилируется в адрес статической памяти.
- Библиотеки (файлы *.so), стек и куча рандомизированы операционной системой.
- Стек не содержит canaries.
- Процесс запускается от имени "root" - это отличная новость.

Это несколько смешанное состояние, которое мы часто наблюдаем при работе с целями под управлением Linux. Операционная система включает некоторые функции безопасности по умолчанию, и обычно поставщик не пытается активно активировать дополнительные функции, такие как PIE (Position Independent Executable) или даже canaries стека. С нашей точки зрения как злоумышленников, использование уязвимости будет нелегким, поскольку существует некоторая ASLR (рандомизация адресного пространства), но это все еще возможно, потому что есть некоторые фиксированные известные адреса памяти, которые мы можем использовать в нашем эксплойте.

Перед тем, как начать реверс инжиниринг процесса, мы заметили, что дизассемблер не может различать разделы кода Mips и Mips16 (аналогично случаю Arm и Thumb в прошивке ARM).К счастью для нас, это сработало достаточно хорошо: изначально у нас было 2525 функций, а после выполнения у нас был более чистый двоичный файл с 3478 отмеченными функциями. Теперь мы начали реверс инжиниринг нашего двоичного файла без необходимости вручную улучшать анализ IDA Pro.

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

4.png


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

Прочитав еще раз заключения Eyal R. и Colin, все стало ясно. У модема есть дополнительная роль, которую мы изначально проигнорировали: он переводит двоичные сообщения в текстовое представление, а затем отправляет их через интерфейс USB-to-Serial. Таким образом, основной процессор считывает простые для обработки текстовые сообщения с последовательного устройства, которое отображается как файл в операционной системе.

Colin обнаружил доказательства того, что лампочки используют SDK Atmel BitCloud, который теперь является закрытым и должен быть приобретен у Atmel. Следовательно, имеет смысл предположить, что тот же программный стек также используется в качестве уровня "декодера" в процессора модема в мосте:

- Входящее сообщение анализируется и проверяется программным стеком BitCloud.
- Затем проанализированное сообщение преобразуется в текстовое представление.
- Это текстовое сообщение отправляется в главный процессор для обработки.

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

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

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

Ничто в этом исследовании не будет легким, поэтому мы просто добавляем это новое препятствие в наш список и продолжаем.

Поиск уязвимостей - I раунд

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

- E_ZCL_UINT32 (0x23) – 4 байта целый тип.
- E_ZCL_UINT16 (0x21) – 2 байта целый тип.
- E_ZCL_UINT8 (0x20) / E_ZCL_ENUM8 (0x30) – 1 байт целый тип / 1 байт перечисление.
- E_ZCL_BOOL (0x10) – 1 бит Булево значение (Истина/Ложно).
- E_ZCL_ARRAY (0x48) – байтовый массив переменной длины с использованием поля длиной 1 байт.

Как вы, наверное, понимаете, обработка полей переменной длины во встроенном устройстве - верный рецепт уязвимостей. На рисунке 5 показан ассемблерный код, обрабатывающий этот случай:

5.png


Примечание: Имейте в виду, что архитектура MIPS использует слот задержки, поэтому при вызове malloc() значение 0x2B передается в качестве аргумента внутри слота задержки в инструкции: li $ a0, 0x2B. Это может немного сбить с толку любого, кто впервые читает ассемблерный код MIPS.

Что мы нашли? Злоумышленник может отправить злонамеренный ответ на сообщение READ_ATTRIBUTE, содержащее искаженный массив байтов, размер которого превышает фиксированный размер 43 байта (0x2B). Это вызывает контролируемое переполнение буфера на основе кучи без каких-либо байтовых ограничений.

Возможные ограничения этой потенциальной уязвимости:

- Поскольку ZCL является относительно высоким уровнем в стеке ZigBee, мы можем позволить себе отправлять только массив размером до 70 байт. В противном случае наше сообщение будет больше ограничений сети.
- Проверка конечного автомата может потребовать, чтобы мы отвечали только на существующий запрос.
- Проверка конечного автомата может потребовать, чтобы мы ответили только правильным запрошенным типом данных.
- Модем может отбросить наше сообщение, если он нарушает логику черного ящика.

Это не самая простая уязвимость для использования, но, тем не менее, это серьезная уязвимость.

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

Тем временем мы обнаружили хак, который позволил нам проверить наличие этой уязвимости даже без передачи радиосообщения по воздуху (надеясь, что модем не заблокирует нас в дальнейшем). Процесс ipbridge поддерживает режим тестирования отладки, который активируется путем подключения к двум именованным каналам, которые процесс прослушивает с помощью потока отладки:/tmp/ipbridgeio_in и /tmp/ipbridgeio_out. Хотя эти возможности отладки не очень полезны, мы исправили двоичный файл, чтобы сообщения, поступающие по этим каналам, добавлялись в очередь сообщений, как если бы они поступали от самого модема.

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

В ожидании передатчика прибыл наш полный стартовый комплект Philips Hue с новым мостом модели 2.1 и 3 лампочками. Похоже, сейчас самое время извлечь новую прошивку из моста вместе с обновлением моста 2.0 до последней версии. Ведь до сих пор мы работали над прошивкой 2016 года, и за это время все могло измениться.

К сожалению, все действительно изменилось.

Первое, что мы заметили в новой прошивке, - это ее размер. По какой-то причине ELF-файл ipbridge вырос с 1221 КБ до 3227 КБ. Открытие его в IDA Pro показало нам главное отличие: двоичный файл (случайно?) был отправлен с отладочными символами. Это отличная новость, которая действительно может помочь нам в наших попытках реверс инжиниринга. На рисунке 6 показаны некоторые из этих символов:

6.png


Используя это новое открытие, мы узнали, что наша первоначальная обратная разработка была относительно точной, и имя уязвимой функции оказалось:
SMARTLINK_UTILS_ReadAttributeValue.

При анализе уязвимой функции в новой версии прошивки нас ждал неприятный сюрприз. Список поддерживаемых типов данных был обновлен, и теперь производитель поддерживает символьные строки (0x42) вместо байтовых массивов (0x48). Хотя строки по-прежнему имеют переменную длину, выделение теперь изменено, чтобы быть более подходящим для строк с завершающим нулем:
- A 1-байтовое поле (обозначенное как L) читает из входящего сообщения
- Выделяется A буфер размером L + 1.
- L байтов данных копируются из входящего сообщения в выделенный буфер.

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

Поиск уязвимостей - II раунд

Мы отложили модуль ZCL в сторону и в конце концов нашли путь к модулю ZDP, а точнее к обработчику входящих ответов управления LQI (Link Quality Indicator). Эти сообщения являются частью модуля, который отвечает за обнаружение соседей. Периодически мост запрашивает у лампочек их известных соседей в сети ZigBee. Хотя название предполагает, что сообщения ориентированы на качество радиопередачи, структура сообщения фактически сосредоточена на полном наборе сетевых адресов для каждого соседа.

Контекст для каждого соседа, как видно в этих сообщениях следующий:

- 8 байт - Расширенный адрес: глобально уникальный сетевой адрес (аналогичный MAC-адресу Ethernet).
- 2 байта - Сетевой адрес: короткий сетевой адрес, который является локально уникальным в текущей сети ZigBee.
- 2 байта - PAN Id: идентификатор персональной сети, идентификатор локальной сети ZigBee.
- 1 байт - LQI: индикатор качества связи в диапазоне 0–255.
- 3 байта - Разное: другие флаги, добавленные до 16 байтов на запись.

Поскольку обе стороны должны сообщать друг другу о переменном количестве соседей, которое может включать до 0x41 поддерживаемых записей в глобальном массиве соседей ipbridge, эти сообщения включают формат фрагментации. В каждом ответе лампочка сообщает мосту, что он в настоящее время отвечает L записями от смещения X до смещения X + L - 1 из возможных S записей.

Как вы помните, размеры сообщений в стеке ZigBee довольно малы, поэтому использование такого количества индексов в каждом сообщении и отправка нескольких записей по 16 байт каждая действительно ограничивает количество записей, которые могут быть включены в каждое сообщение. В результате разработчики хранят входящие записи в стеке в массиве, который может содержать до 6 записей. Однако нет никаких проверок, чтобы убедиться, что входящее поле длины действительно достаточно мало, что может привести к переполнению буфера на основе стека.

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

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

Вердикт: не использовать. По крайней мере, это избавило нас от необходимости искать уязвимости в модеме.

7.png


Примечание: максимальное количество записей, разрешенное в BitCloud SDK, равно 2. Протокол ZigBee использует несколько индексов в сообщении фрагментации, которое может содержать не более 2 записей в каждом сообщении. Это, мягко говоря, не совсем эффективно.

Поиск уязвимостей - Раунд III — CVE-2020-6007

К счастью, 3 оказалось нашим счастливым числом. После того как мы закончили аудит кода для всех различных обработчиков сообщений, у нас возник интригующий вопрос: когда мы отправляем атрибуты ZCL, кто обрабатывает их после первоначального (уже не уязвимого) синтаксического анализа?

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


8.png


По неизвестной причине из входящей структуры извлекается код операции:

- 0x0F - Вероятно, означает строковый тип, потому что ввод дублируется с помощью strdup().
- 0x10 - Вероятно, означает массив байтов, потому что ввод дублируется с использованием того же шаблона уязвимого кода, который мы видели в старой версии прошивки.

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

9.png


Похоже, что переход от поддерживающих массивов к строкам был сделан только наполовину, так как строка по ошибке помечена как "массив" с использованием константы 0x10 вместо 0x0F. Это означает, что у нас снова есть уязвимость, связанная с переполнением буфера на основе кучи, и мы смогли вызвать ее с помощью нашего взлома наряду с небольшой модификацией нашего предыдущего PoC.

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

Нюхаем подсказки

Важно отметить, что мы специально выбрали оценочную плату ATMEGA256RFR2-XPRO по нескольким причинам:

- Если нам удастся выполнить весь эксплойт с оценочной платы, мы докажем, что это возможно выполнить с помощью лампочки, поскольку они имеют точно такие же аппаратные возможности: тот же процессор, ту же антенна и так далее.
- Мы надеемся сохранить некоторый код C из предыдущего исследования, проведенного Eyal Ronen (@eyalr0) и Colin O’Flynn (@colinoflynn).

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

Вы можете ожидать, что когда вы купите продукт Atmel, который поставляется с IDE на основе Visual Studio под названием "Atmel Studio", вы легко сможете создать образец проекта ZigBee, который просто прослушивает сообщения и выводит их на выход/последовательный интерфейс. К сожалению, этого не произошло. После некоторого поиска в Google мы обнаружили, что Atmel предоставляет серию полезных туториалов на YouTube, например этот https://www.you-tube.com/watch?v=Rz5VxvnsEu0 , в котором человек, плывущий на лодке (мы не шутим), рассказывает вам, как использовать менеджер расширений и загрузить пакет, который позволяет вам создать образец беспроводных проектов. Это именно то, что мы искали изначально.

Теперь, когда мы смогли перехватить некоторые сообщения, мы соединили лампочку с нашим мостом (процесс, называемый commissioning), и распечатали сообщения на последовательном выходе. На этом этапе мы поняли, что, хотя теперь у нас есть несколько записанных сообщений, у нас действительно нет надлежащего способа преобразовать их в удобочитаемый формат. Мы пробовали различные сценарии Python с открытым исходным кодом для ZigBee, но ни один из них не оказался действительно полезным. Однако нам удалось загрузить пакеты с шестнадцатеричным дампом в Wireshark, используя следующий тип инкапсуляции, показанный на рисунке 10:

10.png


Важное примечание: Wireshark не может проанализировать сообщения, если в них есть недопустимое поле FCS (Frame Check Sequence). Когда мы передаем сообщения, это поле автоматически вычисляется и добавляется антенной. Поэтому мы рекомендуем исключить это поле из входящих сообщений и заранее выбрать тип инкапсуляции, который сообщает Wireshark, что поле FCS отсутствует. Это упрощает анализ дампов входящих и исходящих сообщений.

Даже беглый взгляд показал, что не хватает нескольких вещей:

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

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

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

Открытие криптослоя

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

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

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

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

На рисунке 11 показан пример файла ZigBee .pcap с веб-сайта Wireshark, и сообщение Transport Key выделено:


11.png


Мы видим, что, поскольку у нас нет транспортного ключа, мы не можем расшифровать сообщение транспортного ключа, и оно просто отображается как общая команда APS.

Хотя мы обнаружили несколько ключей при исследовании темы, ни один из них не помог. Похоже, мы не были первыми, кто занялся этой проблемой, поскольку в конце концов мы дошли до этого сообщения в блоге, в котором автор подробно описывает решение проблемы. Оказывается, что "обычные" ключи используются при "commissioning", но в нашем "классическом commissioning" используется другой секретный ключ. К счастью, оба ключа включены в статью, и они действительно сработали. На этот раз нам удалось успешно расшифровать сообщение внутри Wireshark. На рисунке 12 показано расшифрованное сообщение:


12.png


Примечание. Мы намеренно включили в это изображение фактический сетевой ключ.

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

Наивная попытка атаки

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

- Хорошие новости: проверки конечного автомата ZCL отсутствуют. Мост анализирует ответные сообщения на запросы, которые он даже не отправлял.
- Плохие новости: проверка неизвестного конечного автомата, которую мы обнаружили возле уязвимой функции, перенаправляет наше сообщение другой функции.

Проверка показана на рисунке 13:

13.png


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


Вывод №1: уязвимая функция доступна только при вводе в эксплуатацию новой лампочки в сети ZigBee. Законные участники сети ZigBee не могут активировать уязвимость, которую мы хотим использовать.

Classic Commissioning

Classic Commissioning - это процесс подключения (ввода в эксплуатацию) новой лампочки в нашей сети ZigBee с помощью стандартного мобильного приложения. В нашем случае мы использовали приложение Philips Hue из Android Play Store.

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

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

Вывод №2: Мост не будет принимать новые лампочки в сеть, если пользователь активно не заказывает ему поиск новых лампочек. Это хороший выбор дизайна, который значительно снижает поверхность атаки на самом мосту. В нашем сценарии атаки мы должны каким-то образом заставить пользователя нажать эту кнопку в своем приложении.

Это также означает, что перед каждым экспериментом мы должны были нажимать кнопку в приложении (давая нам период отсрочки в 1-2 минуты), и только затем запускать нашу программу с оценочной платы. Так было, когда мы пытались узнать о сообщениях на этапе ввода в эксплуатацию, а также при тестировании эксплойта. Не совсем гладкая автоматическая процедура, но со временем она сработала.

Как мы обещали ранее, вот ссылка на полную запись в формате .pcap ( https://github.com/CheckPointSW/Cyber-Research/tree/master/Vulnerability/Smart_Lightbulbs) классического ввода в эксплуатацию с нашей моделью моста до момента, когда мобильное приложение уведомит нас о новой лампочке. Сообщения удаляются из своего поля FCS, а pcap не содержит сообщений IEEE 802.15.4 Ack, поскольку они отправляются в качестве подтверждения почти после каждого сообщения.

На рисунке 14 показана созданная нами новая лампочка, которая отображается в приложении, если пользователь запрашивает полную информацию.

14.png


Как видите, на этапе ввода в эксплуатацию происходит обмен несколькими управляемыми строковыми полями. Мы решили обозначить нашу новую лампочку как новую лампочку Check Point Research, модель "CPR123".

Этап ввода в эксплуатацию можно разделить на 4 основные части:

- Ассоциация: появляется новая лампочка, которая связана с коротким сетевым адресом.
- Принятие: новая лампочка получает сетевой ключ и сообщает о себе с помощью сообщения Device Announce.
- Бюрократия: мост запрашивает у лампочки несколько дескрипторов.
- ZCL: мост выдает несколько запросов READ_ATTRIBUTE ZCL (ZigBee Cluster Library), чтобы узнать о характеристиках лампочки.


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

Атака на кучу

Мы решили решать наши проблемы по очереди. Наша первая цель состояла в том, чтобы успешно использовать уязвимость на основе кучи и перейти к произвольному адресу памяти, а затем обнаружить, куда перейти. Это оказалось неправильным решением, поскольку куча сильно изменялась в зависимости от сообщений, с которыми мы помещали шелл-код в память цели.

Первое, что нужно сделать при эксплуатации переполнения буфера на основе кучи, - это проверить, какая реализация кучи используется целью. В нашем случае цель использует uClibc, что означает "micro LibC". Точная версия четко указана в имени файла библиотеки: libuClibc-1.0.14.so. Имея на выбор несколько различных реализаций кучи, которые поддерживаются этой библиотекой, мы легко заметили в двоичном коде использование "стандартной реализации malloc", которая основана на dlmalloc.

Для небольшой реализации LibC, основной целью которой являются продукты с ограниченными ресурсами памяти и ЦП, реализация довольно проста:

- Fast-Bins хранит небольшие свободные буферы, используя односвязный список.
- В двусвязном списке хранятся остальные свободные буферы.
- Несколько раз выполняется консолидация для оптимизации/очистки кучи.

Для "стандартной" реализации dlmalloc это метаданные, используемые этой реализацией кучи:

15.png


- Когда буфер выделяется и используется, первые два поля сохраняются перед буфером данных пользователя.
- Когда буфер освобождается и помещается в Fast-Bin, третье поле также используется и указывает на следующий узел в связанном списке Fast-Bin. Это поле находится в первых 4 байтах пользовательского буфера.
- Когда буфер освобожден и не помещен в Fast-Bin, третье и четвертое поля используются как часть двусвязного списка. Эти поля расположены в первых 8 байтах пользовательского буфера.

Выбираем нашу цель внутри кучи

Двусвязные списки иногда предлагают отличный примитив для эксплойтов, поскольку во время отключения списка поврежденный узел может вызвать операцию Write-What-Where. Однако мы уже не в начале 2000-х, и этот примитив не будет работать для нас в этой популярной реализации кучи. Вместо этого разработчики развернули механизм защиты, известный как "Safe Unlinking", который проверяет "forward" и "backward" указатели перед их использованием.

16.png


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

Fast-Bins представляют собой массив "ячеек" разного размера, каждая из которых содержит односвязный список фрагментов до заданного размера. Минимальный размер ячейки содержит буферы размером до 0x10 байт, следующий содержит буферы размером от 0x11 до 0x18 байтов и так далее. В ходе исследования мы обнаружили интересную ошибку в реализации метода free():

17.png


Основываясь на том, что наименьший размер выделения должен быть 0x10, макрос fastbin_index() делит размер на 8, вычитает из него 2 и использует результат в качестве индекса для массива Fast-Bin. Если мы можем повредить запись метаданных для данного освобожденного фрагмента, мы можем изменить этот индекс на одно из недопустимых значений: -1 или -2.

18.png


Использование недопустимого значения -1 сохраняет наш освобожденный буфер в поле max_fast, которое отвечает за настраиваемый максимальный размер для fast bin. Сохранение указателя в этом поле, вероятно, нанесет ущерб, но как насчет недопустимого индекса -2?

Используя отладчик, мы увидели, что перед глобальной структурой malloc_state ничего не хранится, а это означает, что сохранение указателя в fastbins[-2] не испортит ничего важного. Кроме того, malloc() не подумает о проверке этого недопустимого Fast-Bin на предмет любого выделения, которое будет возвращено пользователю. Для любого практического использования мы просто создали /dev/null bin, дающий нам примитив для утечки памяти из кучи, примитив, который может помочь нам привести его в желаемое состояние.

План переполнения

Наша уязвимость дает нам контролируемое переполнение буфера на основе кучи из буфера размером 0x2B до примерно 70 байт. Из-за базовых выравниваний в куче мы, скорее всего, получим буфер размером 0x30 (мы получим буфер большего размера, только если у нас закончатся подходящие буферы). Кроме того, в реализации кучи есть странность:

- Байты 0x00-0x04: поле размера из нашего malloc_chunk.
- Байты 0x04-0x2C: буфер данных пользователя (который на 4 байта короче, чем нам нужно).
- Байты 0x2C-0x30: "недостающие" 4 байта, также действующие как поле prev_size блока malloc_chunk, расположенного после нас в памяти.

Эта причудливая реализация, вероятно, сэкономила кому-то 4 байта на каждый блок malloc, но она, конечно же, не упростила чтение или отладку кода.

Имея в виду все эти детали, наш генеральный план состоит в том, чтобы переполнить соседний свободный буфер, расположенный в Fast-Bin. На рисунке 19 показано, как выглядят буферы до нашего переполнения:

19.png

На рисунке 20 показаны те же два буфера после нашего переполнения:


20.png

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

Мы также модифицируем то, что, как мы надеемся, является односвязным указателем на запись Fast-Bin. Изменяя этот указатель на наш собственный произвольный адрес, мы можем заставить кучу думать, что теперь там хранится новый освобожденный кусок. Запуская последовательность выделения размера, соответствующего размеру соответствующего Fast-Bin, мы можем получить примитив Malloc-Where, с помощью которого мы планируем добиться выполнения нашего кода.

Вот краткое описание различных сценариев, с которыми мы можем столкнуться во время нашего переполнения:
- Буфер после нас свободен и помещен в Fast-Bin. Успех, поскольку мы повредили указатель Fast-Bin и можем использовать его для получения желаемого примитива Malloc-Where.

- Буфер после нас уже используется и будет свободен. Частичный успех, так как операция free() будет использовать наш поврежденный размер и сохранять его в папке /dev/null.

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

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

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

Специальное примечание: после того, как мы закончили это исследование, мы разработали средство защиты под названием "Safe Linking", которое защищает односвязные списки в куче от эксплойтов, подобных тому, который мы только что описали. Эта функция уже интегрирована в последние версии uClibc-NG и glibc.

Формирование кучи

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

Обладая этим важным открытием и зная, что мы переполняем кучу из-за выделения памяти размером 0x30 байт, мы разработали простой план:

- Отправить несколько строк ZCL, которые распределены по размерам 0x28 и 0x30.
- Отправить (очень) несколько переполняющихся строк ZCL, направляя захваченный указатель Fast-Bin в глобальную таблицу смещения (GOT).
- Отправить дополнительный пакет сообщений размером 0x30 в надежде получить примитив Malloc-Where.

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

На втором этапе мы надеемся изменить указатель Fast-Bin, чтобы он указывал непосредственно на адрес указателя на free() в GOT. Таким образом, третья фаза отправляет сообщения, и одно из них сохраняется в GOT, поскольку куча ошибочно считает, что это свободный буфер кучи. Этот примитив Malloc-Where теперь превращается в полностью контролируемый сетевой пакет, который записывается в произвольный адрес памяти, очень сильный примитив эксплойта. И сам триггер сразу же; при вызове free() одно из наших сообщений перескакивает на выполнение нашего шелл-кода.

Хранение нашего шеллкода

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

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

Плюсы

- Глобальный массив расположен по фиксированному известному адресу памяти.
- Массив (как и все другие глобальные переменные с возможностью записи) имеет права памяти RWX.
- Массив относительно большой: он может содержать до 0x41 (65) записей размером 0x10 (16) байт.

Минусы

- Мы не можем полностью контролировать всю запись размером 16 байт.

Позже мы также узнали, что мы даже не можем использовать всю емкость записей 0x41. Однако, когда у вас не так много вариантов, вы не можете позволить себе быть разборчивым.

Ограничения на каждую соседнюю запись:

- Байты 0x00-0x08: Расширенный сетевой адрес - Полностью управляемый.
- Байты 0x09-0x0A: Короткий сетевой адрес - Полностью управляемый.
- Байты 0x0A-0x10: Разные поля — неконтролируемые.

Вдобавок ко всему, у нас действительно нет 10 соседних контролируемых байтов, поскольку мост проверяет уникальность каждой записи. Каждый "расширенный сетевой адрес" должен быть уникальным, что легко сделать из-за его размера в 8 байтов. Каждый "короткий сетевой адрес" также должен быть уникальным, а это совершенно другая история, поскольку мы должны проявить творческий подход, чтобы обойти это ограничение и использовать как можно больше байтов.

Правильный способ доставки наших "записей о соседях" на мост - это управляющие сообщения LQI (Link Quality Indicator). Однако на этот раз и модем, и основной ЦП отслеживают правильность конечного автомата, и мы можем отправлять наши сообщения только в качестве правильных ответов на запросы, исходящие от самого моста. К сожалению, мост выдает эти запросы только после завершения фазы ZCL, а это означает, что мы можем подготовить шелл-код в памяти цели только после того, как окно возможности для эксплуатации закрыто.

На этом этапе мы проверили содержимое массива памяти и увидели, что наши сетевые адреса также хранятся здесь, хотя мы еще не отправили никаких сообщений LQI. Дальнейшее изучение показало, что сообщение DEVICE_ANNOUNCE, которое мы передаем на этапе принятия, также добавляет одну запись в массив соседей. Фактически это означает, что это массив адресной книги, а не "массив соседей".

21.png



Здесь все начало запутываться. Для каждого нового адреса мост отправляет соответствующий запрос маршрута, пытаясь узнать, как достичь этого нового узла ZigBee. Эти передачи сделали мост довольно нестабильным и повлияли на и без того нестабильные таймауты остальных конечных автоматов протокола. Нашим решением этой новой проблемы было использование нескольких лампочек:
- Правильная лампочка, которая появляется в мобильном приложении пользователя, а затем использует бэкдор, который мы планируем установить.

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

- Дополнительная фальшивая лампочка, которая достигает фазы ZCL и использует уязвимость теперь, когда шелл-код уже находится в памяти.

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

Идеальный дизайн шеллкода

Если мы используем инструкции сборки Mips16, большинство наших инструкций состоят из 2 байта каждая, а более сложные инструкции состоят нам 4 байта каждая. В идеале мы можем использовать первые 8 байтов для выполнения нескольких инструкций сборки и использовать последние 2 байта для перехода к следующей записи. В большинстве случаев мы перескакиваем на 6 байтов вперед (к следующей записи), а это означает, что инструкции перехода каждый раз одинаковы и нарушают ограничение. Однако мы можем использовать различные инструкции перехода, если, например, у нас есть условные переходы.

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

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

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

Хотя шелл-код работал нормально в нашей фиктивной среде, он столкнулся с несколькими препятствиями, когда мы попробовали его на нашей реальной цели.

Во-первых, шеллкод был дорогим: он состоял из 0x19 записей; изначально мы отправляли только 0x10 записей при тестировании эксплойта для уязвимости на основе кучи. Простое добавление всего 9 записей оказалось слишком большим: мост был слишком неустойчивым, и наша третья лампочка не достигла фазы ZCL.

После долгих вычислений нам удалось втиснуть наш прекрасный настраиваемый шелл-код в записи 0x12 не очень удобочитаемого шелл-кода. Мы успешно обошли это ограничение по размеру и смогли начать отладку нашего шелл-кода на реальной цели (используя наш удаленный gdbserver).

Здесь мы обнаружили недостатки в нашем первоначальном плане. Цикл декодера в архитектуре Mips требует, чтобы мы вызывали sleep(), чтобы у нас не было проблем с кешем. В противном случае наши переупорядоченные записи не будут распространяться (сбрасываться) в кэш инструкций процессора (I-Cache), и фактически он выполняет некоторый случайный мусор вместо нашего полного шелл-кода. Эта функция sleep() означала, что мы в значительной степени разрушили целевую кучу, и пока мы спали прекрасным сном, другие потоки были оставлены, чтобы разобраться с нашим беспорядком и потерпели крах.

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

Смелый дизайн шеллкода

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

Мы вернулись к чертежной доске и через несколько дней нам удалось написать новый шелл-код, который выполняет следующий набор задач (по порядку):

- Восстановление потока выполнения: стабилизация кучи, восстановление GOT и так далее.
- Отключить сторожевой таймер: убедитесь, что он не заметит, что мы отправили слишком много сообщений во время эксплойта (или, по крайней мере, убедитесь, что никто его не слышит).
- Установите бэкдор: mprotect() определенную страницу памяти для разрешений RWX и измените необходимые байты, чтобы разместить наш бэкдор в нужном месте.

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

В конце концов, после некоторой отладки мы получили рабочий шелл-код из 0x10 записей. На рисунке 22 показана структура памяти нашего шелл-кода, как показано в IDA:

22.png


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

Наш бэкдор

Мы не собираемся слишком глубоко погружаться в технические аспекты нашего бэкдора, поскольку мы не публикуем полностью вооруженный эксплойт. Мы можем поделиться тем, что наш бэкдор дал нам примитив Write-What-Where, используя специально созданное сообщение, которое мы теперь можем отправить на целевой мост с нашей "законной" лампочки. Мы использовали этот стабильный примитив записи для записи загрузчика Scout в память RWX, а затем использовали тот факт, что код все еще доступен для записи, чтобы перенаправить выполнение на наш новый шелл-код.

Загрузчик Scout просто подключился через TCP к нашим серверам, получил исполняемый файл, который нужно было отбросить и развернуть на мосту, и выполнил его. На рисунке 23 мы видим процесс /tmp/exploit, который выполняет следующий этап нашей атаки.

23.png


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

Объединение частей эксплойта

В нашем сценарии атаки мы хотим взять под контроль мост из сети ZigBee и использовать его как точку воздействия для атаки дополнительных компьютеров в IP-сети. Но во-первых, наша уязвимость требует, чтобы мы обманом заставляли пользователя искать новые лампочки, а это не совсем простой шаг. Используя примитивы атаки из первоначального исследования, мы разработали следующий план:

- Используйте сенсорную ссылку (использованную в первоначальном исследовании) и украдите лампочку из сети пользователя, чтобы теперь она перешла под наш контроль.

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

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

- Пользователь в конце концов видит, что с лампочкой что-то не так. В мобильном приложении она отображается как “Unreachable”. Затем пользователь "сбрасывает" её.

- Единственный способ сбросить лампочку - удалить ее из приложения, а затем сказать мосту, что нужно искать новые лампочки. Бинго! Теперь мы можем начать атаку.

- Украденная лампочка находится в другой сети ZigBee, поэтому мост не обнаружит ее.

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

- Потихому мы создаем дополнительные фантомные лампочки, которые используют уязвимость в мосту и устанавливают наш бэкдор.

- "Законная" лампочка использует этот бэкдор для установки вредоносного ПО на целевой мост.

- Наше вредоносное ПО подключается к нам через Интернет, и теперь мы успешно проникли в IP-сеть цели из радиосети ZigBee.

Для нашей демонстрации мы решили использовать утекший эксплойт NSA EternalBlue, как и в нашем исследовании FAX. Эксплойт запускается с самого моста и используется для атаки непропатченных компьютеров внутри IP-сети цели.


Примечания по защите продукта

Во второй части видео на YouTube вы можете увидеть попытку эксплуатации того же уязвимого моста Hue Bridge, когда на этот раз мы установили на него наш наноагент IoT. Этот нано-агент обеспечивает целостность управления потоком (CFI) и добавляет защиту устройства к самой прошивке, таким образом успешно выявляя и блокируя нашу атаку, даже не зная про эксплоит нулевого дня, который мы использовали.

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

Скоординированное раскрытие информации

- 5 ноября 2019 г .- Компания Philips сообщила об уязвимостях и направила их в компанию Signify.
- 5 ноября 2019 г. - Компания Signify приняла к сведению наш отчет и подтвердила наличие уязвимости в своем продукте.
- 25 ноября 2019 г. - Компания Signify уведомила нас, что они завершили разработку и тестирование патча и что он будет выпущен в январе 2020 г.
- 13 января 2020 г. - Патч был развернут как удаленное обновление прошивки (1935144040).
- 28 января 2020 г. - Из-за географического распределения нашему мосту потребовалось некоторое время, чтобы автоматически установить обновление прошивки.
- 5 февраля 2020 г. - Мы выпустили демонстрационное видео для повышения осведомленности и держали технические подробности до тех пор, пока у пользователей не будет достаточно времени, чтобы обновить свои продукты.
- 7 августа 2020 г. - Полное публичное раскрытие информации во время DEF CON 28.

Источник: https://research.checkpoint.com/2020/dont-be-silly-its-only-a-lightbulb/
Автор перевода: yashechka
Переведено специально для портала xss.pro (c)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
одна из самых интересных статей которые я читал. Но как это может быть монетизировано?
ну например точка входа или армия iot лампочек, люблю эту контору, спасибо за перевод
 
Пожалуйста, обратите внимание, что пользователь заблокирован
одна из самых интересных статей которые я читал. Но как это может быть монетизировано?
Первое что на ум пришло это майнинг, но сомневаюсь что на IoT-устройствах можно хорошо майнить, но все же...
Второе это требовать выкуп, чтобы хозяин обратно получил доступ к управлению умного дома.
Третье ботнет из IoT-устройств для DDoS-атак aka mirai etc
Четвертое фан хулиганство раздражать жильцов дома или изжить их из дома...
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Пожалуйста, обратите внимание, что пользователь заблокирован
Да вот получается еще к списку шпионаж за жильцами дома. Тоже можно монетизировать в некотором смысле... Весть наблюдение и т.д.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Да вот получается еще к списку шпионаж за жильцами дома. Тоже можно монетизировать в некором смысле... Весть наблюдение и т.д.
Читал про спецов из Сингапура, они заложили концепцию, что когда человек вставляет ключ в затвор, делает оборот и открывает дверь вытащив ключ другой человек может записать как он это делает (именно записать звук) а потом преобразовать это в определенные данные специальным ПО и таким образом сделать дубликат ключа. Тут если так представить, точки компрометации везде, абсолютно . Если кому интересно, атака Spikey называется
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Читал про спецов из Сингапура, они заложили концепцию, что когда человек вставляет ключ в затвор, делает оборот и открывает дверь вытащив ключ другой человек может записать как он это делает (именно записать звук) а потом преобразовать это в определенные данные специальным ПО и таким образом сделать дубликат ключа. Тут если так представить, точки компрометации везде, абсолютно
Верно сказано. Сейчас это называется умными словами "атаки по сторонним каналам". Вот кстати пример https://xss.pro/threads/35511/ Не так давно сам разбирался что это такое и с чем едят. правда в статье не про дверные замки, но принцип тот же.
 
Последнее редактирование:
Весьма интересный вектор атаки. Фактически, если немного упрощенно, то это позволяет с помощью радиоканала получить доступ к ip сети в которой находится шлюз. В будущем это весьма перспективный вектор, поскольку будет позволять осуществлять таргетированные атаки на сети к которым часто нет возможности подключиться извне иначе (например, домашняя сеть какого-то топ менеджера какой-то крупной компании).
Чем-то похоже по вектору на атаки на радиоклавиатуры/мышки.
 
Пожалуйста объясните, что ты имеешь в виду? Шпионить за CEO через умную лампочку? Я правильно понял? Интересное предложение, и я вижу большой потенциал в этом способе...
 
Последнее редактирование:
Пожалуйста, обратите внимание, что пользователь заблокирован
Пожалуйста объясните, что ты имеете в виду? Шпионить за CEO через умную лампочку? Я правильно понял? Интересное предложение, и я вижу большой потенциал в этом способе...
Всё правильно вы поняли. Смотрите пост w00du -> https://xss.pro/threads/41229/post-253340
 
Перед тем, как начать реверс инжиниринг процесса, мы заметили, что дизассемблер не может различать разделы кода Mips и Mips16 (аналогично случаю Arm и Thumb в прошивке ARM).К счастью для нас, это сработало достаточно хорошо: изначально у нас было 2525 функций, а после выполнения у нас был более чистый двоичный файл с 3478 отмеченными функциями. Теперь мы начали реверс инжиниринг нашего двоичного файла без необходимости вручную улучшать анализ IDA Pro.
This was a good time to test if Thumbs Up, originally tested only on Intel and Arm binaries, also produces improved analysis in our Mips binary.

Пропустили предложение, добавьте пожалуйста после "ARM)"
Интересная статья. На практике попробовать вряд ли удастся, а жаль
 
This was a good time to test if Thumbs Up, originally tested only on Intel and Arm binaries, also produces improved analysis in our Mips binary.

Пропустили предложение, добавьте пожалуйста после "ARM)"
Интересная статья. На практике попробовать вряд ли удастся, а жаль
" На практике попробовать вряд ли удастся " Почему ты так думаешь?
 
" На практике попробовать вряд ли удастся " Почему ты так думаешь?
Нужна где-то подопытная сеть ZigBee с такими лампочками и прошивкой без патча, вектор очень уж узконаправлен. Да и вообще, атаки на умные дома в небольших городах СНГ тема не очень актуальная)
Статья хорошо подходит для расширения кругозора, мол, не только через ПК и телефоны можно доступ получать в сеть.
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх