
Inyección de plantilla no autenticada en Atlassian Jira
4.4.x
5.x.x
6.x.x
7.0.x
7.1.x
7.2.x
7.3.x
7.4.x
7.5.x
7.6.x anteriores a 7.6.14 (versión corregida para 7.6.x)
7.7.x
7.8.x
7.9.x
7.10.x
7.11.x
7.12.x
7.13.x anteriores a 7.13.5 (versión corregida para 7.13.x)
8.0.x anteriores a 8.0.3 (versión corregida para 8.0.x)
8.1.x anteriores a 8.1.2 (versión corregida para 8.1.x)
8.2.x anteriores a 8.2.3 (versión corregida para 8.2.x)
set JVM_SUPPORT_RECOMMENDED_ARGS= en el archivo ./bin/setenv.bat (o similar con ./bin/setenv.sh en Linux) para poder ejecutar depuración remotaset JVM_SUPPORT_RECOMMENDED_ARGS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
Remote JVM Debug con los valores host y port como localhost:5005 y Command line arguments for remote JVM-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
Ejecutar el archivo ./bin/config.bat (o config.sh en Linux) y ajustar "Jira home" al directorio de jira home propio

Ejecutar el archivo ./bin/start-jira.bat (o ./bin/start-jira.sh en Linux). Verificar que la versión de Java, el puerto 8080 y el 5005 estén libres si no se ejecuta.
Seleccionamos modo private

En este paso, recuerden usar una dirección de correo que pueda recibir correos :)

Configurar y probar la conexión completamente

En http://localhost:8080/secure/admin/EditApplicationProperties!default.jspa activamos la función Contact Administrators Form

Solo anoto algunas notas importantes al construir, pueden consultar building jira from source
Después de leer el Advisory sabemos que este bug se encuentra en ContactAdministrators y SendBulkMail (este último lo omito porque requiere autenticación). Así que empiezo probando la función ContactAdministrators y capturo la solicitud

Veo que la solicitud va a /secure/ContactAdministrators.jspa, por lo que reviso el archivo ./atlassian-jira/WEB-INF/web.xml para ver a qué clase se redirige esta solicitud


Entonces la solicitud será procesada en JiraWebworkActionDispatcher, por lo que coloco un breakpoint en init y server en esta clase y ejecuto la depuración

Así el programa se detiene en la función server, tras rastrear un poco, el programa entra en ContactAdministrators.doExecute()

Luego pasa a send, aquí el programa lista las cuentas de administrador activas

Después el programa pasa a la función sendTo. Aquí vemos que el programa crea un MailQueueItem y lo añade a mailQueue.

El programa llama a EmailBuilder.withSubject. Aquí el string subject del correo (enviado por el atacante) se convierte de String a TemplateSources y se asigna al parámetro subjectTemplate de EmailBuilder.

En la función renderLater el programa crea un EmailRenderer y lo usa para crear un RenderingMailQueueItem

Desde aquí, al volver a la función ContactAdministrators.sendTo. Después de crear un MailQueueItem, el programa añade el item a mailQueue y luego vuelve a la función doExecute para redirigir. Si seguimos este flujo de depuración no podemos saltar a la parte donde el programa renderiza el correo, por lo que no podemos llegar al punto donde ocurre la inyección de plantilla. Entonces, ¿qué debo hacer para poder seguir el procesamiento del correo?
Veo que en EmailRenderer hay una función renderNow (el programa solo llama a renderLater). Supongo que cuando el correo en la cola es llamado para renderizar, también seguirá un flujo similar a renderNow, así que decido rastrear desde la función renderNow

Desde renderNow el programa llama a EmailRenderer.render(). Coloco un breakpoint aquí y vuelvo a enviar la solicitud para ver si el programa realmente llega hasta aquí

Por suerte, el programa sigue la dirección que supuse. Luego el programa llama a renderEmailSubject

Después el programa llama a DefaultVelocityTemplatingEngine.render(this.subjectTemplate)

Llega a DefaultVelocityTemplatingEngine.applying y DefaultVelocityTemplatingEngine.asPlainText

Continúa llamando a asPlainText(Writer writer)

Llega a toWriterImpl ya que writer que introduzco es un Fragment, por lo que el programa salta al else
private void toWriterImpl(Writer writer, boolean attachCartridge) throws IOException {
if (this.source instanceof File) {
File template = (File)this.source;
if (attachCartridge) {
this.context.attachEventCartridge(DefaultVelocityTemplatingEngine.this.createDefaultCartridge());
}