
Template-Injection in E-Mail-Vorlagen führt zur Codeausführung auf dem Jira Service Management Server
Template-Injection in E-Mail-Vorlagen führt zur Codeausführung auf Jira Service Management Server
Ich habe das Deployment + Debugging hier beschrieben, ihr könnt es dort nachschlagen.
In der Beschreibung dieser CVE wird klar gesagt, dass der Bug in der Funktion Email Template liegt. Mit Admin-Rechten kann der Benutzer die Vorlagen der Benachrichtigungs-E-Mails beliebig ändern. Dieser Bug erfordert Admin-Rechte, ist also trotz RCE nicht besonders kritisch, aber ich habe beschlossen, den Blog einfach zum Spaß zu schreiben :) wer sich mit SSTI beschäftigt, kann es sich ansehen.
atlassian-jira-servicedesk-4.17.0-m0006-standalone deployed und per Diff versucht herauszufinden, was sich gegenüber der Version 4.18.0 geändert hat:

Als ich diesen Haufen sah, ... natürlich habe ich nicht jede Datei einzeln gelesen, ich bin zu faul. Spaß beiseite, abgesehen vom zusätzlichen Security-Fix enthalten die Versionen auch Upgrades und Änderungen an Funktionen. Alles zu diffen und dann durchzulesen ist sehr zeitaufwändig. In einigen Fällen muss ich das wohl tun, aber in diesem Fall habe ich es nicht gemacht =)))
SendBulkMail, um eine Benachrichtigungs-E-Mail zu erzeugen. Auf den Stack Call dieses Endpoints möchte ich nicht näher eingehen, um es kurz zu halten, da er ähnlich zum Stack Call in CVE-2019-11581 ist.In der Funktion SimpleNote.render kann ich die Kontextvariable ansehen, um zu sehen, was ich ausnutzen kann:
Nach meiner eigenen Erfahrung achte ich darauf, Kontexte/Klassen mit Schlüsselwörtern wie: Utils, Manager, service, ... zu überprüfen. Mir ist aufgefallen, dass der Kontext $jirautils (Klasse com.atlassian.jira.util.JiraUtils) eine Methode public static <T> T loadComponent(String className, Class<?> callingClass) enthält:
Ich habe die Doku durchforstet, um zu sehen, was sie tut und wie sie verwendet wird, denn die Eingabe ist ein String className und die Ausgabe ist eine Klasse, also könnte diese Methode möglicherweise beliebige Klassen laden:
Ich gehe zu System -> Email templates und lade die aktuelle Template-Datei herunter
Es gibt viele verschiedene Vorlagen, jede für eine andere Art von Benachrichtigung, also habe ich nach einer Datei gesucht, die für viele verschiedene Benachrichtigungsarten gemeinsam verwendet werden kann, z. B. email\html\includes\header.vm
Nachdem ich die bearbeitete Template-Datei hochgeladen und mit SendBulkMail eine Benachrichtigungs-E-Mail gesendet hatte, erhielt ich in der E-Mail folgende Ausgabe:
Im Grunde hat diese Klasse keine Konstruktoren oder wird nicht akzeptiert. Ich habe es mit einer anderen Klasse versucht, die Konstruktoren hat (Konstruktoren ohne Eingabe):
Und das Ergebnis war wie erwartet. Ich konnte die Klasse erfolgreich abrufen:
Wir sehen, dass 3 Klassen zur Blacklist hinzugefügt wurden:
org.springframework.expression.spel.standard.SpelExpressionParser,\
com.atlassian.jira.component.ComponentAccessor,\
com.atlassian.jira.plugin.ComponentClassManager
Als ich die einzelnen Klassen geprüft habe, stellte ich fest, dass die Klasse SpelExpressionParser eine Funktion public SpelExpression parseRaw(String expressionString) hat. Nach kurzer Google-Recherche zur Verwendung sieht es ungefähr so aus:
#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser',$i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('calc')")
Wie ihr seht, gibt die Funktion parseRaw ein Objekt der Klasse org.springframework.expression.spel.standard.SpelExpression zurück, rendert den übergebenen Ausdruck aber noch nicht wirklich. Ich bin in die Klasse SpelExpression gesprungen und habe die Methode getValue gefunden:
@Nullable
public Object getValue() throws EvaluationException {
CompiledExpression compiledAst = this.compiledAst;
if (compiledAst != null) {
try {
EvaluationContext context = this.getEvaluationContext();
return compiledAst.getValue(context.getRootObject().getValue(), context);
} catch (Throwable var4) {
if (this.configuration.getCompilerMode() != SpelCompilerMode.MIXED) {
throw new SpelEvaluationException(var4, SpelMessage.EXCEPTION_RUNNING_COMPILED_EXPRESSION, new Object[0]);
}
}
this.compiledAst = null;
this.interpretedCount.set(0);
}
ExpressionState expressionState = new ExpressionState(this.getEvaluationContext(), this.configuration);
Object result = this.ast.getValue(expressionState);
this.checkCompile(expressionState);
return result;
}
Beim Blick auf Input/Output habe ich als jemand, der auf sein Bauchgefühl vertraut, beschlossen, es einfach auszuprobieren, statt weiter in die Doku zu schauen:
#set($SpelExpressionParser = $jirautils.loadComponent('org.springframework.expression.spel.standard.SpelExpressionParser',$i18n.getClass()))
$SpelExpressionParser.parseRaw("T(java.lang.Runtime).getRuntime().exec('calc')").getValue()
und das Ergebnis:
Damit konnten wir die Sandbox von Velocity umgehen und RCE erreichen. Wenn ich mich jedoch in die Lage des Autors versetze – der Person, die diesen Bug entdeckt hat – gibt es noch viele Fragen, die ich nicht beantworten kann:
Als ich diese 3 Klassen untersuchte, sah ich, dass sie eine Kette bilden können:
ComponentAccessor.getComponentClassManager()
=> ComponentClassManager.newInstance(String className) (Class này có thể load class tùy ý)
=> SpelExpressionParser
Wenn der Autor wie ich $jirautils verwendet, bräuchte er die anderen beiden Klassen nicht. Aber wenn der Autor $jirautils nicht verwendet, wie kommt er dann an ComponentAccessor???