Problema 2857

CVE-2023-1177: LFI/RFI en MLflow
- LFI/RFI que conduce a la toma de control de la cuenta del sistema y de la nube
- Todos los CVE parcheados en 2.2.2
- Exploit y herramienta de escaneo lanzada
Una de las herramientas más populares en un sistema ML es MLflow (con más de 13 millones de descargas mensuales y en aumento) que se utiliza para administrar el ciclo de vida de aprendizaje automático de extremo a extremo. .
Protect AI probó la seguridad de MLflow y encontró una vulnerabilidad combinada de Inclusión de archivos locales/Inclusión de archivos remotos que puede conducir a la adquisición completa del sistema o del proveedor de la nube. Se insta a las organizaciones que ejecutan un servidor MLflow a actualizar a la última versión o al menos a la versión 2.2.2 inmediatamente. La versión 2.2.1 corrige CVE-2023-1177 y la versión 2.2.2 corrige CVE-2023-1176. En este blog, exploramos el impacto de esta vulnerabilidad, cómo detectarla y nuestro proceso para descubrir estos impactos críticos. Si está ejecutando MLflow, utilice nuestra herramienta gratuita que se proporciona en este blog y comience a parchear sus sistemas de inmediato. Aplicar parches a sus sistemas puede ser un desafío con sus herramientas tradicionales, ya que muchos sistemas automatizados de administración de parches no enumeran ni identifican MLflow y, si lo hacen, es posible que no realicen verificaciones de versión.
Es fundamental que actualice a la última versión de MLflow de inmediato, incluso si sus instancias no están en producción y solo se usan en entornos de desarrollo.
Impacto
La explotación de esta vulnerabilidad permite que un atacante remoto no autenticado lea cualquier archivo en el servidor al que pueda acceder el usuario que inició el servidor MLflow.
La ejecución remota de código se puede adquirir tomando las claves SSH privadas o las credenciales del proveedor de servicios en la nube del servidor MLflow. Esto permite que un atacante inicie sesión de forma remota en el servidor o en los recursos de la nube y ejecute la ejecución de código arbitrario con los permisos de las credenciales encontradas.
Detalles de vulnerabilidad
- No se requiere interacción del usuario
- No se requiere conocimiento previo del medio ambiente
- Todas las configuraciones personalizadas de MLflow son vulnerables, incluida la instalación lista para usar
- Todas las versiones de MLflow hasta 2.1.1 son vulnerables a LFI
- La herramienta de explotación funciona en todas las versiones de MLflow v1.12 - v2.1.1
- Todas las versiones de MLflow anteriores a v2.0 eran vulnerables a LFI a través del exploit más simple de:
http://<server:port>/get-artifact?path=../../../../. ./etc/passwd&run\_uuid=<ejecutar\_uuid
Los mantenedores de MLflow fueron extremadamente rápidos en responder a la divulgación responsable de esta vulnerabilidad con soluciones entregadas en solo unas semanas. Las versiones de MLflow posteriores a la 2.1.1 ya no son vulnerables.
Detección de vulnerabilidades
Para comprobar si su servidor MLflow es vulnerable, utilice nuestra herramienta gratuita CVE-2023-1177-scanner.
Nuestro Proceso de Descubrimiento
Comenzamos instalando MLflow, iniciando el proxy de interceptación BurpSuite para interceptar todas las llamadas a la API de MLflow, ejecutando un experimento para llenar MLflow con datos y luego iniciando el servidor de la interfaz de usuario para la exploración.
# Descargue la fuente de MLflow para obtener acceso a sus ejecuciones de ejemplo
clon de git https://github.com/mlflow/mlflow
# Crear e ingresar un nuevo directorio fuera del directorio mlflow/
mkdir mlflowui
cd mlflowui
# Copie el código de ejemplo de la fuente de MLflow en este nuevo directorio
cp -r ../mlflow/examples/sklearn_elasticnet_wine .
# Configure un entorno virtual para los requisitos de instalación
python3 -m venv venv
fuente venv/bin/activar
# Instalar mlflow en este entorno virtual
pip instalar mlflow pandas
# Ejecutar el experimento de ejemplo
ejecutar mlflow --env-manager=local sklearn_elasticnet_wine -P alfa=0.5
# Ejecute la interfaz de usuario para ver los detalles del experimento
interfaz de usuario mlflow --host 127.0.0.1:8000
Al crear experimentos, nos dio la opción de especificar un directorio donde almacenar los objetos. Esto parecía ser una ruta de archivo configurable como se ve a través del experimento de ejemplo que ejecutamos:
Esto inmediatamente llamó nuestra atención, ya que requeriría un filtrado perfectamente implementado para evitar la inclusión de archivos locales o sobrescrituras de archivos arbitrarios. Sin embargo, no puede ejecutar un experimento de MLflow de forma remota desde la interfaz de usuario. Dado que en realidad no sucede nada con la ubicación del artefacto cuando crea un experimento a través de la interfaz de usuario, aquí no hay consideraciones de seguridad. Luego continuamos la exploración haciendo clic en las ejecuciones de experimentos individuales.
Al hacer clic en el nombre de la ejecución como se ve en la imagen de arriba, nos llevó a los detalles de la ejecución del experimento donde pudimos ver los archivos involucrados en el experimento y descargarlos como se ve en la imagen de abajo.
En este caso, vimos un gran botón "Registrar modelo" en nuestros archivos de artefactos. Teníamos curiosidad.
No parecía ser nada particularmente interesante, ya que simplemente aparece un modal que le permite seleccionar un modelo y luego guarda los detalles de ese modelo como "Versión 1".
Pero, ¿qué estaba pasando bajo el capó? Revisamos BurpSuite.
Encontramos otra entrada de protocolo y ruta de archivo que no se nos mostró en la interfaz de usuario. Esto parecía sospechoso. Lo cambiamos manualmente a la clave SSH privada del usuario file:///Users/danmcinerney/.ssh/id_rsa. El acceso a este archivo le permitiría iniciar sesión de forma remota en la máquina host de MLflow como el usuario que inició el servidor de MLflow.
La nueva fuente se reflejó en la respuesta, lo que generalmente indica que se produjo un cambio en el lado del servidor. Con curiosidad por lo que esto logró, volvimos atrás y buscamos los detalles del modelo registrado. Nada en los artefactos de ejecución del experimento, nada interesante en los detalles del modelo o los detalles de la versión del modelo, tampoco. Parecía otro callejón sin salida similar a cómo descubrimos que podía señalar la ruta del artefacto del experimento a una ubicación arbitraria, pero la interfaz de usuario no le dio nada que ver con eso. Sin embargo, al revisar el registro de solicitudes y respuestas de BurpSuite, apareció algo interesante.
Un atacante ahora tendría acceso
Un error interno del servidor 500 en la llamada a la API get-artifact nos pareció sospechoso. La llamada a la API get-artifact fue de interés al principio de las pruebas de seguridad porque es la llamada que devuelve los datos del archivo del repositorio de artefactos. Es la forma de descargar el modelo de una ejecución de experimento, y descubrimos que estaba protegido con una función que evitaba las vulnerabilidades de inclusión de archivos locales, como se ve a continuación.
Habíamos pasado algún tiempo tratando de eludir esto sin éxito. La diferencia en esta llamada de obtener artefacto en particular es que no está tratando de obtener un archivo de una subcarpeta, sino que está accediendo directamente al nombre del archivo. Además, en realidad no es la misma llamada a la API. Aquí está la llamada API REST de obtención de artefacto documentada:
Y aquí está la llamada modelo-versión/obtener-artefacto comparable:
Las diferencias incluyen la ruta de URL, los parámetros y los valores. Claramente no es la misma llamada a la API.
Notamos que esta llamada API no está en la documentación. La diferencia clave es que busca directamente un nombre de archivo a través del parámetro de URL de la ruta en lugar de una ruta de archivo relativa en la llamada API legítima de obtención de artefactos.
Esto significa que la protección LFI está ausente porque no es necesario realizar un recorrido de directorio. Solo se necesita controlar la ubicación de la carpeta de origen. Unos pasos más arriba, intentamos modificar la ubicación de la ruta fuente de una solicitud API a file:///Users/danmcinerney/.ssh/id_rsa cuando creamos una nueva versión del modelo:
Lo que deberíamos haber hecho fue cambiar la ubicación de la fuente a una carpeta, no a un archivo. Corregimos eso.
Luego, reenviamos la llamada API REST no documentada encontrada y la señalamos a id_rsa, que es un archivo dentro de la ubicación fuente de la nueva versión del modelo y las claves SSH privadas que desbloquean la capacidad de iniciar sesión de forma remota en el servidor.
Con esta clave SSH recuperada, podemos obtener acceso de terminal al host que ejecuta el servidor MLflow. MLflow se configura con mayor frecuencia para usar un depósito S3 como almacén de artefactos. Si este es el caso, otro objetivo de gran valor en la máquina sería el archivo ~/.aws/credentials que, como se puede imaginar, almacena las credenciales de AWS.
Otros objetivos de alto valor podrían incluir archivos como configuraciones SQL del servidor web que contienen contraseñas de texto sin formato o /etc/shadow que contiene todos los hash de contraseñas de usuario que se pueden descifrar a través de una herramienta como hashcat.
Herramienta de explotación
Para ayudar a proteger sus sistemas, hemos creado una herramienta simple para sacar a la luz su vulnerabilidad potencial, denominada MLFIflow.py (M + LFI + flujo).
Instalación
clon de git https://github.com/protectai/Snaike-MLflow
cd Snaike-MLflow/MLFIflow
python3 -m venv mlfiflow
fuente mlfiflow/bin/activar
pip install -r requisitos.txt
Uso
De forma predeterminada, MLFIflow intentará leer /etc/passwd desde el servidor MLflow y usar los nombres de usuario encontrados para buscar claves SSH y archivos de credenciales en la nube.
python MLFIflow.py -s http://1.2.3.4:5000
Para especificar una lista de palabras personalizada de archivos para descargar, use el indicador -f:
python MLFIflow.py -s http://1.2.3.4:5000 -f /path/to/wordlist.txt
Más investigación
Siempre estamos interesados en escuchar y colaborar con otros investigadores de seguridad interesados en mantener seguro el campo de la IA. Si desea trabajar juntos para la investigación de seguridad de IA compensada, envíeme un correo electrónico a [dan@protectai.com] (mailto: dan@protectai.com).