Разберитесь, как работают EtherNet/IP и CIP на уровне сырых сокетов. Поймите, почему абстракции скрывают реальное поведение PLC. Начните писать свои анализаторы прямо сейчас.
Вы когда-нибудь пытались отладить взаимодействие с PLC и получали тишину в ответ — ни ошибок, ни данных? Если вы полагаетесь на высокоуровневые библиотеки вроде Scapy или cpppo, то рискуете не заметить, как протокол на самом деле обрабатывает ваши команды. В этой статье мы на практике разберём, как устроены EtherNet/IP и CIP, и покажем, почему знание сырых сокетов критично для безопасности и отладки OT-систем.
Многие разработчики считают, что библиотеки дают полное понимание протокола. На самом деле они скрывают детали, которые могут привести к сбоям. Чтобы увидеть реальную картину, я построил песочницу EtherNet/IP и CIP с нуля: никаких Scapy, только сырые сокеты, Linux loopback, симулятор cpppo и пассивный монитор enip_monitor.py. Когда я добрался до прикладного уровня, теория перестала работать.
В отличие от Modbus с его линейным адресным пространством, EtherNet/IP и CIP используют объектную модель, упакованную в несколько уровней:
+-----------------------------------------------------------+
| EtherNet/IP Encapsulation Header (24 байта) |
| → Управление сессией, команды (0x0065, 0x006F) |
+-----------------------------------------------------------+
| Common Packet Format (CPF) |
| → Маршрутизация, адресация, сегментация |
+-----------------------------------------------------------+
| CIP Application Layer |
| → Коды сервисов (0x4C, 0x4D, 0x10 и т.д.) |
+-----------------------------------------------------------+Чтобы общаться с PLC на уровне проводов, ваш код должен:
Любая ошибка на любом уровне приводит к молчаливому отказу.
Базовые операции чтения (0x4C) и записи (0x4D) тегов работали нормально. Но когда я перешёл к фрагментированным передачам (0x52 — Read Fragmented, 0x53 — Write Fragmented), всё сломалось. Я вручную отслеживал смещения, количество элементов и границы буферов. Клиент сообщал об успехе:
[+] Attribute Write Resolved: write_frag.elements
[+] Attribute Write Resolved: write_frag.offset
[+] Attribute Write Resolved: write_frag.data
[+] Attribute Write Resolved: serviceНо на проводе ничего не менялось. Ни значений, ни ошибок — просто молчаливый отказ. На этом уровне нет стека вызовов. Если один байт в CPF или пути неверен, CIP Message Router молча отбрасывает внутреннее выполнение.
Переломный момент наступил, когда я запустил enip_monitor.py параллельно с клиентом. Вместо того чтобы верить внутренним логам, я начал доверять потоку пакетов. Я вызвал намеренный сбой, запросив несуществующий тег NON_EXISTENT_TAG. Монитор сразу показал реальное поведение:
[!] SESSION REGISTRATION DETECTED | Handle: 0xe946f379 | Status: 0
[+] INDUSTRIAL MONITORING ALERT
Source IP : 127.0.0.1
Session : 0xf6d8e0cf
CIP Service : Unconnected Send (Router)
Target : NON_EXISTENT_TAGPLC ответил кодом General Status 0x05 (Path Destination Unknown). Этот момент подтвердил: то, что клиент думал, что отправил, и то, что реально ушло на провод, — разные вещи. Как только я выровнял смещения фрагментации, полезная нагрузка начала передаваться корректно. Система никогда не была сломана — сломаны были предположения.
Этот проект доказал: абстракции не гарантируют понимания. Они часто его устраняют. EtherNet/IP и CIP оптимизированы для скорости и совместимости, но их модель выполнения неявна и требует точной сборки пакетов. С точки зрения безопасности это важно, потому что:
Чтобы защитить такие системы, работайте на уровне проводов:
Если хотите по-настоящему понять OT-системы, не начинайте с инструментов. Начинайте с байтов. Сырые сокеты — раздражающие, медленные и безжалостные, но они показывают то, что пытаются скрыть все абстракции.
Все скрипты, сценарии проверки и 13 вспомогательных заметок доступны в репозитории: github.com/404saint/industrial-protocol-labs/
Дисклеймер: это исследование проводилось в контролируемой лабораторной среде в образовательных целях. Не используйте эти методы против production-систем без явного разрешения.
Хочешь закрепить знания на практике?
Решай задачи на Algolit — интерактивная платформа для обучения
Начать бесплатно →