
Guía paso a paso de análisis y explotación para CVE-2019-3396, una vulnerabilidad SSTI crítica en Confluence Server & Data Center, incluyendo depuración y ejecución de payloads de RCE.
Producto afectado: Confluence Server & Data Center
Versiones afectadas: de 6.0.0 a 6.15.4
Gravedad: Crítica (CVSS ~9.8)
Causa:
Confluence tiene el plugin Widget Connector (usado para incrustar videos, contenido externo como YouTube, Vimeo…).
Esta funcionalidad no controla correctamente la entrada del usuario, lo que lleva a una Inyección de Plantillas del Lado del Servidor (SSTI).
Un atacante puede enviar un payload malicioso → Confluence lo renderiza usando el motor de plantillas Velocity → ejecuta código en el servidor.
https://www.atlassian.com/software/confluence/downloads/binary/atlassian-confluence-6.9.0.zip
https://nguyendt.hashnode.dev/confluence-cve-2019-3396




Widget Connector, intentamos buscar en la carpeta fuente de Confluence
com.atlassian.confluence.extra.widgetconnector.WidgetMacro.classDefaultRenderManager.class
getEmbeddedHtml()
YoutubeRendererurl → enlace original de YouTube ingresado por el usuarioparams → mapa que contiene los parámetros de configuración para el renderizado (por ejemplo: ancho, alto, plantilla a usar,…).
getEmbedUrl(), setDefaultParam() y DefaultVelocityRenderService.render()setDefaultParam()
Si no hay _template → se asigna la plantilla predeterminada youtube.vm.
=> Se puede agregar _template manualmente al programa
A continuación, entramos en DefaultVelocityRenderService.render()
Propósito del método
Recibe url + parámetros params.
Usa la plantilla Velocity (.vm) para renderizar el HTML incrustado (iframe, embed, …).
Determinación de la plantilla
Si params contiene _template → se usa esa plantilla.
Si no → se usa la predeterminada embed.vm.
Crea un contexto predeterminado con MacroUtils.defaultVelocityContext().
Coloca todos los parámetros de params en el contexto:
Si la clave es tweetHtml → se mantiene el HTML sin cambios.
De lo contrario → se codifica de forma segura con GeneralUtil.htmlEncode().
Agrega urlHtml, width, height al contexto (si están vacíos, se asignan valores predeterminados 400×300).

VelocityUtils.getRenderedTemplate()
VelocityUtilsgetRenderedTemplate y getRenderedTemplateWithoutSwallowingErrors()
getTemplate()
Aquí templateName es el _template mencionado anteriormente.
Después continúa llamando a VelocityEngine.Template()

VelocityEngine se continúa llamando a RunimeInstance.getTemplate()
RuntimeInstance (núcleo de Velocity)
Este es el “corazón” del motor Velocity. Se encarga de:
Inicializar el motor (init)
Gestionar la configuración, macros, analizador sintáctico, directivas, manejadores de eventos…
Y especialmente: gestionar los recursos a través de ResourceManager
→ Esto significa que RuntimeInstance no carga los recursos por sí mismo, sino que delega en resourceManager.
CompatibleVelocityResourceManager.getResource()
ConfigurableResourceManager (personalizado de Confluence)
Esta es una implementación de la interfaz ResourceManager.
Es responsable de:
Gestionar los cargadores de recursos (cargador de archivos, cargador de classpath, cargador de URL…).
Gestionar la globalCache (caché de plantillas según resourceKey).
Realizar la carga/actualización de plantillas (archivo .vm) cuando RuntimeInstance lo solicita.

try {
this.refreshResource(resource, encoding);
} catch (ResourceNotFoundException var7) {
this.globalCache.remove(resourceKey);
return this.getResource(resourceName, resourceType, encoding);
}