Многие современные компьютерные системы (материнские платы в ПК, смартфоны, сетевое оборудование…) работают под управлением прошивки, которая, как правило, разрабатывается под конкретное железо, может использовать весь спектр доступных аппаратных ресурсов и имеет самые высокие привилегии. Защите прошивок необходимо уделять особое внимание, иначе она будет настоящей Ахиллесовой пятой в безопасности системы.
Этому вопросу будет посвящён небольшой цикл статей, мы покажем слабую и сильную модели безопасности прошивок на реальных примерах.
Кстати, в основе этой статьи – наше исследование защищённости промышленных сетевых коммутаторов, которое было представлено мной на хакерской конференции ZeroNights 2015 (доклад «Модификация прошивок промышленных свитчей», презентация лежит здесь).
Введение
Вначале расскажем об объектах нашего исследования – промышленных коммутаторах.
Сердцем любой современной инфраструктуры АСУ ТП является среда передачи данных. В подавляющем большинстве случаев она представляет собой промышленную сеть типа Industrial Ethernet, т.е. основанную на семействе технологий Ethernet. Такая сеть от обычной отличается, прежде всего, использованием протокола реального времени (например, Profinet, EtherCAT, Ethernet/IP и другие).
Пример промышленной сети [картинка отсюда]:
Различного рода устройства (ПЛК, панели HMI, управляющие ПК, полевые устройства и прочие) к сети подключаются через сетевые коммутаторы (свитчи) промышленного типа. В отличии от обычных коммутаторов они менее требовательны к условиям эксплуатации (расширенный диапазон рабочих температур, защита от перепадов напряжения, ударопрочность, возможность крепления на DIN-рейку и т.д.) и поддерживают промышленные сетевые протоколы.
Таким образом, промышленные коммутаторы являются критическим элементом структуры промышленной сети. Очень важно должным образом защищать их от компрометации потенциальным злоумышленником потому, как это позволит получить практически безграничные возможности контроля над технологическим процессом: компрометация других устройств в сети, вмешательство и изменение данных внутри различных соединений между ПЛК и SCADA, между шлюзами и ПЛК, подделывание данных, передаваемых на HMI и в системы журналирования и т.д. Всё это может повлечь за собой потерю контроля оператором над реальным состоянием технологического процесса и, как результат, остановку или аварию.
Чтобы этого не произошло:
- во-первых, территориальное размещение коммутатора должно сводить к минимуму возможность несанкционированного физического доступа к нему;
- во-вторых, программно-аппаратная архитектура коммутатора должна иметь модель информационной безопасности, учитывающую современные угрозы.
О последнем и поговорим.
Объекты исследования
Для исследования мы взяли по одной модели управляемых промышленных коммутаторов от двух самых распространённых производителей промышленного сетевого оборудования:
- Hirschmann RS20
- Phoenix Contact FL SWITCH MM HS
Управлять работой этих свитчей можно через COM-порт (у обоих есть разъём RS-232) или на сетевом уровне.
При работе через COM-порт мы имеем дело с консолью для ввода команд:
Доступ к консоли требует ввода логина и пароля. Тем не менее, до экрана аутентификации доступны некоторые опции, например, вывод на экран информации о железе и прошивке, обновление прошивки и т.п.
При работе со свитчом по сети можно достучаться (по его IP-адресу) до веб-интерфейса:
Для доступа к нему требуется аутентификация.
Ещё один вариант управления свитчом на сетевом уровне — протокол SNMP (Simple Network Management Protocol), в котором тоже есть аутентификация. Однако, поддержка SNMP в исследуемых свитчах имеет несколько недостатков:
- по умолчанию (а это самая любимая конфигурация большинства сетевых устройств) используется самая небезопасная версия этого протокола – SNMP v1;
- в SNMP v1, дефолтные логин и пароль вендор этих устройств настоятельно рекомендует не изменять;
- в версиях SNMP v1 и SNMP v2c не используется шифрование, а значит протокол уязвим к атакам типа MITM (man in the middle).
Вначале поговорим об исследовании коммутатора Hirschmann RS20, затем обозначим особенности Phoenix Contact FL SWITCH MM HS в сравнении с этим свитчом.
Исследование промышленного коммутатора Hirschmann RS20
Прошивка
Сначала необходимо достать прошивку, понять, что за процессор её исполняет, и оценить возможность подключения программатора/отладчика. Для этого мы заглянули внутрь и увидели:
- CPU Digi NET+ARM NS9360B-0-I155, 32-разрядный ARM9, без внутренней памяти (следовательно, прошивка должна хранится во внешней памяти);
- Оперативная память SDRAM Micron MT48LC8M16A2 на 16 МБ;
- Флэш-память Intel 28F640JD3D75 на 8 МБ (скорее всего, прошивка здесь);
- CPLD Marvell 88E6095F-LG01, выполняет функцию Ethernet свитча, имеет внутреннюю конфигурационную память.
Микросхема флэш-памяти выполнена в корпусе BGA. Если мы её выпаяем, будет очень сложно впаять её обратно без инфракрасной паяльной станции. Поэтому прошивка (версии 8.0.07) для этого коммутатора была слита с открытого ftp-сервера Hirschmann.
Один из файлов в скачанном архиве – бинарник rsL2E.bin (около 4 МБ), это и есть образ прошивки. Покопавшись в нём, мы увидели, что он состоит из двух модулей. Каждый модуль имеет заголовок (их структура одинакова), а также сжатое тело.
Первый модуль сжат по алгоритму zlib (RFC 1951). Именно в нём хранится исполнимый код. В распакованном виде модуль весит примерно 7 МБ.
Второй модуль сжат по алгоритму gzip (RFC 1952), в нём находится pack200-архив, после распаковки которого получается JAR (Java Archive) файл, представляющий собой реализацию веб-интерфейса устройства. После распаковки модуль весит примерно 3 МБ. Кстати этот файл передаётся на хост (управляющий ПК) при обращении к коммутатору по его IP-адресу (т.е. при попытке доступа к веб-интерфейсу устройства) и исполняется именно на нём (на хосте).
Видно, что суммарный объём распакованных модулей составляет 10 МБ, а объём флэш-памяти на системной плате устройства – 8 МБ. Поэтому мы предположили, что образ прошивки хранится в запакованном виде. А значит, должен быть и загрузчик, который эту прошивку распаковывает и запускает. Но о загрузчике позже.
Размер каждого заголовка модуля составляет 256 байт. Структура его нигде не документирована, поэтому пришлось разбирать методом научного тыка. Поля, которые привлекли наше внимание:
- сигнатура модуля;
- тип модуля;
- размер модуля;
- контрольная сумма модуля (CRC32);
- смещение до конца файла (eof offset);
- контрольная сумма модуля (повтор) (CRC32);
- контрольная сумма заголовка (CRC32).
Исходя из этого, можно сделать вывод о наличии контроля целостности прошивки. Но контроль подлинности, обычно это ЭЦП (электронно-цифровая подпись), отсутствует.
Возможность подделывать эти прошивки обязательно надо проверить, для этого мы написали небольшой скрипт, позволяющий быстро извлекать оба модуля из образа прошивки, и, после внесения в них изменений – собирать обратно в готовый образ:
Но, прежде чем вносить изменения, надо подумать. И поревёрсить.
Оказалось, внутри прошивки находится код ОСРВ (операционная система реального времени) VxWorks, причём довольно древней версии 5.4.2 (где-то 1998 год). На момент написания статьи самая последняя версия — 7.
В китайских «интернетах» мы нашли исходники для VxWorks 5.5, что существенно облегчило идентификацию различных функций ОС, libc-процедур и прочего. Тот, кто сталкивался с задачей анализа VxWorks кода наверняка сейчас подумает: «Посмотри в конец, у VxWorks-образов всегда есть таблица символов!». Она есть, но в таком виде почти бесполезна:
VxWorks — продукт модульный, и состав модулей определяет заказчик, когда покупает исходники. В этом случае, помимо базовых компонентов, мы увидели модули веб-сервера (EmWeb), SnmpOverHttp (да-да, в снятом трафике мы видели SNMP-пакеты внутри HTTP-запросов) и прочие.
О наполнении вендор определённо позаботился.
А вот о безопасности — не очень. Здесь линейное адресное пространство, исполнение кода может осуществляться из любого места в памяти, защиты от переполнений на стеке тоже нет и т.д. Элементарные механизмы защиты от эксплуатации бинарных уязвимостей отсутствуют напрочь. Может, они не нужны? Но ведь зарегистрированных уязвимостей для этой версии VxWorks полно:
- CVE-2015-3963 spoof TCP sessions;
- CVE-2010-2968 brute-force;
- CVE-2010-2967 obtain access;
- CVE-2010-2966 obtain access;
- CVE-2010-2965 RCE;
- CVE-2008-2476 DoS;
- ...
Выбирай на любой вкус: DoS (Denial of Service), RCE (Remote Code Execution), возможности для подбора (brute-force), возможности для обхода авторизации. Перечень не полный.
Но не надо расстраиваться! Ведь в ходе анализа прошивки были найдены очень интересные фрагменты кода:
- обработчики SNMP-запросов;
- обработчики консольных команд;
- чтение и перезапись флэш-памяти;
- чтение и перезапись конфигурационной памяти CPLD Marvell!
Поревёрсили, теперь можно похачить.
Для этого следует грамотно выбрать место для внедрения кода: нельзя допустить, чтобы он препятствовал нормальному функционированию коммутатора, и лучше всего, если он будет вызываться по требованию.
Очевидным выбором стал один из обработчиков консольных команд. Конкретнее, обработчик команды «logout». На его место в прошивке мы записали код, считывающий память заданного размера по заданному адресу (всё задаётся в переменных в конце вставленного фрагмента), и выводящий снятый дамп в COM-порт:
Мы сделали готовый образ, обновили им коммутатор (обновлять прошивку можно и через COM-порт, и через веб-интерфейс). Успех! Действительно, после ввода команды logout вместо того, чтобы разлогиниться, теперь выводился дамп памяти:
Тем самым, подтвердилась возможность подделывать прошивки.
Но как злоумышленник может внедрить свою прошивку в коммутатор, реально использующийся на промышленном объекте?
Рассмотрим возможность обновления через COM-порт (т.е. через консольный интерфейс). Как уже говорилось, чтобы обновить прошивку коммутатора не требуется знать логин и пароль, но необходимо иметь физический доступ к устройству (чтобы воткнуться в RS-232). В этот вариант слабо верится, если устройство уже используется на объекте.
Тем не менее, с завода-изготовителя свитч сразу не попадает на промышленный объект. В схеме доставки до заказчика всегда есть промежуточные организации, которые имеют возможность, в качестве бесплатного бонуса, загрузить на коммутатор неоригинальную прошивку.
Еще вариант (правда это уже вектор распространения): заразить прошивку свитча можно с предварительно скомпрометированного управляющего ПК, который уже подключён к свитчам по COM-порту.
Удалённо модифицировать прошивку свитча сложнее, но attack surface гораздо шире. Вспомним, что для доступа к веб-интерфейсу коммутатора требуется аутентификация. Что можно сделать? Попробовать:
- ввести дефолтные логин и пароль;
- подобрать с учётом известных ограничений на пароль. Благо, защиты от brute-force атак здесь нет;
- эксплуатировать бинарную уязвимость (известную или честно найти свою), опять же, защиты от эксплуатации бинарных уязвимостей нет.
Кстати, удалённо — это не только с ПК, подключённого к коммутатору. А также с одного из полевых устройств, которые, бывает, находятся на неохраняемой территории. А значит должны быть обязательно похачены!
Вывод следующий. Потенциальный злоумышленник при внедрении своего кода в прошивку коммутатора имеет возможность:
- исполнять свой код на CPU коммутатора (используя весь спектр его аппаратных ресурсов);
- исполнять свой код на стороне хоста (управляющего ПК) или любого другого клиентского ПК, случайно обратившемуся по IP-адресу свитча. Конечно, этот код будет исполняться в Java машине, но она, как известно, не оплот безопасности.
Заметим, что скомпрометированный коммутатор можно «вылечить» путём штатной процедуры обновления прошивки. Главное, чтоб в подлинности нового образа вы были уверены.
В любом случае, это сразу наводит на вопрос о возможности закрепления на устройстве с тем, чтобы вносимые в прошивку изменения «переживали» бы любые обновления. И тут мы вспомнили про загрузчик, дампа которого у нас не было.
Загрузчик
Понадеявшись, что загрузчик оставил след в оперативной памяти, мы дампили (при помощи вышеописанного фрагмента кода) её в разных местах, но ничего не нашли. И решили попробовать достать его из флэш-памяти коммутатора, дёргая ранее найденные процедуры для чтения флэш-памяти. И снова успех.
Итак, содержимое флэш-памяти можно условно разделить на три региона:
- Bootblock, первые 80000h байт. Это загрузочная область, здесь хранится загрузчик, который состоит из трех частей:
- стартовый код;
- основной код (сжат по алгоритму Хаффмана);
- заголовок (структура идентична ранее описанной структуре заголовка модуля прошивки);
- Application firmware, самая большая область, здесь хранится образ прошивки в упакованном виде, как и предполагалось;
- Storage, область для хранения служебной информации, конфигураций, логов и т.д.
Код загрузчика позволил нам реконструировать ранние этапы процесса загрузки коммутатора.
При старте первые 4 КБ флэш-памяти (а это как раз размер стартового кода) проецируются в адресное пространство CPU по адресу 0. С этого адреса начинается исполнение.
Задача стартовой части загрузчика заключается в конфигурировании карты памяти, распаковке основной части загрузчика в память и передаче ей управления.
Основной код загрузчика должен:
- Проинициализировать аппаратные ресурсы CPU;
- Сконфигурировать модель прерываний;
- Распаковать в память прошивку и передать ей управление.
Сразу на ум приходит способ модификации загрузчика. Коммутатор обновляется модифицированной версией прошивки, которая, используя штатные процедуры для работы с флэш-памятью, перепишет область bootblock.
В дальнейшем, модифицированный загрузчик будет иметь возможность при каждой загрузке вносить изменения в распакованный образ прошивки. Скомпрометированный таким образом коммутатор «вылечить» уже не так просто.
Возможно ли «вылечить» свитч штатными средствами? Для этого надо обновить на оригинальные и прошивку, и загрузчик.
В консольном интерфейсе возможности обновлять загрузчик нет, хотя в коде прошивки были найдены процедуры, предназначенные для обновления области bootblock таким же образом, как обновляется прошивка. Но эти функции нигде не вызываются, стало быть, это недокументированный отладочный функционал.
А вот в веб-интерфейсе коммутатора была найдена вполне себе штатная опция для обновления загрузчика:
Вопрос только в том, чем обновлять? А ничем!
В архиве с образом прошивки для многих моделей своих устройств Hirschmann не прикладывает образ загрузчика. И исследуемая модель в их числе.
Получить образ загрузчика, связавшись с техподдержкой, тоже не получится. Мы пытались, и получили ответ, что образы загрузчика не распространяются. Единственное, что удалось от них добиться, – предложение отправить девайс им, воспользовавшись формой RMA. Однако они всячески будут отговаривать вас это делать, искренне считая этот процесс бесполезным.
Таким образом, потенциальный злоумышленник имеет возможность через модификацию прошивки закрепляться в загрузчике устройства. И выцепить его оттуда штатными средствами практически невозможно.
А можно ли закопаться еще глубже?
На данный момент у нас нет ответа на этот вопрос, но идею озвучит стоит.
Вспомним, что у этого устройства есть ещё одна исполнимая среда, со своей, в некотором роде, прошивкой. Это ПЛИС (программируемая логическая интегральная схема), типа CPLD от Marvell с внутренней энергонезависимой конфигурационной памятью.
Программы для них пишутся на языке описания логики (VHDL, Verilog – самые распространённые). Напомним, что в коде прошивки коммутатора, мы нашли функции для чтения и перезаписи этой конфигурационной памяти.
Исследование промышленного коммутатора Phoenix Contact FL SWITCH MM HS
При исследовании этого свитча мы прошли тот же путь, только быстрее. Что интересного внутри:
- CPU PMC RM5231A, 32-разрядный MIPS IV, без внутренней памяти;
- Оперативная память SDRAM Micron MT48LC8M16A2 на 16 МБ, две штуки;
- Флэш-память от Intel неизвестной модели;
- Чипсет Galileo GT-64115.
Образ прошивки для этого коммутатора мы скачали с официального сайта вендора и таким же способом разобрали её структуру. У неё есть заголовок и сжатое по алгоритму zlib (RFC 1951) тело:
Основные поля в структуре заголовка:
- сигнатура;
- контрольная сумма заголовка (ADLER32);
- контрольная сумма распакованного тела (ADLER32);
- размер распакованного тела;
- контрольная сумма упакованного тела (ADLER32);
- размер упакованного тела.
Здесь тоже отсутствует контроль подлинности прошивки, мы это экспериментально проверили.
Здесь тоже VxWorks, правда немного более новой версии 6.1 имеющая те же проблемы: отсутствие механизмов защиты от эксплуатации бинарных уязвимостей и пачка зарегистрированных CVE.
Обновлять прошивку можно теми же способами:
- через COM-порт, аутентификации также не требуется
- через веб-интерфейс. Для доступа к нему не требуется ввод логина и пароля, но при внесении изменений в настройки (или при обновлении прошивки) необходимо знать пароль.
К слову о пароле. Согласно документации, существует инженерный пароль, на случай если текущий пароль утерян (ну или никогда не приобретался, если ты хакер). Для этого необходимо обратиться в техподдержку, предоставив им MAC-адрес и серийный номер коммутатора.
Это говорит о том, что есть алгоритм преобразования этих чисел в инженерный пароль.
У данного коммутатора тоже есть загрузчик, который может быть перезаписан. И это экспериментально доказано. Штатных возможностей для обновления загрузчика нет вообще.
Заключение
В результате проведённого исследования выявлены следующие недостатки в архитектуре промышленных коммутаторов:
- Возможность нелегитимно обновлять прошивку (для некоторых штатных процедур, аутентификация не требуется);
- Возможность подделывать образ прошивки устройства (в последствии и загрузчика, прошивку CPLD …) т.к. отсутствует контроль подлинности кода;
- Отсутствуют механизмы от эксплуатации бинарных уязвимостей, что открывает дополнительные возможности для удалённого исполнения кода на коммутаторе.
В ходе исследования мы показали возможность подделывать прошивки коммутаторов, а также возможность закрепления модификаций в загрузчике.
Короче, похачено.
Реальный пример правильной, на наш взгляд, модели безопасности прошивки, будет рассмотрен в следующей статье.
Автор: Digital Security