
El robo de hash NTLMv2 es una técnica de recolección de credenciales muy conocida que se hizo posible gracias a la insistencia de Windows en autenticarse automáticamente en todo lo que pueda. Es una técnica básica utilizada en pruebas de penetración internas con herramientas como responder o ntlmrelayx , que explotan problemas como la habilitación de protocolos LLMNR/NBT-NS heredados o vulnerabilidades de autenticación forzada como PetitPotam. También se ha explotado a través de Internet, generalmente mediante el abuso de Microsoft Outlook, como se describe en casos recientes de Proofpoint y Microsoft .
Al auditar aplicaciones web, el robo de hash NTLMv2 es posible en hosts Windows mediante la explotación de vulnerabilidades de falsificación de solicitud del lado del servidor (SSRF) o entidades externas XML (XXE). Se ha escrito mucho sobre el tema y se siguen encontrando nuevas vulnerabilidades . En esta publicación, revelamos nuevas vulnerabilidades de SSRF que conducen a la divulgación de hash NTLMv2 en tres de los marcos de Python más populares: Gradio de Hugging Face, que impulsa varias herramientas de inteligencia artificial populares; Jupyter Server, que sustenta Jupyter Notebook y JupyterLab; y Streamlit de Snowflake.
Las vulnerabilidades que se revelan aquí se relacionan con la forma en que estos marcos de Python recuperan archivos. Específicamente, en Python, cualquier operación del sistema de archivos realizada en una entrada que no haya sido validada lo suficiente puede provocar la fuga de hashes NTLMv2. Las vulnerabilidades que se revelan aquí pueden ser explotadas por atacantes no autenticados, y han surgido en pruebas de penetración del mundo real realizadas por NodeZero. En el camino, también cubriremos un error interesante de Python que afecta a versiones anteriores de Python en Windows y que podría ayudar en el robo de hashes NTLMv2.
CVE-2024-34510: Divulgación de hash NTLMv2 en Gradio
Gradio es un popular marco de trabajo de aplicaciones web de código abierto de Python para desarrollar y compartir demostraciones de IA/ML. El pasado mes de diciembre, revelamos dos vulnerabilidades de recorrido de ruta, CVE-2023-51449 y CVE-2024-1561, que afectan a Gradio, y escribimos sobre nuestro trabajo posterior con Hugging Face para proteger su entorno Spaces . En el momento en que revelamos estas vulnerabilidades, también revelamos un par de problemas de divulgación de hash NTLMv2, que están cubiertos por CVE-2024-34510 .
Divulgación de hash NTLMv2 en el filepunto final
El punto final de la API de Gradio fileacepta una ruta para descargar un archivo dentro de un conjunto restringido de directorios en el sistema de archivos local. De forma predeterminada, este punto final es accesible para usuarios no autenticados. En versiones vulnerables de Gradio, el Path.is_dir()método se llama en esta ruta antes de validarlo por completo.
https://github.com/gradio-app/gradio/blob/gradio%404.4.0/gradio/routes.py#L447

Si Gradio se ejecuta en Windows y la ruta proporcionada por el usuario es una ruta UNC, Gradio intentará conectarse al servidor SMB en la ruta. Un atacante puede aprovechar esto utilizando herramientas como Responder para configurar un servidor SMB falso y capturar o retransmitir el hash NTLMv2 del usuario de Windows que ejecuta Gradio. En este ejemplo, Gradio se ejecuta en 10.0.220.53 y la IP del atacante donde se ejecuta Responder es 10.0.225.200.

Divulgación de hash NTLMv2 en los controladores de archivos estáticos de Gradio
¿Qué sucede si Gradio se configuró para requerir autenticación? Muchos puntos finales de Gradio en Internet tienen la autenticación habilitada. Encontramos otro vector para filtrar hashes NTLMv2 en los controladores de archivos estáticos de Gradio,
suponiendo que la versión de Python instalada en el host sea menor que 3.11.2 . Una solicitud GET a una URL del formato http://10.0.220.53:7860/static///10.0.225.200/shareactivará una devolución de llamada SMB desde el servidor Gradio en 10.0.220.53 a la IP del atacante 10.0.225.200.

Divulgación de hash NTLMv2 en los controladores de archivos estáticos de Gradio
¿Qué sucede si Gradio se configuró para requerir autenticación? Muchos puntos finales de Gradio en Internet tienen la autenticación habilitada. Encontramos otro vector para filtrar hashes NTLMv2 en los controladores de archivos estáticos de Gradio,
suponiendo que la versión de Python instalada en el host sea menor que 3.11.2 . Una solicitud GET a una URL del formato http://10.0.220.53:7860/static///10.0.225.200/shareactivará una devolución de llamada SMB desde el servidor Gradio en 10.0.220.53 a la IP del atacante 10.0.225.200.

El problema subyacente se puede rastrear hasta la implementación de Python os.path.isabsen Windows. Al recuperar archivos estáticos, Gradio realiza una operación safe_joinpara cargar archivos desde un directorio de confianza.
https://github.com/gradio-app/gradio/blob/gradio%404.4.0/gradio/routes.py#L836

En la línea 834, Gradio comprueba varias condiciones antes de realizar la operación del sistema de archivos os.path.isdiren la línea 839. Resulta que en las versiones de Python anteriores a la 3.11.2, os.path.isabsno informa las rutas UNC parciales de la forma //10.0.225.200/sharecomo rutas de archivo absolutas. Tenga en cuenta la sintaxis: esta ruta UNC parcial debe construirse con barras diagonales y no debe tener una barra diagonal final ni ningún otro elemento de ruta final. Al mismo tiempo, al realizar una os.path.join, Python trata esto como una ruta UNC parcial como una ruta absoluta. Esta inconsistencia entre os.path.isabsy os.path.joines un error. Esto da como resultado un escenario donde se cumplen todas las condiciones y os.path.isdirse ejecuta, lo que lleva a la divulgación del hash NTLMv2. (Si está interesado en profundizar, consulte los cambios en el ntpathmódulo Python en GitHub).
Comparación entre Python 3.10.6 y Python 3.11.2


Este escenario puede parecer un caso extremo, pero tenga en cuenta que el uso más popular de Gradio es la interfaz de usuario web de difusión estable , que, según sus instrucciones de instalación, requiere Python 3.10.6 cuando se ejecuta en Windows. Esta aplicación tiene más de 138 000 estrellas y se encuentra entre los 50 principales repositorios con estrellas de GitHub.
Herramienta safe_jointambién vulnerable
Gradio tomó prestado su código safe_joinde la popular biblioteca Werkzeug , y la safe_joinbiblioteca de Werkzeug tampoco es segura bajo esta condición: versión de Python < 3.11.2 en Windows.
https://github.com/pallets/werkzeug/blob/main/src/werkzeug/security.py#L131

Werkzeug safe_joinse utiliza como parte del popular marco web
Flask para servir archivos estáticos. Afortunadamente, en la configuración predeterminada de Werzkeug, no se pueden pasar múltiples barras diagonales consecutivas como parámetros de ruta. Sin embargo, una aplicación que se ejecute en Windows que acepte una ruta como parámetro de consulta o desde el cuerpo de la solicitud sería vulnerable, por ejemplo, algo como esto:
(Gradio utiliza uvicorn como su servidor web, que no fusiona barras y permite que se pasen rutas UNC parciales como parámetros de ruta).
Cronología
Notificamos tanto al equipo de seguridad de Python como al equipo de Werkzeug sobre los problemas relacionados con os.path.isabsy safe_join. Si bien reconocieron los problemas, no vieron ninguna razón para hacer un seguimiento adicional. La versión 4.20 de Gradio corrige por completo ambos problemas de divulgación de hash de NTLMv2.
- 14 de diciembre de 2023 : Se notificó al equipo de seguridad de Python por correo electrónico.
- 14 de diciembre de 2023 : Reconocimiento del equipo de seguridad de Python
- 17 de diciembre de 2023 : Informe inicial a Hugging Face por correo electrónico
- 18 de diciembre de 2023 : Hugging Face reconoce el problema
- 18 de diciembre de 2023 : Werkzeug fue notificado a través de un problema de seguridad en GitHub
- Dic. 19 de septiembre de 2023 : problema de reconocimiento de herramientas
- 5 de marzo de 2024 : Hugging Face lanza la versión 4.20 de Gradio con correcciones
- 5 de mayo de 2024 : se publicó CVE-2024-34510
CVE-2024-35178: Divulgación de hash NTLMv2 en Jupyter Server
Teníamos el presentimiento de que otras aplicaciones de Python podrían ser vulnerables a la divulgación del hash NTLMv2 y decidimos echar un vistazo a quizás la aplicación de Python más popular: Jupyter Notebook.

La aplicación Jupyter Notebook está alojada en Jupyter Server, que a su vez utiliza el servidor web Tornado . Para servir archivos estáticos, Jupyter Server implementa un controlador de archivos estáticos personalizado FileFindHandler que extiende el StaticFileHandler integrado de Tornado . Al servir un archivo, Jupyter Server ejecuta la función filefindpara determinar la ruta absoluta del archivo de entrada.

La llamada al sistema de archivos os.path.isfilese realiza antes de verificar que la ruta proporcionada por el usuario se encuentra dentro de un directorio restringido. Esto significa que, si Jupyter Notebook se ejecuta en Windows, un atacante puede filtrar el hash NTLMv2 del usuario de Windows que ejecuta Jupyter Notebook al proporcionar una ruta UNC. En el siguiente ejemplo, Jupyter Notebook se ejecuta en 10.0.220.6 y un atacante ejecuta Responder en 10.0.225.200:

Hemos verificado que esta vulnerabilidad también afecta a la versión clásica de Jupyter Notebook y JupyterLab.
Cronología
La vulnerabilidad, CVE-2024-35178 , afecta al jupyter_serverpaquete y se corrige en la versión 2.14.1 del paquete.
- 15 de mayo de 2024 : se planteó un problema de seguridad de GitHub contra el proyecto jupyter_server
- 15 de mayo de 2024 : el equipo del proyecto Jupyter reconoce el problema
- 6 de junio de 2024 : CVE-2024-35178 se publicó con un aviso de seguridad de GitHub
CVE-2024-42474: Divulgación de hash NTLMv2 en Streamlit
A continuación, echamos un vistazo a Streamlit , un popular marco de Python desarrollado por Snowflake para crear demostraciones de ciencia de datos y aprendizaje automático. Al igual que Jupyter Server, Streamlit también utiliza el servidor web Tornado y reemplaza el StaticFileHandler de Tornado con su propio controlador de archivos estáticos personalizado. Descubrimos que cuando el uso compartido de archivos estáticos está habilitado (no es el valor predeterminado) y Streamlit se ejecuta en Windows, un atacante podría explotar Streamlit para filtrar el hash NTLMv2 del usuario de Windows que ejecuta Streamlit.

El código vulnerable está en la AppStaticFileHandler.validate_absolute_pathfunción:

La llamada a os.path.isdirla línea 45 ocurre antes de la verificación en la línea 49 para garantizar que la ruta proporcionada por el usuario esté dentro de la carpeta estática esperada.
Cronología
Snowflake corrigió la vulnerabilidad, CVE-2024-42474 , en Streamlit versión 1.37.0.
El vector CVSS del aviso de seguridad de Snowflake indica que se requieren pocos privilegios para explotar esta vulnerabilidad. Esta evaluación no es precisa : los atacantes no autenticados pueden explotar esta vulnerabilidad.
- 12 de mayo de 2024 : Se revela una vulnerabilidad en Snowflake a través de HackerOne.
- 14 de mayo de 2024 : HackerOne valida el problema
- 6 de junio de 2024 : Snowflake valida el problema
- 25 de julio de 2024 : Snowflake publica la versión 1.37.0 con la corrección
- 12 de agosto de 2024 : CVE-2024-42474 se publicó con un aviso de seguridad de GitHub
Explotación del robo de credenciales NTLM
Hay dos formas bien conocidas de explotar la divulgación del hash NTLMv2:
- Descifrar el hash para revelar la contraseña de texto simple del usuario que ejecuta el servicio vulnerable.
- Retransmisión del hash a otro objetivo accesible desde la red. Según los privilegios del usuario víctima y la configuración del objetivo, es posible ejecutar código de forma remota en el host de destino.
En muchos casos de divulgación de hash NTLMv2, la aplicación web vulnerable se ejecuta como LocalSystemuna cuenta de computadora y el hash capturado es el de esta. Estas cuentas tienen contraseñas aleatorias largas y no es posible descifrarlas. Las vulnerabilidades reveladas aquí son más peligrosas porque las aplicaciones vulnerables suelen ser ejecutadas por usuarios finales que tienden a tener contraseñas descifrables. Una vez descifradas, un atacante puede intentar usar estas credenciales para iniciar sesión en cualquier servicio al que el usuario víctima pueda tener acceso.
Explotación desde el perímetro
Herramientas como Responder suelen estar asociadas con pruebas de penetración internas, pero las vulnerabilidades reveladas aquí pueden explotarse desde Internet, asumiendo que la red víctima no ha sido bloqueada para evitar el tráfico SMB saliente.
En este ejemplo, una versión vulnerable de Gradio que se ejecuta en Windows se expone a Internet mediante la función «compartir» de Gradio. Estas URL compartidas se publican ocasionalmente en las redes sociales cuando los usuarios quieren compartir sus demostraciones con el mundo. Un atacante puede explotar la instancia expuesta de Gradio para capturar el hash NTLMv2 del usuario que ejecuta Gradio.


Explotación indirecta desde el perímetro
Incluso si la aplicación vulnerable no está expuesta directamente a Internet, es posible explotarla indirectamente a través de vulnerabilidades SSRF o XXE que afecten a otros activos del perímetro. Esto es posible porque las vulnerabilidades reveladas en esta publicación se pueden explotar con simples solicitudes GET.
En este ejemplo, un servidor Keycloak en 54.83.90.245 es vulnerable a una SSRF ciega, CVE-2020-10770 , y está expuesto a Internet. Aprovechamos la SSRF ciega haciendo que Keycloak se vuelva a conectar a un servidor HTTP controlado por el atacante en 98.80.128.226.

A continuación, el servidor HTTP controlado por el atacante emite una redirección 302 dirigida a una instancia de un Jupyter Notebook vulnerable que se ejecuta en Windows con una IP interna 10.0.229.6. Tenga en cuenta que la URL de redirección codifica las barras dobles para evitar el comportamiento de Keycloak de combinar barras.

El servidor Keycloak sigue la redirección y envía una solicitud a la instancia de Jupyter Notebook. La instancia de Jupyter Notebook se conecta nuevamente a través de SMB al servidor del atacante que ejecuta el respondedor, filtrando el hash NTLMv2 del usuario que ejecuta Jupyter Notebook.

Las vulnerabilidades ciegas de SSRF son comunes y generalmente se consideran de gravedad moderada, pero es posible elevar su impacto encadenándolas a una de las vulnerabilidades reveladas aquí.
Acciones de reparación
Para los defensores, recomendamos las siguientes acciones:
- Si está ejecutando alguna de las aplicaciones vulnerables de esta publicación en Windows, actualice a la última versión: 4.20+ de Gradio, 2.14.1+ de Jupyter Server y 1.37.0+ de Streamlit
- Configure los firewalls de su host o red para bloquear el tráfico SMB que sale a Internet. Esta es una buena política para evitar la explotación de vulnerabilidades de autenticación forzada de Windows en general, como la vulnerabilidad de elevación de privilegios de Outlook CVE-2023-23397 que se encuentra en la lista de vulnerabilidades explotadas conocidas de CISA.
- Para aquellos que se preocupan por la seguridad, si tiene usuarios que ejecutan Python en Windows, actualice a la última versión de Python para no tener que pensar en el error que os.path.isabsafecta a las versiones de Python anteriores a 3.11.2.
Conclusión
Windows es el sistema operativo predominante en las empresas y Python es el lenguaje de elección para la IA. Con la gran popularidad de la IA en los últimos años, estamos viendo un aumento en el uso de aplicaciones Python en Windows. Esto conlleva un nuevo riesgo porque, tradicionalmente, las aplicaciones Python se han desarrollado y ejecutado en sistemas basados en Linux, donde los riesgos de seguridad son diferentes a los de Windows. Creemos que es probable que el problema específico del robo de hash NTLMv2 en las aplicaciones Python no se haya denunciado lo suficiente y que sea algo a lo que todas las partes (defensores, desarrolladores, profesionales de la seguridad de las aplicaciones, cazadores de errores, etc.) deberían estar atentos.
Fuente: traducido y tomado de horizon3.ai








