![]() |
https://forum.antichat.xyz/attachmen...1958148568.png
Сегодня о том, как заглянуть в кишки программируемому логическому контроллеру (PLC) без карты местности, то есть без исходного кода, без символов, без подсказок от вендора - голыми руками, через недокументированные функции инженерного софта и протоколов. Зачем это всё? От благородных целей до чёрного рынка Причины, по которым тебе может понадобиться прямой доступ к памяти контроллера, могут быть совершенно разными. И я не буду делить их на «белые» и «чёрные», потому что в реальном мире всё смешано. Легитимные сценарии (для тех, кто платит налоги и спит спокойно):
Чтобы понять, почему мы вообще можем читать память контроллера без пароля, нужно нырнуть в историю промышленной автоматизации. 80-е, 90-е годы. PLC разрабатывались как надёжные заменители релейных щитов. Они должны были работать в жёстких условиях, не виснуть годами и быстро выполняться. Протоколы, по которым они общались (Profibus, Modbus, S7, CANopen), создавались для скорости и детерминизма, а не для безопасности. Сеть была изолирована физически (air gap) - к контроллеру мог подключиться только инженер с программатором, воткнув кабель напрямую. Никто не думал, что эти протоколы когда-нибудь полетят по Ethernet в общую сеть завода, а потом - в интернет. Но прогресс не остановить: появился Industrial Ethernet, Profinet, Ethernet/IP. Контроллеры обзавелись сетевыми картами, и теперь они торчат в локальной сети как новогодние ёлки. А протоколы остались теми же - доверчивыми, как щенки. Вендоры, конечно, пытаются навернуть безопасность сверху: ставят пароли на загрузку проекта, вводят уровни доступа, шифрование в новых версиях. Но фундамент остался старым. Внутри каждого PLC есть функции, которые просто обязаны быть для инженерного софта: читать любой кусок памяти, писать в любой адрес, останавливать и запускать процессор. Эти функции недокументированы для широкой публики, но они есть в каждой прошивке. И если ты знаешь, как их вызвать, контроллер сделает всё, что ты скажешь, независимо от того, ввёл ты пароль или нет. Поехали, брат. Открывай терминал, запускай Wireshark, готовь кабель. Мы идём в гости к PLC, и хозяин даже не узнает, что мы там были. Часть 1. Анатомия ПЛК: Вскрытие покажет, где хранятся ваши тайны 1.1. ПЛК - это просто компьютер, который носит спецовку Давай сразу договоримся: ПЛК (программируемый логический контрлер) - это не магическая коробочка с молниями. Это специализированный компьютер. У него есть:
1.2. Карта памяти: Где лежит что Представь себе память контроллера как огромный склад с ячейками. Вендор (Siemens, Schneider и др.) заранее разбил этот склад на зоны. Каждая зона имеет своё назначение. В документации к контроллеру обычно есть карта памяти, но в общем виде это выглядит так: Области памяти (на примере Siemens S7, но аналоги есть у всех)
У Rockwell (ControlLogix) - тэговая архитектура. Там нет фиксированных областей I, Q, M, а есть просто тэги (переменные) с именами, которые могут быть как базовыми типами (BOOL, DINT, REAL), так и структурами. Но физически они тоже лежат в памяти по определённым адресам, просто адресация динамическая. 1.3. Теги, переменные и абсолютные адреса Теперь важный момент: что мы читаем, когда подключаемся к контроллеру через инженерный софт? Мы видим теги (или переменные). Тег - это имя, которое программист дал какому-то адресу. Например, Engine_Start может соответствовать биту Q0.0. Или Pressure_Tank может соответствовать REAL-переменной в DB1.DBD12. Инженерный софт (TIA Portal, Unity Pro) хранит в проекте таблицу символов - соответствие имён адресам. Когда вы открываете проект, вы видите удобные имена, и можете следить за их значениями. Но контроллеру плевать на имена. Контроллер оперирует адресами. Когда программа компилируется, все имена превращаются в конкретные адреса памяти. И когда вы просите контроллер дать значение тега Engine_Start, инженерный софт переводит это в запрос: "Прочитай мне бит по адресу Q0.0". Контроллер отвечает: "Вот бит". А что, если у нас нет проекта и мы не знаем, какой адрес соответствует какому тегу? Мы всё равно можем читать адреса напрямую. Мы можем сказать контроллеру: "Дай мне 100 байт, начиная с адреса Q0.0". Контроллер даст. Он не спросит: "А зачем тебе? А кто ты?" Он просто отдаст данные. Потому что это его работа - обслуживать запросы от мастер-устройств. 1.4. Инженерный софт как привилегированный клиент Инженерный софт - это не просто программа, которая показывает красивые лесенки. Это клиент, который общается с контроллером по определённому протоколу. В этом протоколе заложены различные функции (сервисы):
Ирония в том, что эти функции всегда доступны, если у вас есть сетевое соединение. Да, производители добавляют пароли, но часто они защищают только определённые действия (например, загрузку проекта), а чтение памяти остаётся открытым. Потому что иначе как бы вы мониторили значения в онлайн-режиме без пароля? Вендоры пытаются балансировать между удобством и безопасностью, и, как обычно, удобство побеждает. 1.5. Что такое «недокументированные функции»? Термин звучит зловеще, как что-то из арсенала спецслужб. На самом деле, всё проще. Есть официальная документация по протоколам, которую вендоры выкладывают в открытый доступ. Там описаны основные функции, которые нужны для разработки приложений верхнего уровня (SCADA, OPC-серверы). Но есть функции, которые в документацию не попадают. Почему? Потому что они предназначены только для инженерного софта, и вендор считает, что обычным пользователям они не нужны, либо их использование может быть опасным (можно нарушить работу контроллера). Например, функция "Записать в оперативную память напрямую, минуя защиту" - она есть, но в документации вы её не найдёте. Или функция "Остановить CPU" - тоже есть, но её вызов без пароля может быть запрещён настройками, но сам по себе запрос протоколом предусмотрен. Недокументированные функции - это просто коды операций (function codes), которые прошивка контроллера распознаёт, но которые не описаны в публичных спецификациях. Их находят исследователи методом реверс-инжиниринга: сниффают трафик между инженерным софтом и контроллером, видят странные запросы, анализируют, пробуют повторить. Так рождаются библиотеки вроде Snap7, которые умеют делать с контроллером всё то же, что и родной Step7, но без лицензии и без графического интерфейса. 1.6. Чтение тегов через чтение памяти Вернёмся к нашим баранам. Нам нужно читать теги (переменные), не зная логики программы. Как это сделать? Метод 1: Чтение по абсолютным адресам. Если мы знаем, что в данном контроллере входы лежат по адресам I0.0 – I0.7, выходы по Q0.0 – Q0.7, а данные, скорее всего, в DB, мы можем начать читать их все подряд и анализировать. Метод 2: Поиск по шаблонам. Если мы знаем тип переменной (например, REAL - 4 байта в формате IEEE754), мы можем сканировать память в поисках значений, которые выглядят как правдоподобные числа (не слишком большие, не слишком маленькие, меняются плавно). Это поможет найти аналоговые сигналы. Метод 3: Динамический анализ. Мы воздействуем на процесс (нажимаем кнопку, меняем уставку через HMI) и смотрим, какие байты в памяти изменились. Те, которые изменились - вероятно, связаны с нашим воздействием. Повторяем несколько раз, сужаем круг. Метод 4: Использование уязвимостей. Иногда можно обойти защиту и выгрузить таблицу символов прямо из контроллера (например, в старых версиях Siemens S7-1200 символическая информация загружалась в контроллер и могла быть считана). Но в новых версиях это обычно отключено. 1.7. Примеры конкретных протоколов и их возможностей Siemens S7 (S7-300, 400, 1200, 1500)
Давай теперь приземлимся. Кто может реально использовать эти методы?
Всё упирается в фундаментальное свойство: PLC не аутентифицирует клиента на уровне протокола. Есть исключения (например, Siemens S7-1500 с включённой защитой может требовать пароль даже на чтение), но по умолчанию - открыто. Протоколы разрабатывались для замкнутых сред, где все устройства доверяют друг другу. Перенос их в IP-сети без дополнительной защиты - как оставить ключи в замке зажигания и уйти. Производители сейчас пытаются исправиться: в новых версиях появляются функции: разрешить чтение только с определённых IP-адресов, требовать пароль на запись, шифрование. Но старых контроллеров на заводах - миллионы, и менять их никто не будет. Так что на ближайшие 20 лет это всё актуально. Часть 2. Анатомия: Как программа лежит в памяти контроллера Структура памяти (сильно упрощенно, но для понимания сути - ок):
Если мы знаем, что давление в ёмкости регулируется заслонкой, которая висит на выходе Q0.7, нам плевать, как технолог назвал эту переменную. Мы просто пишем 1 в бит Q0.7 и клапан открывается. Вопрос в том, как найти, какой бит за что отвечает? И тут начинается самое интересное: анализ поведения. Часть 3. Инструментарий: Строим мост к контроллеру Хватит теории. Давай говорить о конкретике. Мы не будем пользоваться только мышем и кликать в графическом интерфейсе (хотя и это метод). Мы будем использовать инструменты, которые дают нам прямой, нефильтрованный доступ к протоколу. Инструмент 1: Snap7 (и его обертки) Это, пожалуй, легенда. Snap7 - это открытая библиотека на C++, которая полностью эмулирует поведение клиента S7 (для Siemens S7-300, S7-400, S7-1200, S7-1500). Она обращается к контроллеру по протоколу S7, не требуя наличия Step7 или TIA Portal. Что она нам дает?
Python: Код:
importИнструмент 2: libplctag (для ControlLogix/CompactLogix от Rockwell) Если ты имеешь дело с продукцией Rockwell Automation (Allen-Bradley), там своя песня - протокол CIP. Но для него есть libplctag. Это библиотека, которая позволяет читать и писать тэги. Принцип тот же: подключаемся, читаем память. Инструмент 3: pyads (для TwinCAT от Beckhoff) TwinCAT от Beckhoff использует протокол AMS (производный от того, что использовался в старом добром S5). Библиотека pyads дает прямой доступ к переменным по имени. Если имена неизвестны, можно сканировать память. Инструмент 4: Инженерный софт (в «нелегитимном» режиме) Да, сам софт тоже подходит. Но мы будем использовать его хитро. Забудем про открытие проекта. Мы просто создадим пустой проект (или любой левый), сконфигурируем железо (CPU) и подключимся к контроллеру. В Siemens TIA Portal есть функция "Online & Diagnostics" и "Go online" (работа в режиме онлайн без загрузки проекта). Там можно смотреть таблицы переменных (Watches/Forces) и смотреть сырые значения. Но есть нюанс: TIA Portal захочет, чтобы структура данных в проекте совпадала с контроллером для удобного отображения. Он может отказаться показывать DB, если у него нет информации о типах. Но! Он всегда может показать системные области (M, I, Q). Это уже хлеб. Часть 4. Практика: Методология разведки (Recon) Допустим, мы подключились к контроллеру неизвестной установки. Мы не знаем логики, не знаем, где что лежит. Наша задача - найти критические переменные. Шаг 1. Сканирование памяти. Мы не будем тупо качать все DB подряд. Мы будем искать паттерны. Используем скрипт на Python (через snap7), который будет пробегаться по адресам и искать определенные значения.
Вот тут начинается магия. Мы будем дергать за переменные и смотреть, что изменится в реальном мире (или в показаниях других переменных). Техника называется "Fuzzing" применительно к полям ввода-вывода, но с умным подходом.
Siemens (Step7 / TIA Portal)
Допустим, мы можем читать и писать память. Но как понять, что мы не сломаем станок? Для этого нужно понимать логику "снаружи". Представь, что логика - это функция F(Inputs) -> Outputs. Мы можем подавать на вход произвольные значения и смотреть на выход. Это называется моделированием. Пример: Есть программа, управляющая насосом. Насос включается, если уровень в резервуаре ниже 2 метров и если не нажата кнопка аварийного останова. Нам не обязательно читать код программы, чтобы это понять. Мы можем:
7.1. Зачем вообще нужно глубоко копать? Скажи мне, зачем тебе Wireshark, если есть Snap7, который и так умеет читать DB? Ответ прост: Snap7 реализует известные функции протокола. А что, если контроллер новой модели, и старые функции там не работают? Или если защита включена, но мы подозреваем, что есть обходной путь? Или мы хотим найти те самые недокументированные функции, которые инженерный софт вызывает, а в документации их нет? Без глубокого анализа ты будешь слепым котёнком. Ты не узнаешь, какие ещё сервисы предоставляет контроллер, какие уязвимости в прошивке можно дёрнуть. Поэтому мы начинаем с самого базового - с прослушки трафика. 7.2. Wireshark: Глаза и уши хакера Wireshark - это, без преувеличения, швейцарский нож сетевого аналитика. Если ты его ещё не установил - бегом ставить. Это бесплатно, кроссплатформенно, и умеет разбирать сотни протоколов, включая промышленные (S7, Modbus/TCP, Profinet, Ethernet/IP, CIP и многие другие). 7.2.1. Первый запуск и захват трафика Допустим, у тебя есть инженерная станция с TIA Portal и контроллер Siemens S7-1200. Ты хочешь понять, что именно происходит, когда ты нажимаешь «Go online» и смотришь значения переменных.
7.2.2. Фильтры отображения - наше всё Wireshark умеет показывать только нужные пакеты. Вот несколько фильтров, которые тебе пригодятся:
7.2.3. Разбор S7-пакета на примере Посмотрим на типичный запрос чтения DB от TIA Portal к контроллеру. В Wireshark ты увидишь примерно такую структуру:
А теперь самое интересное: иногда инженерный софт вызывает функции, которых нет в документации. Например, функция 0x1a (запись в системную память) или 0x28 (PLC stop). Wireshark их покажет. Ты можешь подсмотреть, какие параметры передаются, и потом повторить эти запросы через свой скрипт. 7.2.4. Анализ недокументированных функций на примере Siemens Когда я в первый раз смотрел трафик S7, я заметил, что перед чтением больших блоков TIA Portal отправляет какой-то странный пакет с функцией 0x1f. Я полез в интернет, нашёл старые документы - оказалось, это функция "Request download" (запрос на загрузку). В новых версиях она используется реже, но в старых контроллерах она открывала доступ к загрузке проекта без пароля. Как это работает: ты отправляешь пакет с функцией 0x1f, контроллер отвечает OK, и после этого можно читать и писать любые блоки, даже защищённые. Это, конечно, давно пофиксили, но на S7-300 с устаревшей прошивкой - до сих пор работает. И ты это можешь обнаружить только через Wireshark. 7.2.5. Modbus/TCP - простота хуже воровства С Modbus всё ещё проще. Wireshark отлично декодирует Modbus. Ты увидишь:
7.2.6. Полезные приёмы работы с Wireshark
Не вздумай включать Wireshark на живом работающем объекте без согласования. Во-первых, захват трафика может создать дополнительную нагрузку на коммутаторы (если ты включишь режим promiscuous и будешь ловить всё подряд, это может загрузить CPU). Во-вторых, если ты случайно отправишь какой-то пакет (например, с неправильной контрольной суммой), контроллер может зависнуть. В-третьих, сам факт прослушки может нарушать политику безопасности. Так что всегда делай это на тестовых стендах или с письменного разрешения. 7.3. pyhs220: Работа с недокументированными функциями Siemens Переходим к инструменту, который уже не для новичков. pyhs220 - это Python-библиотека (или, точнее, набор скриптов), которая реализует низкоуровневый доступ к контроллерам Siemens через протокол S7. В отличие от Snap7, который предоставляет высокоуровневые функции, pyhs220 позволяет формировать произвольные S7-запросы, в том числе те, которых нет в официальной документации. 7.3.1. Что такое HS и при чём тут 220? HS - это Hacker's Choice? Нет, скорее, отсылка к старым исследованиям. Исходники pyhs220 можно найти на GitHub, но они древние, под Python 2. Однако, их можно адаптировать. Главная ценность - это примеры формирования пакетов для нестандартных функций: останов CPU, запись в защищённую память, чтение диагностики. 7.3.2. Пример: остановка S7-300 без пароля В старых контроллерах (S7-300, S7-400) функция остановки CPU (PLC STOP) часто доступна без аутентификации, если не включена защита в свойствах CPU. В TIA Portal она вызывается через меню, но по протоколу это просто пакет с определённым кодом функции. Пример кода с использованием pyhs220 (псевдокод, потому что реальный синтаксис может отличаться): Python: Код:
import7.3.3. Обход Know-How Protection В старых версиях Step7 защита know-how protection (блокировка чтения исходного кода) реализовывалась просто: в заголовке блока выставлялся флаг, и инженерный софт отказывался показывать содержимое. Но через прямое чтение памяти можно было вычитать блок целиком как бинарные данные. В pyhs220 есть примеры, как вычитать блок и потом вручную убрать флаг защиты. Python: Код:
# Чтение блока OB17.3.4. Поиск уязвимостей с pyhs220 pyhs220 удобен для фаззинга (fuzzing) - отправки случайных или некорректных запросов, чтобы проверить, не упадёт ли контроллер. Можно написать скрипт, который будет перебирать разные функции, разные параметры, и смотреть на реакцию. Если контроллер перестаёт отвечать или зависает - значит, найдена уязвимость типа DoS. Иногда такие уязвимости позволяют выполнить код, но это редкость. 7.3.5. Где брать и как использовать Оригинальный репозиторий pyhs220 на GitHub (от пользователя h2h) уже мёртв. Но исходники можно найти на форумах типа plcforum или в архивах. Я бы рекомендовал не тратить время на древний Python 2, а написать свой велосипед на Python 3, используя структуру пакетов из документации Snap7 или из открытых спецификаций. Snap7, кстати, тоже умеет отправлять пользовательские PDU, но для этого нужно копаться в его внутренностях. Альтернатива: использовать Scapy с поддержкой S7 (есть плагины). Но это для тех, кто любит сложности. 7.4. Metasploit: Тяжёлая артиллерия Когда ты уже перерос уровень одиночных скриптов и хочешь автоматизировать атаки, проводить пентесты по-взрослому, тебе пригодится Metasploit. Да, этот фреймворк, известный своими эксплойтами для Windows и Linux, имеет модули и для промышленных контроллеров. 7.4.1. Модули для Siemens В Metasploit есть несколько модулей для работы с Siemens PLC. Самый известный - auxiliary/admin/scada/siemens_s7_300_400_cpu_command. Он позволяет отправлять команды на CPU (старт, стоп, сброс) через недокументированные функции. Использование:
7.4.2. Модули для Modicon (Schneider) Есть модуль auxiliary/admin/scada/modicon_stop для остановки контроллеров Modicon через Modbus. Работает просто: отправляет специальную команду в функциональный код 90 (нестандартный). Если контроллер не защищён, он уходит в STOP. 7.4.3. Модули для чтения памяти Есть модули для чтения регистров Modbus: auxiliary/scanner/scada/modbus_find_holding_registers. Он сканирует диапазон адресов и читает значения, помогая составить карту памяти. 7.4.4. Написание собственного модуля Metasploit Если ты хочешь автоматизировать какой-то специфический эксплойт, можешь написать свой модуль на Ruby. Metasploit предоставляет удобные API для работы с сокетами, таймерами, шелл-кодами. Но для PLC это редко нужно, обычно хватает готовых модулей и вспомогательных скриптов. 7.4.5. Ограничения Metasploit Главное ограничение: Metasploit - это инструмент для атак, и его использование без разрешения незаконно. Кроме того, многие модули заточены под старые версии прошивок. На новых контроллерах (S7-1500, M580 с активированной защитой) они не сработают. Но для проверки унаследованных систем - самое оно. 7.5. Другие нишевые инструменты Кроме трёх китов (Wireshark, pyhs220, Metasploit), есть ещё куча специализированных утилит, которые стоит знать. 7.5.1. plcscan Скрипт на Python для сканирования промышленных протоколов. Он умеет определять тип контроллера, версию прошивки, открытые сервисы. Используется для разведки: ты запускаешь его в сети и получаешь список всех PLC с их характеристиками. Bash: Код:
python plcscan.pyКод: Код:
192.168.0.1:102 Siemens S7-300, CPU 315-2 PN/DP, Firmware V3.27.5.2. modpoll Утилита командной строки для опроса Modbus-устройств. Поддерживает все основные функции: чтение/запись регистров, битов. Легко встраивается в скрипты. Bash: Код:
modpoll -m tcp -a7.5.3. cpppo Библиотека Python для работы с Ethernet/IP и CIP. Позволяет читать и писать тэги в контроллерах Rockwell. Очень мощная, поддерживает не только базовые типы, но и структуры, массивы. Python: Код:
fromРамка для эксплуатации промышленных систем, разработанная авторами известной книги "Hacking Exposed: Industrial Control Systems". Написана на Python, включает модули для сканирования, эксплуатации уязвимостей, работы с протоколами. Позиционируется как аналог Metasploit, но специализированный для АСУ ТП. К сожалению, проект развит слабо, но исходники доступны и могут быть полезны для изучения. 7.5.5. S7Scan Утилита для сканирования Siemens S7. Умеет определять тип CPU, состояние (RUN/STOP), версию, а также пытается подобрать пароль по словарю (через недокументированные функции). Полезно для аудита. 7.6. Комбинирование инструментов: Реальный сценарий Давай представим, что ты проводишь пентест завода. Как ты будешь использовать все эти инструменты?
Может показаться, что мы тут собрались всё ломать. А вот хрен там. Самые крутые инженеры используют эти техники каждый день, просто не всегда об этом говорят.
Мы с тобой рассмотрели, как можно залезть в кишки ПЛК, не зная пароля и логики. Это не просто дырка - это архитектурная особенность. Промышленные протоколы разрабатывались в эпоху, когда об интернете вещей даже не слышали, и главным требованием была надежность и скорость, а не безопасность. Вендоры много лет закладывали мины под свои системы, надеясь на изоляцию сетей (air gap). Сейчас эти мины взрываются на каждом шагу. Наша с тобой задача - не просто научиться пользоваться этими знаниями, а понять глубину проблемы. Когда ты в следующий раз будешь настраивать контроллер или проект, помни:
Заключение: Почему это вообще возможно? Всё это возможно по одной простой причине: протоколы промышленной автоматизации создавались для надёжности и детерминизма, а не для безопасности. В 80-е и 90-е годы, когда закладывалась архитектура Modbus, Profibus, S7, никто не предполагал, что эти сети будут торчать в интернете. Заводы были изолированы физически, и главной угрозой считался электрик, который ошибётся с проводами, а не хакер из другой страны. Протоколы были закрытыми (проприетарными) не для защиты от злоумышленников, а для конкурентного преимущества. Вендоры надеялись, что сложность форматов сама по себе отпугнёт любопытных. Это называется «безопасность через неясность» (security by obscurity). И мы все знаем, чем это заканчивается: рано или поздно находится энтузиаст с Wireshark и паяльником, который всё раскуривает. Когда промышленные сети начали переходить на Ethernet, протоколы просто завернули в TCP/IP, не добавив ни грамма аутентификации или шифрования. Modbus TCP - это Modbus RTU, упакованный в TCP-пакет. S7 over Ethernet - это старый добрый S7, только поверх TCP-порта 102. Всё те же функциональные коды, всё те же адреса. Да, сейчас вендоры добавляют функции безопасности: пароли на загрузку проекта, списки доступа (IP-фильтрация), шифрование (например, S7-1500 с опцией Security), ролевые модели. Но:
Итог и напутствие Мы с тобой разобрали тему чтения тегов контроллеров через недокументированные функции от А до Я. Ты узнал, как устроена память PLC, какие протоколы используются, как работают основные библиотеки, как искать переменные без документации и как этим пользоваться. Теперь у тебя есть знания, которые выделяют тебя из толпы обычных инженеров-эксплуатационников. Ты можешь не просто нажимать кнопки в SCADA, а понимать, что происходит на уровне железа. Ты можешь находить проблемы, которые другие не видят. Ты можешь защищать свои объекты от реальных угроз. Но помни про ответственность. Знание - сила, но большая сила требует большой ответственности. Используй эти навыки во благо: восстанавливай утерянное, помогай коллегам, ищи баги, делай промышленность безопаснее. Кодекса у нас нет, но чувство правильного есть у каждого. |
| Время: 00:45 |