
Демонстрация оборонительной безопасности: шлюз на микроядре seL4, защищающий уязвимые ICS от CVE-2019-14462
Исследовательский проект в области защитной безопасности, сравнивающий архитектуры разрыва протокола и пересылки пакетов для защиты промышленных систем управления от кибератак.
Документация:
- Сетевая архитектура — схемы сети и потоки трафика
- Архитектура контейнеров — связи между контейнерами Docker
- Пояснения по CVE — детали уязвимостей и механизмы атак
Современные ICS/SCADA-системы сталкиваются со сложными атаками, такими как FrostyGoop, которая в январе 2024 года атаковала украинские системы районного отопления через Modbus TCP, оставив более 600 домохозяйств без тепла при температуре ниже нуля. Традиционные решения безопасности (межсетевые экраны, IDS) используют архитектуры пересылки пакетов, которые проверяют трафик in-line, но поддерживают единое сквозное TCP-соединение.
Этот проект демонстрирует альтернативу: шлюз с разрывом протокола на основе формально верифицированного микроядра seL4. Завершая TCP-соединения и проверяя семантику протокола перед установлением новых соединений с защищаемыми устройствами, такая архитектура обеспечивает более строгие гарантии безопасности.
| Аспект | Разрыв протокола (seL4) | Пересылка пакетов (Snort) |
|---|---|---|
| CVE-2019-14462 | ЗАБЛОКИРОВАНО (проверка длины) | ОБНАРУЖЕНО (правила Quickdraw) |
| CVE-2022-0367 | ЗАБЛОКИРОВАНО (проверка адреса) | ОБНАРУЖЕНО (пользовательские правила) |
| CVE-2022-20685 | НЕУЯЗВИМ (нет препроцессора) | УЯЗВИМ (DoS IDS) |
| CVE-2024-1086 | НЕУЯЗВИМ (нет ядра Linux) | УЯЗВИМ (использует ядро хоста) |
| Неизвестные варианты | ЗАБЛОКИРОВАНО (проверка структуры) | ПРОПУЩЕНО (нет сигнатуры) |
| Атаки на состояние TCP | ЗАБЛОКИРОВАНО (соединение разорвано) | Возможно |
| Поверхность атаки | ~1000 строк кода (микроядро) | ~500 000 строк кода (Linux + Snort) |
┌─────────────────────────────────────────────────────────────────────────────┐
│ Docker Network: ics-untrusted (192.168.96.0/24) │
│ │
│ ┌───────────────────────┐ ┌───────────────────────┐ │
│ │ seL4 Gateway │ │ Snort IDS │ │
│ │ Port 502 │ │ Port 503 │ │
│ │ │ │ │ │
│ │ • Protocol-break │ │ • Packet-forwarding │ │
│ │ • TCP termination │ │ • Inline inspection │ │
│ │ • Length validation │ │ • Rule-based detection│ │
│ └───────────┬───────────┘ └───────────┬───────────┘ │
│ │ │ │
├───────────────┼───────────────────────────────┼─────────────────────────────┤
│ Docker Network: ics-protected (192.168.95.0/24) │
│ │ │ │
│ └───────────────┬───────────────┘ │
│ ▼ │
│ ┌───────────────────────────────┐ │
│ │ PLC (District Heating) │ │
│ │ Vulnerable libmodbus 3.1.2 │ │
│ │ Port 5020 (direct access) │ │
│ └───────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
# Place your seL4 kernel image at:
gateway/sel4-image/capdl-loader-image-arm-qemu-arm-virt
# Build all containers
sudo docker compose build
# Start individual containers
sudo docker compose up plc # PLC only
sudo docker compose up gateway # seL4 gateway + PLC
sudo docker compose up snort # Snort IDS + PLC
# Start all
sudo docker compose up
# Through seL4 gateway (protected - protocol-break)
echo -ne '\x00\x01\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01' | nc localhost 502 | xxd
# Through Snort IDS (protected - packet-forwarding)
echo -ne '\x00\x01\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01' | nc localhost 503 | xxd
# Direct to PLC (unprotected - vulnerable)
echo -ne '\x00\x01\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01' | nc localhost 5020 | xxd
| Порт | Маршрут | Архитектура | Защита |
|---|---|---|---|
| 502 | Клиент → seL4 → ПЛК | Разрыв протокола | Проверяет структуру Modbus |
| 503 | Клиент → Snort → ПЛК | Пересылка пакетов | IDS на основе правил |
| 5020 | Клиент → ПЛК (ASAN) | Прямое подключение | Режим CVE-2022-0367 |
| 5022 | Клиент → ПЛК | Прямое подключение | Режим CVE-2019-14462 (профиль: cve14462) |
Примечание: ПЛК по умолчанию теперь работает в режиме CVE-2022-0367 с ASAN. Используйте
--profile cve14462для тестирования CVE-2019-14462.
ПЛК использует намеренно уязвимый libmodbus 3.1.2. Атака эксплуатирует доверенные поля длины MBAP:
# Start PLC in CVE-2019-14462 mode
sudo docker compose --profile cve14462 up plc-14462
# Build attack tools
cd cve_tools && make
# Attack unprotected PLC (crashes)
./cve_14462_attack 127.0.0.1 5022
# Attack through seL4 (BLOCKED)
./cve_14462_attack 127.0.0.1 502
# Attack through Snort (DETECTED by Quickdraw rules)
./cve_14462_attack 127.0.0.1 503
Ошибка проверки границ в modbus_mapping_new_start_address() позволяет вызвать недополнение буфера кучи через код функции 0x17 (Write and Read Registers):
# Default PLC runs in CVE-2022-0367 mode with ASAN
sudo docker compose up plc
# Build attack tools
cd cve_tools && make
# Attack PLC - ASAN will detect heap-buffer-overflow
./cve_0367_attack 127.0.0.1 5020
# Attack with custom parameters
./cve_0367_attack 127.0.0.1 5020 88 0x4141 # Corrupt tab_registers pointer
./cve_0367_attack 127.0.0.1 5020 72 0xFFFF # Corrupt nb_registers
# Attack through seL4 (BLOCKED - address validation)
./cve_0367_attack 127.0.0.1 502
# Attack through Snort (DETECTED by custom rules)
./cve_0367_attack 127.0.0.1 503
Технические детали:
start_registers=100, допустимые адреса — 100-109write_address < 100, что приводит к отрицательному индексу массиваmb_mapping, включая указателиВ Snort 2.9.18 есть целочисленное переполнение в препроцессоре Modbus, вызывающее бесконечный цикл и полностью блокирующее весь трафик через IDS:
# 1. Verify Snort is working (should return Modbus response)
echo -ne '\x00\x01\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01' | nc -w 2 localhost 503 | xxd
# 2. Attack the Snort IDS
./cve_20685_attack 127.0.0.1 503
# 3. Verify Snort is frozen (should timeout with NO response)
echo -ne '\x00\x01\x00\x00\x00\x06\x01\x03\x00\x00\x00\x01' | nc -w 5 localhost 503 | xxd