Нас окружают умные устройства. Внутри каждого — микросхемы и прошивки с программным кодом, который содержит уязвимости. Представьте, что в руки исследователя безопасности попадает устройство с недокументированным сетевым протоколом. Возникают задачи: разобрать протокол, научиться общаться с устройством и найти слабые места — уязвимости. Для исследования нужна прошивка. Но что делать, если прошивку невозможно достать? В статье я расскажу об опыте исследования ПЛК FX5U компании Mitsubishi без использования прошивки. Поделюсь, как собирал информацию и восстанавливал протокол на основе документации родственных протоколов, утилиты производителя, симулятора ПЛК, кодов ошибок, полного перебора и собственных наработок. Покажу, что знание протокола — это сила, и как это помогло нам с коллегами выявить 15 уязвимостей, среди которых CVE-2022-25161 и CVE-2022-25162. Опишу, как работают две эти уязвимости и как они влияют на технологические процессы на примере демонстрационных стендов. Я Антон Дорфман, исследователь и реверс-инженер. Более 24 лет занимаюсь обратным проектированием, с 2007 года — кандидат технических наук, и вот уже 7 лет работаю ведущим специалистом в отделе анализа приложений в компании Positive Technologies.  Последние девять лет занимаюсь исследованиями промышленных ПЛК и embedded-устройств, особенно интересны прошивки с редкими процессорными архитектурами. Находил CVE в оборудовании и программных системах Mitsubishi Electric, Schneider Electric, WAGO, CODESYS. Помимо этого, я увлекаюсь автоматизацией задач обратного проектирования и являюсь автором процессорного модуля NIOS II для IDA Pro, который участвовал в Hex-Rays Plug-In Contest 2018. Полученными знаниями делюсь на конференциях по безопасности: Positive Hack Days (2013-2018, 2022), ZeroNights (2013), OFFZONE (2023), HITBSecConf (Amsterdam, 2014), Hackron (Tenerife, 2018), Nullcon (Goa, 2023). Например, на PHDays 7 показал атаки на ПЛК с принтера с модифицированной прошивкой, а на PHDays 11 рассказывал про предобработку бинарных файлов в IDA Pro с помощью скриптов. Моя специализация в проектах — разбирать сетевые протоколы и форматы данных ПЛК, чтобы продукты компании могли их понимать. Попутно в процессе исследований возникают задачи поиска уязвимостей. Иногда я разрабатываю шеллкоды — импланты в прошивки — для демонстрации различных proof of concept (PoC). В своей работе я использую дизассемблер IDA Pro, дополняя его функции разработанными мной средствами автоматизации обратного проектирования и другими скриптами на IDAPython. Для анализа сетевых пакетов применяю Wireshark, а для взаимодействия с устройствами разрабатываю скрипты на Python. Чаще всего работаю с редкими архитектурами процессоров, в частности Hitachi, Renesas H8, SuperH, NEC, Siemens и NIOS. Нередко в проектах мне попадаются прошивки, в которых мало подсказок, иногда нет даже текстовых строк. Вводная часть Как устроены ПЛК и чем они отличаются от других систем  Способы атак на промышленный контроллер Какие последствия могут быть при атаке на промышленный контроллер Реальные случаи атак на технологические процессы Контроллеры Mitsubishi Electric Предварительное исследование Задачи исследования и первые шаги в поиске решения M Protocol M Protocol vs PCAP (Read Random) PCAP vs Manual (Read Random) M Protocol vs Manual (Read Random) Предварительные результаты Исследование Правило RTFM и что можно достать из мануалов Как может помочь GX Works 3 — утилита от производителя Строение симулятора и его связь с ПЛК Запуск симулятора и брутфорс команд Реверс-инжиниринг Документация для родственного протокола  Коды ошибок из документации Проецирование адресов внутри симулятора   Результаты исследования Описание протокола  Устройства и команды Демо в стиле K.I.T.T., или Знание протокола — сила Уязвимости и взаимодействие с вендором Уязвимость CVE-2022-25161 Уязвимость CVE-2022-25162 Заключение Благодарности В начале дадим основные понятия, чтобы было ясно, о чем будем говорить дальше.  Программируемый логический контроллер (ПЛК, PLC) — это разновидность вычислительной машины для работы в системах реального времени. Применяется для автоматизации технологических процессов. Основной режим работы ПЛК — длительная автономная и надежная работа без обслуживания и вмешательства.  Отличия ПЛК от других систем: По сравнению с микроконтроллером — это самостоятельное устройство, а не отдельная микросхема. В отличие от встраиваемой системы ПЛК отделен от управляемого им оборудования. В отличие от компьютера, которым управляет оператор, ПЛК взаимодействует с датчиками и исполнительными устройствами через входы и выходы. На рисунке схема, которая это иллюстрирует. Сигналы с датчиков приходят на входы. Программа внутри ПЛК обрабатывает входные сигналы и выдает на выходы управляющие воздействия. К выходам подключены исполнительные устройства. Промышленные ПЛК — это развитые системы как с аппаратной, так и с программной точки зрения. Внутри них — современные процессоры, достаточное количество оперативной памяти, набор встроенных периферийных устройств, операционные системы реального времени и файловые системы.  С точки зрения безопасности в ПЛК может применяться полный спектр средств защиты, используемых в других системах (мобильных, встраиваемых, клиентских, серверных). Самые часто используемые — это шифрование и криптографические подписи прошивок и их обновлений, парольные защиты доступа.  На физическом уровне с ПЛК можно взаимодействовать по RS-232, RS-485 и Ethernet- интерфейсам. Как правило, для общения по сети ПЛК поддерживает как общеизвестные протоколы (TCP/IP, HTTP, FTP), так и чисто промышленные (Modbus, OPC UA и другие). Особый интерес исследователей вызывают недокументированные проприетарные протоколы для общения с ПЛК, которые вендоры реализуют в своих продуктах. Где может стоять промышленный ПЛК и как его можно атаковать?  Посмотрим, как выглядит технологическая сеть глазами злоумышленника. На рисунке приведена упрощенная схема промышленной сети. Она состоит из трех частей: интернет, корпоративная сеть передачи данных (КСПД), технологическая сеть (ТС). В технологической сети есть три уровня. Верхний уровень включает управляющие рабочие места операторов и инженеров. На среднем уровне размещаются промышленные ПЛК, а на нижнем — датчики и исполнительные устройства.  Как злоумышленник может атаковать ПЛК? В основном рассматривают атаку через смежные системы — путь атаки слева направо, то есть злоумышленник должен пройти всю цепочку из внешней сети интернет до ПЛК. Но это не единственный возможный вариант атаки. Представьте себе, что оператор принес USB-модем, чтобы выйти в интернет с рабочего места, или инженер подключил флеш-накопитель к серверу SCADA для обновления, или в одной подсети с ПЛК расположено многофункциональное устройство (МФУ) с дополнительным беспроводным доступом. И это все случаи из проектов и реальной жизни. Так что будем считать, что злоумышленник может подсоединиться к любому сегменту этой сети.  Это зависит от двух моментов: Где установлен ПЛК. С одной стороны, можно повлиять на производство булочек, а с другой стороны — на более серьезный технологический процесс. Как можно повлиять на ПЛК и технологический процесс на его основе. Злоумышленник может остановить процесс, заблокировать его запуск, поменять управляющие воздействия, подменить входы или выходы, изменить параметры процесса или настройки ПЛК. В результате атаки злоумышленник может испортить качество изделий, вызвать аварию, остановить предоставление ресурсов: воды, тепла, электричества, газа — и даже вызвать техногенные катастрофы, такие как взрывы, потопы, пожары. На производствах, конечно, используется не один контроллер, потому не все так просто. Для серьезных атак злоумышленнику нужно глубоко разбираться в протоколах и технологиях взаимодействия с ПЛК. Также он должен понимать, за что отвечают разные параметры технологического процесса на конкретном объекте. Помимо этого, злоумышленник должен получить доступ к контроллерам, которые управляют этим технологическим процессом. Кроме того, на важных и опасных производствах может использоваться специальный контроллер противоаварийной защиты (ПАЗ), задача которого — независимо от работы управляющего контроллера предотвратить серьезную аварию. При этом он может остановить технологический процесс, что, безусловно, тоже является недопустимым событием для любого промышленного предприятия. Чтобы сопоставить эти возможности с реальностью, можно обратиться к истории и вспомнить имевшие место целенаправленные атаки на ПЛК. На рисунке ниже в левой части собраны примеры вредоносов, представляющих опасность для технологических процессов. Считается, что все началось с обнаружения червя Stuxnet в 2010 году на заводе по обогащению урана в Натанзе, Иран. В проведенных позже расследованиях указывалось, что ранние версии Stuxnet существовали с 2007 года. Последние версии червя распространялись с помощью USB-флеш-накопителей, заражая рабочие станции под управлением Windows. Stuxnet перехватывал, разбирал и модифицировал пакеты протокола общения между ПЛК Simatic S7 и SCADA-системой Simatic WinCC компании Siemens. Таким образом, его создатели разбирались в протоколе и технологии взаимодействия с ПЛК. По оценке экспертов, Stuxnet нарушил работу 1368 из 5000 центрифуг для обогащения уранового топлива, таким образом замедлив ядерную программу Ирана. Следовательно, создатели Stuxnet хорошо разбирались в параметрах технологического процесса и соответствующим образом изменяли алгоритмы управления центрифугами в ПЛК. С него начался бум исследований промышленного оборудования и закрытие уязвимостей. Тем не менее такого рода вирусы стали проникать в нашу повседневную жизнь, поэтому давайте коснемся немного их современных представителей. Современные вредоносные программы Industroyer и Pipedream умеют работать с несколькими протоколами и семействами ПЛК. Их экземпляры были обнаружены на электрических подстанциях и в комплексах по производству сжиженного газа. Судя по поддерживаемым протоколам и семействам ПЛК, вредоносная программа Pipedream способна работать и в других технологических процессах. В 2022 году злоумышленники провели рекордное количество атак на технологические процессы. Они затронули многие области нашей жизни: снабжение, производство, металлургию, топливно-энергетический комплекс, транспорт и агропромышленность. Конечно, часть атак связана с программами-вымогателями. Однако происходили и целенаправленные атаки, например, на ПЛК марки Berghof в Израиле и на сталелитейные заводы в Иране. По данным сайта ladderlogicworld.com, Mitsubishi Electric в 2017 году занял третье место в мире на рынке промышленных контроллеров, выпустив свыше 17 миллионов компактных ПЛК. Серии ПЛК Mitsubishi MELSEC и масштабы систем, в которых они применяются, приведены на рисунке. Основные сферы применения ПЛК Mitsubishi (по информации вендора) — микроэлектроника, энергетика, автотранспорт, логистика и индустриальные роботы. В нашей стране контроллеры Mitsubishi часто применяются на насосных станциях и в системах вентиляции зданий. Есть еще редкие и экзотичные применения, которые встречались в проектах коллег на их прошлых работах: например, вагоноопрокидыватели, системы для ТЭЦ и даже шлюзы водохранилищ. Контроллеры FX линейки MELSEC iQ-F, представитель которой попал к нам на исследование, применяются для автоматизации инженерных систем зданий, в деревообработке, типографиях, пищевой и легкой промышленности, водном хозяйстве, судоходстве и других сферах.  Теперь о том, как внешне выглядит этот ПЛК. На рисунке представлена лицевая панель Mitsubishi FX5U. Сносками обозначены индикаторы, наиболее важные из них: питания, ошибки, работы проекта и входы с выходами. В исследовании мне предстояло разобрать протокол, научиться общаться с ПЛК по сети с помощью скриптов, найти уязвимости в прошивке и проприетарном протоколе.  Коллеги записали и прислали сетевой трафик общения инженерной утилиты и ПЛК. На рисунке скриншот из программы — анализатора трафика Wireshark. Давайте внимательно на него посмотрим.  Это TCP-поток, розовым выделены запросы, сиреневым — ответы. В левом столбце смещения байтов внутри TCP-потока, посередине — шестнадцатеричный дамп со значениями байтов, а справа — текстовое представление байтов дампа. Если внимательно посмотреть на скриншот с трафиком, то можно увидеть закономерности. Например, что у обоих запросов в начале — «57 01», а у ответов — «d7 01». Значит, используются некоторые постоянные байты, причем у ответов установлен старший бит.  В первых строчках запросов и ответов видна последовательность «ff ff 03». В середине пакетов видим нули. В первом ответе — строка «FX5U-32MR/ES», очевидно, это номер модели ПЛК.  На основе подобного анализа нескольких десятков пакетов протокола я получил предварительную схему, которая представлена на рисунке. Цветом выделена часть найденных закономерностей. В начале постоянные значения байтов, в запросах последовательность «ff ff 03» по смещению 0Ah, а в ответах — по смещению 0Eh. Зеленым выделена повторяющаяся последовательность, в которой у ответов в первом байте установлен старший бит. В конце этой последовательности число 14h, что соответствует 20 нулям, которые идут после этого поля. Далее голубым цветом выделен номер команды протокола. В ответах бордовым отмечены возвращаемые данные. Если подсчитать нули, то видно, что их в ответах больше на два байта. Эти два байта выделены фиолетовым и являются статусом операции, который ПЛК возвращает после обработки команды. Если в поле статуса возвращается ноль, значит, команда выполнилась успешно. При ошибке в поле статуса возвращается код ошибки, который дает понять, что произошло. По расположению содержимого пакетов видно, что первый и второй запрос отличаются тремя байтами. А если пробежимся глазами, то увидим, что перед зеленым выделением в первом запросе число 20h, во втором — 23h. Оказалось, что это поле — размер данных команды внутри пакета.  Подобные схемы дают начальное понимание, как устроен исследуемый протокол. Мои коллеги из отдела безопасности промышленных систем в шутку называют такой тип анализа — «реверс глазами» или «глазной реверс». Имея первоначальное описание, мы стали искать в сети Интернет открытые исследования протоколов для ПЛК Mitsubishi. Вдруг исследователи уже изучили и описали этот протокол? Этот поиск не дал результатов. Примерно за полгода до проекта, коллеги организовывали кибербитву  на конференции Hack In The Box в Абу-Даби. Там он посетили доклад, посвященный безопасности промышленных систем и в нем упоминался М Protocol, который используется в контроллерах Mitsubishi. На рисунке представлено его краткое описание. Слева показано строение запроса, справа — строение заголовка ответа. Поля, на которые надо обратить внимание, увеличены.  Что мы тут видим? В начале пакета фиксированные значения, есть размеры данных для запросов и ответов, в поле End Code — статус операции. Вроде подходит. Кажется, это наш протокол! Давайте копнем глубже и сравним M Protocol с реальным трафиком.  В обоих случаях первые байты — это фиксированные значения, которые похожи, но не совпадают. Байтовая последовательность «ff ff 03» видна в обоих случаях, но в реальном трафике она по другому смещению. В докладе представлена команда Read Random с кодом команды «03 04». В дампе с реальным трафиком нет этого значения. Следовательно, это другой протокол.  В документации ПЛК Mitsubishi FX5U упоминаются протоколы SLMP и MC Protocol (MELSEC communication protocol).  Они имеют идентичное строение и два вида — текстовый и бинарный. Очевидно, что под наше описание подходит бинарный вид. Мы нашли мануал по протоколу MELSEC «FX5 User's Manual (MELSEC Communication Protocol)» и теперь сравним его с нашим реальным трафиком.  Здесь первые байты также фиксированные и тоже отличаются. В обоих случаях присутствует последовательность «ff ff 03», но в документации она по другому смещению. В мануале команда Device Read Random имеет код 0403h. Меняем порядок байтов, ищем последовательность «03 04» в дампе с реальным трафиком — и не находим это значение. Следовательно, это тоже другой протокол. Пробуем сравнить M Protocol с протоколом MELSEC из мануала по ПЛК Mitsubishi. Первые байты фиксированные и совпадают. Последовательность «ff ff 03» располагается по одинаковым смещениям. Код команды «03 04» также совпадает в обоих случаях. Получается, что M Protocol — это, по сути, то, что уже описано в мануале Mitsubishi как MC Protocol (MELSEC communication protocol).  На рисунке выделено поле Device Code - это адресация внутренних устройств, о них мы поговорим позже. Давайте обратим внимание на значение A8 — и запомним его, оно еще пригодится. На рисунке приведен скан открытых портов, сделанный с помощью утилиты Nmap: открыты три UDP-порта и один TCP-порт. Забегая немного вперед, необходимо отметить, что по всем четырем портам работают наш исследуемый протокол.  На основе визуального анализа пакетов я сделал предварительную спецификацию протокола и разработал начальный набор скриптов на Python для работы по нему. MitsuClass выполнял низкоуровневую работу: собирал и отсылал запросы-команды, принимал и разбирал входящие пакеты-ответы. Я посмотрел строение команд RUN, STOP и PAUSE в трафике инженерного софта и реализовал их в виде трех отдельных простых скриптов, которые базировались на MitsuClass. В это время началась пандемия и все сотрудники ушли на удаленку. Из-за этого мне не успели настроить удаленный доступ к ПЛК, но коллега смог забрать ПЛК домой. Поэтому я выслал скрипты ему и попросил запустить их. Далее приведен скриншот его письма с ответом. Вот его ответ: В итоге с помощью начального набора скриптов наш ПЛК стартовал, останавливался и переходил на паузу. Мы продолжили исследование. Для продолжения исследования требовалась прошивка. Я обратился к коллегам, чтобы они помогли ее достать. Эксперт по прикладной криптографии проанализировал строение файлов с обновлениями для разных серий ПЛК Mitsubishi. Его выводы: обновления прошивок свободно скачиваются. Но они зашифрованы; по косвенным признакам используется шифрование AES128, проверка целостности SHA256 и ECDSA256; ключи AES и параметры ECDSA в прошивке (до расшифровки) не светятся, и без чтения флеша ничего извлечь не получится. единственный выход — прочитать флеш-память и поискать там ключи для расшифровки обновлений.    Параллельно специалист по микросхемам сдампил внешнюю флеш-память. На ней не оказалось ничего, что бы помогло достать прошивку. Затем он попробовал получить доступ к встроенной в процессор флеш-памяти: прозвонил ножки CPU; подцепил к ним JTAG; успешно соединился программатором; CPU вернул, что залочен и требуется ID Code для дальнейшего общения; не смог сдампить флеш-память CPU. В итоге ни одним из примененных нами способов мы не смогли получить прошивку.    В проектах встречались прошивки, в которых не было никаких подсказок, даже строк. Здесь впервые столкнулись с ситуацией, когда нет даже самой прошивки. Такого я еще не встречал. Я не стал опускать руки и решил продолжать исследование. Информацию для восстановления протокола я попробовал искать другими способами. Для начала я решил воспользоваться правилом RTFM (Read The Following Manual, «обратитесь к прилагаемому руководству»). Все знают об этом правиле, но мало кто любит его применять сразу. Из руководства я выделил основные особенности функционала ПЛК Mitsubishi FX5U - они приведены на рисунке. Управление ПЛК мы уже попробовали с помощью своих скриптов. Функции безопасности, обновление и настройки даты и времени я пока не стал глубоко копать. Необходимо отметить внутренние устройства — devices в терминологии мануала. По сути, это входы, выходы, счетчики, таймеры и др. К устройствам можно обращаться, то есть писать в них и читать, как из проекта, выполняемого в ПЛК, так и через сеть с помощью команд протокола.  Помните значение A8 из раздела про сравнение M Protocol и мануала? Именно оно выделено на рисунке красным. Оказалось, это Data register, и тот трафик обращался к этому устройству, чтобы считать из него значения. Устройства имеют разную размерность доступа, например, Word означает, что значения считываются и записываются по 2 байта. Внутри ПЛК встроена своя файловая система и доступны как стандартные действия (чтение, запись, открытие и закрытие), так и расширенные (копирование, перемещение файла, удаление и другие). Настройка ПЛК Mitsubishi FX5U выполняется с помощью загрузки в него файлов с параметрами. Самые важные из них приведены на рисунке. Проект — программа, которая будет выполнятся внутри ПЛК, — также загружается через файл.  Программа GX Works 3 от Mitsubishi — это развитый продукт с большим количество функций. Ее внешний вид показан на рисунке. Давайте подробно исследуем особенности GX Works 3. Почему GX Works 3 — развитый продукт? Во-первых, это среда для разработки проектов и в то же время инженерная утилита. GX Works 3 позволяет настраивать параметры ПЛК, читать из устройств, писать в них, диагностировать ошибки и отлаживать проекты. Какую информацию можно получить из GX Works 3: Команды через пункты меню.  При выборе пунктов меню GX Works 3 запускается взаимодействие утилиты и ПЛК. С помощью Wireshark получаем трафик этого взаимодействия. Затем можно сопоставить выбранные команды и коды для них, которые встретились внутри трафика. Однако это не так-то просто: один пункт в меню часто приводит к отправке последовательности из нескольких команд. Устройства через монитор пакетного чтения записи. В мониторе пакетного чтения записи выбираем устройство, с которым хотим работать, например Data register. Дальше задаем смещение внутри него и считываем значения, которые там хранятся. Затем в трафике видим, какой номер у конкретного устройства для исследуемого протокола.  Параметры настройки через разницу в файлах настроек. В древние времена компьютерных игр под MS-DOS использовали такой прием: в файле с настройками персонажа меняли значения байтов и проверяли, какие параметры поменялись внутри игры: жизнь, сила, выносливость и т. д. В исследовании применялся этот же прием, только наоборот. Внутри GX Works 3 изменялся параметр — устанавливались флажок или значение. Затем через разницу в файлах до и после установки параметра определялось, какие байты или биты отвечают за него. В состав среды разработки GX Works 3 входит полезный компонент — симулятор ПЛК. В симуляторе можно запускать и отлаживать проекты для конкретной модели ПЛК, сам контроллер при этом не нужен. Симулятор поддерживает входы, выходы, таймеры и другие внутренние устройства. Для наглядности поддерживается индикация состояния как на лицевой панели ПЛК.  Симулятор доступен на локальном сетевом интерфейсе localhost, работает только по TCP, при этом порт можно настраивать. По трафику симулятора выяснили, что в нем используется тот же протокол, что и для ПЛК.  Так у нас появилась возможность исследовать работу ПЛК через симулятор: как он обрабатывает команды, какие исполняемые файлы используются и за что отвечают. Я решил подробно исследовать работу симулятора.  Как это можно сделать? С помощью утилиты Process Explorer от Sysinternals узнаём, какой исполняемый файл отвечает за запуск и работу симулятора — им оказался FSimRun3.exe. Командная строка, с которой GX Works 3 запускает симулятор, представлена справа вверху. Краткий анализ показал, что исполняемый файл обращается к библиотеке FX5U.dll. Я выяснил, что эта библиотека содержит строки с именем и номером модели ПЛК, то есть симуляция ПЛК реализована в ней. Также внутри библиотеки я нашел реализацию исследуемого протокола. При запуске из-под GX Works 3 симулятор запускается в монопольном доступе и достучаться к нему не получается. Поэтому я научился запускать симулятор отдельно от GX Works 3, чтобы тестировать варианты команд. Скриншот запуска показан ниже. Через ключ --tcp можно задавать порт, на котором будет работать симулятор. Используя информацию о протоколе, собранную к этому моменту, я написал скрипт, который полным перебором находил все команды, реализованные в протоколе. Скриншоты с частичными результатами запуска скрипта на ПЛК и на симуляторе показаны на рисунке. В ПЛК было выявлено 83 команды, в симуляторе — 54. Часть команд в симуляторе - это процедуры-заглушки, которые не выполняют никаких действий, а просто возвращают сообщение об ошибке. Несмотря на это, симулятор качественно поддерживает основные команды протокола, поскольку результаты их работы идентичны командам в ПЛК. И вот наконец-то мы с вами добрались до реверс-инжиниринга.  Проблему с отсутствием прошивки вроде решил, вместо нее буду исследовать DLL-библиотеку с симулятором ПЛК. Но, снова оказался в ситуации, когда не на что опереться, потому что в DLL нет символов и каких-либо сообщений об ошибках, а также практический нет текстовых строк.  Что здесь может помочь? Во-первых, мануалы и другая документация для похожего, родственного протокола. В документации представлено развернутое описание кодов ошибок и возможных причин, приводящих к ним. Будем использовать результаты предварительного исследования: из мануалов знаем, как работают встроенные механизмы ПЛК, например файловая система и внутренние устройства. Результаты брутфорса команд дают понимание, какие команды реализованы в коде симулятора. С помощью начальных скриптов для работы с протоколом можно перебирать параметры команд и проверять предположения относительно текущих исследуемых команд. И самая классная штука, прямо вишенка на торте — симулятор можно исследовать в отладчике.  Дальше пойдет немножко хардкора — посмотрим, как документация и коды ошибок помогли при исследовании протокола и как это выглядит глазами реверс-инженера.  Смотрим, какие подсказки можно вытащить из документации. Для реверс-инжиниринга динамическая библиотека FX5U.dll была открыта в дизассемблере IDA Pro.  Слева вверху показан кусок x86-кода обработчика команд протокола. В нем вызовы обработчиков для двух разных типов команд: Type2_CmdHandler и Type1_CmdHandler. Эти имена присвоены процедурам в процессе исследования исходя из предположений о том, что они делают.  Справа вверху представлена часть обработчика Type2_CmdHandler в виде псевдокода декомпилятора. В нем с помощью выбора case вызывается обработчик для одной из трех команд: «0401», «0403» и «0406». Последовательность значений «0403» нам уже встречалась. Это команда Device Read Random из документации родственного протокола.  Смотрим подробнее процедуру Type2_Cmd_04_03 — обработчик команды «0403». В ее коде вызывается процедура sub_71927630. Пока это имя нам ничего не говорит. IDA Pro при начальном открытии файла для всех процедур автоматически генерирует такие имена, которые содержат адреса их начала.  IDA Pro поддерживает xrefs — перекрестные ссылки. С их помощью можно посмотреть, из каких мест в коде вызывается процедура. Слева внизу показаны перекрестные ссылки для процедуры sub_71927630. Видим, что, помимо процедуры Type2_Cmd_04_03, из которой мы пришли, текущая процедура вызывается из Type1_Cmd_04_11_12. Делаем вывод, что команда из документации Device Read Random с кодом «0403» для исследуемого протокола будет иметь коды «0411» и «0412».  Таким образом были восстановлены команды, которые имеют аналоги в документированном родственном протоколе, и сделаны общие предположения насчет групп команд. Рассмотрим подробнее, как могут помочь коды ошибок из документации.  Встретился фрагмент кода (он показан в верхней части рисунка). Смотрим подробнее: это сравнение стековой переменной var_E с каким-то значением в регистре eax. Если стековая переменная меньше или равна значению, происходит переход на метку lod_718FCD24. В ином случае в регистр ecx заносится код ошибки 413Ah (на рисунке он выделен желтым цветом). Следующей командой код ошибки заносится в поле EndCode в структуре исходящего пакета-ответа. В мануале код 413Ah означает, что задаваемый размер файла превысил уже существующий размер, то есть в файл попытались записать больше, чем он может вместить. Значит, стековая переменная var_E — задаваемый новый размер файла, и в нижней части рисунка показан результат ее переименования в ReadSizeLoc. С помощью кодов ошибок у меня получилось определить строение части команд и идентифицировать параметры для некоторых команд. В процессе исследования я встретил интересные смещения. На рисунке примеры таких смещений выделены оранжевым цветом: 0x66184 и 0x66000. Процедура GetRealAddr берет такое смещение и проецирует на реальный адрес в памяти. Так что же это за смещения? Для выяснения этого я разработал набор скриптов, которые собирали подобные смещения, потом группировали их и делали из них сегменты. Далее эти смещения преобразовывались в адреса внутри новых сегментов. Таким образом, при переходе по адресу 0x66000 можно по перекрестным ссылкам найти в коде все обращения к этому адресу. Проанализировав код, который к ним обращается я выяснил, что, например, 0x66000 — это внутреннее устройство, на которое спроецированы входы контроллера. Затем я переименовал 0x66000 в Input_Start, что показано в листинге в правой части. Таким образом, представление кода в дизассемблере стало удобнее для анализа, теперь можно понять, за что отвечают эти области. Опытным путем получилось выяснить, что адреса вида 0x66000 содержатся в таком же виде внутри прошивки ПЛК. Получается, что симулятор тщательно моделирует работу ПЛК и совпадает даже внутренняя адресация. Это очень хорошо! В результате исследования я восстановил протокол и сделал его описание. На рисунке показано общее строение пакетов исследованного протокола. Ниже в трафике цветом выделены поля для некоторых подзаголовков.  Фиолетовым отмечен низкоуровневый заголовок — с фиксированными значениями, который мы уже рассматривали. Голубым выделен DstRouteHdr — в протоколе своя внутренняя маршрутизация, то есть он может через один ПЛК обращаться к другим. Зеленым выделен размер данных для пакета. Строение пакета для команды и ответа отличается на одно поле. В ответе дополнительно присутствует поле EndCode — статус операции, который отмечен красным цветом. В процессе исследования я смог идентифицировать большую часть внутренних устройств. Информация о некоторых из них приведена в таблице. Первый столбец - это номера устройств для исследованного протокола, а последний столбец - их номера в документации для родственного протокола. Вспомним значение A8h — это Data register, и на рисунке он выделен красным цветом. Для исследованного протокола Data register имеет код 20h. Это означает, что каждый раз, когда в трафике будет обращение к устройству 20h, мы будем понимать, что идет обращение именно к устройству Data register.  Также я смог определить предназначение большей части команд протокола. Часто используемые команды протокола приведены в таблице.  В первом столбце указаны номера команд для исследованного протокола, а в последнем - для родственного протокола из документации. Красным выделена команда Random Read. В мануале она имеет код 0403, а в разобранном протоколе 0411. О ней упоминали в разделе про реверс-инжиниринг.  Исследованный протокол отличается от родственного протокола из документации общей структурой пакетов, номерами команд, их количеством и номерами устройств.  Итак, у нас есть протокол, но что в нем может быть интересного? Что он может дать? Какие-то таблички, описания — скучно! Но, зная только протокол, мы уже можем сделать многое с ПЛК. К примеру, вот одна ситуация, которую мы смоделировали. Был старый сериал «Рыцарь дорог». Главный герой владел умной машиной K.I.T.T., у которой впереди была лента из лампочек. Эта лента моргала лампочками в виде змейки, которая двигалась из стороны в сторону.  Мы решили смоделировать эти действия на ПЛК Mitsubishi, чтобы он делал то же самое светодиодами, обозначающими сигналы на выходах. Я разработал скрипт, который, посылая команды разобранного протокола, напрямую манипулировал выходами. При этом он практически игнорировал программу, которая в данный момент выполняется на ПЛК, а в области светодиодов двигалась змейка, как у машины K.I.T.T. из сериала «Рыцарь дорог». Коллеги смонтировали наглядное демо и в шутку пририсовали мою голову к фигуре главного героя. С одной стороны, мы хотели показать, что можем манипулировать выходами ПЛК напрямую, просто посылая команды через сеть. С другой стороны, это было забавное демо. Возвращаясь к разделу с последствиями: зная протокол, уже можно делать многое, например влиять на технологической процесс. То, что протокол недокументированный, практически никак не спасает от этого. В результате исследования мы с коллегами нашли 15 уязвимостей. В декабре 2021 года мы отправили отчет с их описанием в Mitsubishi Electric. Они ответили достаточно оперативно и  обещали быстро исправить восемь уязвимостей, связанных с самим ПЛК. По остальным семи уязвимостям внутри продукта GX Works 3 написали, что потребуется больше времени. Это вполне понятно, поскольку GX Works 3 — тяжеловесный продукт с большим количеством функций. В целом Mitsubishi Electric при взаимодействии показали себя как ответственный вендор: давали четкие ответы, согласовывали перенос релизов адвайзори и соблюдали заявленные сроки. В марте 2022 года вышел адвайзори с первыми шестью уязвимостями в ПЛК. Позже, в мае вендор выпустил еще один по двум уязвимостям в ПЛК, а также обновление информации по всем уязвимостям.  Примечательно, что релиз информации о семи уязвимостях в GX Works 3 произошел в день моего выступления с этим докладом на конференции HighLoad++.  Ссылки на выпущенные адвайзори: ● Authentication Bypass, Information Disclosure and Information Tampering Vulnerabilities in Multiple FA Products  ● Multiple Denial-of-Service Vulnerabilities in MELSEC iQ-F Series CPU module ● Multiple Vulnerabilities in Multiple FA Engineering Software Найденные уязвимости, связанные с ПЛК, можно разделить на два типа. Первый тип связан с защитными механизмами ПЛК, а второй — с его программным устройством. Примечательно, что мы исследовали FX5U-контроллер, но многим из обнаруженных нами уязвимостей подвержены все контроллеры серии iQ-F, а также других серий — iQ-R, Q и L.  Дальше я рассмотрю две уязвимости, вызывающие отказ в обслуживании — CVE-2022-25161 и CVE-2022-25162. Они связаны с базовыми механизмами работы ПЛК — внутренними устройствами и файловой системой. При этом уязвимость CVE-2022-25161 имеет самую высокую оценку — 8,6.  Запуск уязвимостей на реальном объекте, реализующем технологический процесс, может привести к плачевным последствиям, о которых я ранее упоминал в статье. Поэтому проверять уязвимости решили на стендах, используемых для нашей кибербитвы Standoff и предназначенных для демонстрации последствий возможных хакерских атак. При работе с устройствами можно задавать смещение внутри устройства, чтобы обратиться к конкретной ячейке — переменной. В коде симулятора есть процедура, которая преобразует смещение внутри устройства в реальный адрес в памяти ПЛК. В процессе исследования я назвал ее DevOff_To_RealAddr. Формула для преобразования приведена на рисунке. Реальный адрес RealAddr зависит от начального адреса устройства DevStartAddr, смещения внутри устройства DevOff и размера элементов UnitSize.  Например, возьмем устройство с адресом DevStartAddr = 0x66000 и размером элементов в два байта — UnitSize = 2. Попробуем обратиться к смещению DevOff = 0xFFFCD000 внутри устройства. Если подставим эти значения в формулу, то реальный адрес RealAddr будет равен нулю. Возьмем это на заметку.  Смещение DevOff проверяется на максимальное значение, чтобы не допустить обращения к памяти за пределами устройства. Привожу псевдокод части процедуры, которая вызывает процедуру DevOff_To_RealAddr:  Видно, что если реальный адрес равен нулю, то происходит прыжок на метку RealAddr_is_Null. При этом проверки DevOff на максимальное значение не происходит. Поэтому, передавая в качестве смещения DevOff подобные большие значения, мы можем читать и писать за пределы памяти, доступной устройству, то есть обращаться напрямую к памяти самого ПЛК.  Для рассмотренной уязвимости CVE-2022-25161 я написал PoC, который активировал уязвимость на ПЛК. Для демонстрации этой уязвимости мы использовали стенд, который моделирует работу нефтеперекачивающей станции на битве Standoff. На нем есть магистральные насосные агрегаты, запорные и регулирующие задвижки. ПЛК Mitsubishi FX5U управляет насосами и задвижками. На экране SCADA отображаются состояние и параметры технологического процесса. Как только запускается PoC-скрипт, ПЛК переходит в состояние ошибки, его входы и выходы погасают. Далее SCADA не может подключиться к ПЛК и выдает сообщение об этом, а на стенде все останавливается и сам стенд загорается красным, сигнализируя об аварии. Суть второй уязвимости в следующем: ПЛК Mitsubishi FX5U работает с файлами собственного формата, они состоят из тела файла (на рисунке выделено зеленым) и заголовка, который идет до этого тела. Заголовок файла содержит поле с его размером (оно выделено красным). При каждом закрытии файла выполняется подсчет контрольной суммы от содержимого тела файла. Для этого используется размер заголовка. Размер тела файла FileBodySize вычисляется вычитанием размера заголовка HeaderSize из размера файла FileSize. Посмотрим, что будет, если попробуем записать в ПЛК файл со строчкой «HACKER» внутри. Буквы «C» и «K» из середины строчки будут восприняты как размер заголовка. В шестнадцатеричном виде они имеют представление 0x43 и 0x4B. Получается, что размер заголовка HeaderSize достаточно большой — 0x4B43, а размер файла всего 6 байт. При вычитании получится отрицательное число, которое будет воспринято как очень большое положительное число — 0xFFFFB4C3. Подсчет контрольной суммы приведет к сбою при обращении к недопустимым адресам. Для демонстрации этой уязвимости мы использовали стенд, который воспроизводит работу водозаборной станции на кибербитве Standoff. На стенде есть установки забора и обработки воды, резервуары, насосы для перекачки, которыми управляет ПЛК Mitsubishi FX5U. Состояние и параметры техпроцесса отображаются на экране SCADA. При запуске разработанного мной PoC-скрипта на этом демостенде мы увидели другой процесс: после запуска скрипта получаем красную индикацию с ошибкой соединения на экране SCADA. Она означает, что ПЛК больше нельзя управлять по сети, поскольку из-за уязвимости падает сетевой стек. При этом сам ПЛК продолжает работать и технологический процесс не останавливается. Что же происходит? Давайте сравним эти два PoC.  У уязвимости CVE-2022-25161 высокая оценка — 8,6. Можно сказать, она практически убивает ПЛК. Единственное, что может вернуть его к жизни, — аппаратная перезагрузка или сброс по питанию.      В случае с уязвимостью CVE-2022-25162 теряется только связь с тем портом, по которому соединились. Поэтому мной была сделана добавка к PoC — скрипт, который предварительно отсоединял SCADA, затем соединялся по всем портам протокола и посылал последовательность пакетов для вызова DoS. После этих действий SCADA не может соединиться с ПЛК, то есть оператор не получает данные и не может управлять технологическим процессом. Подведем итоги исследования ПЛК Mitsubishi FX5U: у нас не было доступа к его прошивке, но это не остановило нас в исследовании ПЛК.  По утилитам производителя, симулятору ПЛК, информации из трафика, мануалам и другим источникам мне удалось собрать информацию и восстановить протокол. Я научился общаться с ПЛК с помощью разработанного набора скриптов. Вместе с коллегами мы нашли пачку из 15 уязвимостей, которые признал производитель и выпустил для них обновления безопасности.  Благодарю за помощь в проекте соавторов найденных уязвимостей: Дмитрия Склярова, Владимира Назарова, Илью Рогачева и Артура Ахатова, а также весь отдел безопасности промышленных систем компании Positive Technologies. Понравилась статья? Жду ваши комментарии и вопросы. Кстати, это еще не финал моего исследования. На очереди вторая часть. В ней я расскажу о механизмах защиты ПЛК Mitsubishi FX5U и остальных 13 уязвимостях, которые связаны с этими механизмами, а также раскрою некоторые детали процесса исследования и его результаты. Ведущий специалист отдела анализа приложений Positive Technologies В нашем блоге есть еще много интересных статей про кибербезопасность, технологии, инструменты и новейшие подходы к защите от кибератак. Читайте и подписывайтесь, чтобы не пропустить новые посты.