ГлавнаяБлогEtherNet/IP и CIP: понимание протоколов на уровне байтов
Алгоритмы

EtherNet/IP и CIP: понимание протоколов на уровне байтов

Разберитесь, как работают EtherNet/IP и CIP на уровне сырых сокетов. Поймите, почему абстракции скрывают реальное поведение PLC. Начните писать свои анализаторы прямо сейчас.

Al
Редакция Algolitalgolit.ru
10 мин чтения30 июня 2026 г.

Зачем понимать EtherNet/IP и CIP на уровне байтов?

Вы когда-нибудь пытались отладить взаимодействие с PLC и получали тишину в ответ — ни ошибок, ни данных? Если вы полагаетесь на высокоуровневые библиотеки вроде Scapy или cpppo, то рискуете не заметить, как протокол на самом деле обрабатывает ваши команды. В этой статье мы на практике разберём, как устроены EtherNet/IP и CIP, и покажем, почему знание сырых сокетов критично для безопасности и отладки OT-систем.

Абстракции скрывают архитектуру

Многие разработчики считают, что библиотеки дают полное понимание протокола. На самом деле они скрывают детали, которые могут привести к сбоям. Чтобы увидеть реальную картину, я построил песочницу EtherNet/IP и CIP с нуля: никаких Scapy, только сырые сокеты, Linux loopback, симулятор cpppo и пассивный монитор enip_monitor.py. Когда я добрался до прикладного уровня, теория перестала работать.

Структура EtherNet/IP и CIP

В отличие от Modbus с его линейным адресным пространством, EtherNet/IP и CIP используют объектную модель, упакованную в несколько уровней:

+-----------------------------------------------------------+
| EtherNet/IP Encapsulation Header (24 байта)               |
| → Управление сессией, команды (0x0065, 0x006F)            |
+-----------------------------------------------------------+
| Common Packet Format (CPF)                                |
| → Маршрутизация, адресация, сегментация                   |
+-----------------------------------------------------------+
| CIP Application Layer                                     |
| → Коды сервисов (0x4C, 0x4D, 0x10 и т.д.)                |
+-----------------------------------------------------------+

Чтобы общаться с PLC на уровне проводов, ваш код должен:

  • Установить сессию через RegisterSession (0x0065)
  • Оборачивать все запросы в SendRRData (0x006F)
  • Кодировать информацию о маршрутизации внутри CPF
  • Строить символьные или логические пути для CIP Message Router
  • Соблюдать строгое выравнивание байтов во вложенных уровнях

Любая ошибка на любом уровне приводит к молчаливому отказу.

Фрагментация и путаница состояний

Базовые операции чтения (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_TAG

PLC ответил кодом General Status 0x05 (Path Destination Unknown). Этот момент подтвердил: то, что клиент думал, что отправил, и то, что реально ушло на провод, — разные вещи. Как только я выровнял смещения фрагментации, полезная нагрузка начала передаваться корректно. Система никогда не была сломана — сломаны были предположения.

Практический вывод: что делать прямо сейчас

Этот проект доказал: абстракции не гарантируют понимания. Они часто его устраняют. EtherNet/IP и CIP оптимизированы для скорости и совместимости, но их модель выполнения неявна и требует точной сборки пакетов. С точки зрения безопасности это важно, потому что:

  • Протокол доверяет правильно сформированным пакетам по умолчанию
  • Символьные и объектные структуры наблюдаемы извне
  • Состояния ошибок раскрывают информацию о внутренней маршрутизации
  • Во многих устаревших конфигурациях для взаимодействия не требуется аутентификация

Чтобы защитить такие системы, работайте на уровне проводов:

  • Стройте логику обнаружения на основе пакетов (правила Suricata/Snort)
  • Мониторьте поведение инкапсуляции и CIP-сервисов напрямую
  • Внедряйте строгую сегментацию сети и контроль режимов устройств
  • Используйте CIP Security, где это поддерживается

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

Все скрипты, сценарии проверки и 13 вспомогательных заметок доступны в репозитории: github.com/404saint/industrial-protocol-labs/

Дисклеймер: это исследование проводилось в контролируемой лабораторной среде в образовательных целях. Не используйте эти методы против production-систем без явного разрешения.

#EtherNet/IP#CIP#промышленные протоколы#безопасность OT#сырые сокеты
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →