Entiende como funciona la vulnerabilidad y cómo puedes protegerte
– Escrito por Bastian Muhlhauser
Recientemente, en los grupos y comunidades de seguridad ofensiva, se ha popularizado el término Spring4Shell. Esto, por lo crítico que es aplicar las medidas contra la vulnerabilidad y del riesgo que significa. Pero, ¿por qué debemos preocuparnos de Spring4Shell?
Spring4Shell es el nombre que recibió una vulnerabilidad crítica identificada como CVE-2022-22965. Esta vulnerabilidad permite la ejecución de código remoto (RCE) y afecta las versiones 5.3.0 a 5.3.17, 5.2.0 a 5.2.19 y, versiones posteriores de Spring Framework (Java), un framework que se utiliza generalmente para desarrollar aplicaciones y servicios web.
Hackmetrix Insight: RCE corresponde a las siglas de Remote Code Execution ó Ejecución Remota de Código. Cuyo significado se aplica para definir las vulnerabilidades que permitan a un agente externo ejecutar código arbitrario o comandos de sistema operativo.
A continuación, te contamos nuestro análisis sobre la vulnerabilidad, cómo detectarla y cómo corregirla o mitigarla, en caso de que exista en tus implementaciones de Spring Framework.
La vulnerabilidad
Spring4Shell se identifica como CVE-2022-22965, y es considerada una vulnerabilidad de alto impacto. Spring4Shell, permite la ejecución de código remoto en aplicaciones Spring MVC o Spring WebFlux que se ejecuten en JDK9+ a través del enlace de datos o data binding.
Hackmetrix Insight: Common Vulnerabilities and Exposures (CVE) es un sistema creado por Mitre que proporciona un método para compartir e identificar públicamente información sobre vulnerabilidades de seguridad informática.
Este hallazgo fue detectado y reportado inicialmente a VMware por los investigadores independientes conocidos codeplutos y meizjm3i, el martes 29 de marzo de 2022.
Como te darás cuenta, es bastante reciente, pero antes de la asignación de un identificador CVE por parte de Mitre, los detalles completos de la vulnerabilidad fueron expuestos de manera pública en internet el día 29 de marzo de 2022 por p1n93r .
Hackmetrix Insight: The Mitre Corporation es una organización estadounidense sin fines de lucro que administra centros de investigación y desarrollo financiados con fondos federales (FFRDC) que brindan apoyo a varias agencias gubernamentales de EE. UU. en los campos de aviación, defensa, atención médica, seguridad nacional,ciberseguridad, entre otros.
Este issue se origina por la forma en que el cuerpo de una solicitud HTTP es convertido a un objeto java donde se valida la presencia de ciertas propiedades que podrían complementar las de un objeto de una determinada clase.
De esta manera, antes de validar si las propiedades corresponden a las propiedades de un objeto de una clase personalizada, las propiedades que vengan desde las solicitud HTTP son pasadas a un objeto java base o POJO.
Hackmetrix Insight: Un POJO o Plain Old Java Object, es el nombre que reciben los objetos Java de clases simples o clases base, que no dependen de otros frameworks o clases personalizadas.
El comportamiento mencionado anteriormente, permite instanciar un objeto java (POJO) que contenga las propiedades de otros objetos o de sus objetos predecesores.
Por ejemplo, en el exploit público de la vulnerabilidad, se accede al ClassLoader, el cual es responsable de cargar dinámicamente las clases en la máquina virtual de Java o JVM del servidor Apache Tomcat.
Acto seguido, se accede a los objetos de clase Valve que corresponden al objeto Logger/Standard Access Log Valve, encargado de generar y almacenar los logs de la aplicación en el sistema de archivos.
Hackmetrix Insight: Standard Access Log Valve crea archivos de registro en el mismo formato que los creados por los servidores web estándar. Estos registros se pueden analizar posteriormente mediante herramientas de análisis de registros estándar para realizar un seguimiento de los recuentos de visitas a la página, la actividad de la sesión del usuario, etc.
Hallazgos
Basado en lo anterior, si desglosamos cada una de las líneas del payload utilizado en el exploit podemos afirmar lo siguiente:
La primera línea del payload utilizado, corresponde al contenido o patrón con que se generan los logs en Apache Tomcat cuyo valor por defecto corresponde al siguiente:
%h %l %u %t “%r” %s %b
Cada uno de los valores se describen a continuación:
- %h – Nombre de host remoto (o dirección IP si el atributo resolveHosts se establece en falso; de forma predeterminada, el valor es falso).
- %l – Nombre de usuario lógico remoto; siempre es un guión (-).
- %u – Usuario remoto que ha sido autenticado.
- %t – Fecha y hora en formato de archivo de registro común.
- %r – La primera línea de la solicitud. Por ejemplo, “GET / HTTP/1.1” (tenga en cuenta que esto está configurado para mostrarse entre comillas (“”)).
- %s – El código de estado HTTP de la respuesta.
- %b – El conteo de bytes enviados, excluyendo los encabezados HTTP, y muestra un guión (-) si es cero.
En el exploit la línea con que se modifica el patrón del Standard Access Log Valve corresponde a la siguiente:
class.module.classLoader.resources.context.parent.pipeline.first.pattern=
El patrón con el que quedaría el Standard Access Log Valve corresponderá al que se muestra a continuación:
Se puede observar en la imagen anterior que no existe ningún patrón para generar los logs según las solicitudes HTTP. Más bien, lo que se hace acá es que cada vez que se escriba algo al archivo con el que está configurado el Standard Access Log Valve, será el código que se muestra en la imagen anterior.
Aunque también se puede observar que existen dos patrones que se inyectan al principio y al final %{xxx}i, y que según la documentación de Apache Tomcat corresponde a los valores que existen por ejemplo en las cabeceras HTTP xxx, o en este caso las cabeceras c2 y suffix y que si no existen, o están vacías, sus valores por defecto serán un guión (-).
Esto se puede observar en el contenido del archivo tomcatwar.jsp que se genera al ejecutar el exploit.
Hackmetrix Insight: Apache Tomcat es un popular servidor web de código abierto y contenedor Servlet para código Java.
Otra de las propiedades que se modifican del Standard Access Log Valve,es la propiedad suffix. La cual establece un sufijo para los archivos que se escribirán en el sistema de archivos donde se almacenarán los logs (el valor por defecto es .txt). yEn el exploit se utiliza la siguiente línea para modificarlo para que los archivos que se escriban sean con extensión .jsp, lo que es muy conveniente si se quiere que el archivo se interprete por la JVM o para una webshell:
class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp
Hackmetrix Insight: Se define como webshell a todo código arbitrario cargado junto a una aplicación web, o en el contexto de una aplicación web, que permita a un agente malicioso realizar acciones arbitrarias al comportamiento normal de la aplicación e incluso ejecutar comandos de sistema operativo en el servidor que aloja la aplicación web.
Una propiedad, que de igual manera es modificada, es la que más llama la atención, ya que permite modificar el directorio donde se escribirán y almacenarán los archivos de logs en el sistema de archivos. Su valor por defecto es CATALINA_HOME/logs, en el exploit se utiliza la ruta webapps/ROOT para indicarle al Standard Access Log Valve que escriba los archivos de log o, en este caso, el archivo .jsp en la ruta /<ruta-de-instalacion-de-apache-tomcat/webapps/ROOT/.
Esto permitirá acceder a este archivo JSP a través de la URL http://<ip-tomcat>/<nombre-archivo>.jsp. Para lograr lo anterior, se utiliza la siguiente propiedad:
class.module.classLoader.resources.context.parent.pipeline.first.directory=
La propiedad prefix permite definir el nombre del archivo donde se escribirán los logs, su valor por defecto es localhost_access_log. En el exploit se utiliza la siguiente línea para definir que el nombre del archivo sea tomcatwar:
class.module.classLoader.resources.context.parent.pipeline.first.prefix=
Como se puede observar, las propiedades se pueden modificar al instanciar un POJO de tipo Class. Desde ahí se acceden y modifican las propiedades de otros objetos, como el class loader, entre otros.
Más adelante, en el análisis, se describen las particularidades que se descubrieron en la explotación de esta vulnerabilidad.
Cómo saber si soy vulnerable
Según los mantenedores de Spring los requerimientos específicos para que se pueda explotar esta vulnerabilidad son los siguientes:
- Que la aplicación se ejecute en un ambiente con JDK versión 9 o superior
- Que la aplicación se utilice Apache Tomcat como contenedor y servidor web
- Que la aplicación haya sido empaquetada como un paquete tradicional WAR y cargada en una instancia de Apache Tomcat
- Que la aplicación dependa utilice las dependencias spring-webmvc o spring-webflux
- Que la aplicación implemente las versiones 5.3.0 a 5.3.17, 5.2.0 a 5.2.19 y versiones posteriores de Spring Framework
Cómo ven para poder explotar esta vulnerabilidad hay que tener un escenario específico, pero no se ha descartado que en otros escenarios también sea posible lograr la explotación exitosa de esta falencia.
El equipo de AppSec de Hackmetrix continúa evaluando e investigando otros escenarios donde sería posible lograr la explotación de la vulnerabilidad, como por ejemplo en distribuciones de aplicaciones JAR ejecutables de Spring Boot, en servidores GlassFish, etc.
Probablemente esta publicación sufra varias modificaciones según nuestro equipo vaya descubriendo nuevos escenarios o nuevas formas de explotar esta vulnerabilidad.
Análisis
Para comenzar, y según los requisitos de un escenario ideal para poder explotar la vulnerabilidad, es necesario tener definido un RequestMapping cuya función reciba al menos un objeto de cualquier clase mediante parámetro para que el cuerpo de la solicitud HTTP pueda ser bindeado o parseado al objeto recibido por parámetro:
Para detectar si nuestra aplicación web es vulnerable, basta con enviar un parámetro o nombre de parámetro, con un valor inválido o de tipo incorrecto, y generar un error (HTTP Status code: 500). En este caso se utilizó el valor class[0] para que al tratar de bindear, dicho valor genere un error, ya que el POJO inicial no contiene un Array de clases en su base, sino más bien es de tipo com.hackmetrix.spring4shellpoc.User.
La siguiente imagen muestra el stack trace del error en la aplicación:
El mensaje de error general es el siguiente:
Property referenced in indexed property path ‘class[0]’ is neither an array nor a List nor a Map; returned value was [class com.hackmetrix.spring4shellpoc.User]
Hackmetrix Insight: Un stack trace o seguimiento de pila, es un informe que proporciona información sobre las subrutinas del programa. Se usa comúnmente para ciertos tipos de depuración, donde un seguimiento de pila puede ayudar a los ingenieros de software a descubrir dónde se encuentra un problema, o cómo varias subrutinas funcionan juntas durante la ejecución.
Al enviar una solicitud HTTP es posible observar que se instancia un objeto de tipo User, según la definición de la función que recibe por parámetro un objeto de este tipo:
Tenemos que la clase User está definida de la siguiente forma:
Al enviar una solicitud HTTP que contenga algún parámetro que haga match con las propiedades de la clase, gracias al data binding, el valor de dicho parámetro será puesto en la propiedad que corresponda:
Hackmetrix Insight: El Data Binding o enlace de datos de manera general se refiere a un mecanismo que enlaza los elementos de la interfaz de usuario con la parte en la que se arma la información a mostrar. En pocas palabras, es el enlace entre el frontend y el backend de nuestra web. En este contexto se aplica para explicar el proceso que vincula los datos ingresados por el usuario en las solicitudes HTTP y los objetos Java que están cargados en memoria en el servidor web.
En la siguiente imagen se puede observar el data binding ocurriendo antes de llegar a la línea de return:
Este data binding ocurre en la clase BeanWrapperImpl en la función getLocalPropertyHandler:
Se puede observar que se cargan de igual manera los getters y setters de las propiedades según la clase (writeMethod, readMethod). Posteriormente, se ejecuta la función processLocalProperty (AbstractPropertyAccessor.java); la cual convierte la propiedad recibida y su valor a un POJO.
Hackmetrix Insight: Las funciones getters y setters hacen referencia a las funciones encargadas de modificar o disponer la información de una propiedad en específico para una determinada clase u objeto.
De la ejecución de esta función se obtiene un ArrayList que contiene el listado de propiedades y valores obtenidos desde la solicitud HTTP
Hackmetrix Insight: ArrayList corresponde a un tipo de dato en programación que hace referencia a las llamadas listas ordenadas y/o pilas, que pueden contener 0 o más elementos.
Estas propiedades se aplican al objeto User con la función applyPropertyValues en DataBinder.class
Esto se puede observar al mirar los detalles del objeto ExtendedServletRequestDataBinder. Este objeto almacena los resultados del data binding y los pasa a la función que se ejecuta en el RequestMapping. Aquí podemos observar que el valor de la propiedad username del objeto User, ya ha sido modificado por el ingresado desde la solicitud HTTP:
Hackmetrix Insight: RequestMapping se describe como una anotación a nivel programática utilizada para asignar solicitudes web a funciones específicas en clases de manejo de solicitudes HTTP.
Ahora enviamos en el cuerpo de la solicitud HTTP una propiedad llamada class, en este caso class[0] (para que genere un error):
Hackmetrix Insight: El parsing, en informática, es donde la información se separa en sub componentes más fáciles de procesar, que se analizan para determinar la sintaxis correcta y luego se adjuntan a las etiquetas o propiedades que definen cada componente.
Cuando se haga el parse de la propiedad podremos observar que se accede al método getClass:
También al analizar el tipo de dato al que se transformó (parsing) la propiedad, podemos ver que corresponde a un objeto de tipo java.lang.Class:
Esto ya indica que se está accediendo directamente a la clase del objeto y no a las propiedades definidas. Como cada clase definida por el desarrollador hereda las propiedades y métodos de la clase java.lang.Class, se pueden acceder a ciertas propiedades que permitirían acceder a superclases u objetos de clases con propiedades críticas según sea el contexto en el que se ejecuta la aplicación web.
Por ejemplo, se envía la siguiente solicitud HTTP:
Al parsear la solicitud, Spring primero se hace cargo de la parte class:
Luego de procesar la propiedad “padre”, por decirlo de alguna manera, procede con el subcomponente de esta, en este caso module:
En el análisis del POJO obtenido con el parsing de la propiedad class, se puede apreciar que se han cargado alrededor de 46 propiedades:
Dichas propiedades pueden ser modificadas y accedidas desde la solicitud HTTP:
Éste análisis se realizó sobre un aplicación empaquetada en un archivo JAR, y fuera de un servidor Apache Tomcat.
Así confirmamos que la vulnerabilidad también afecta a este tipo de implementaciones.Aunque es en teoría posible lograr un RCE, es necesario continuar investigando al respecto.
Otros Vectores
En el análisis a la versión WAR de la aplicación y ejecutándose en un contexto de un Apache Tomcat, se descubrieron nuevos vectores de ataque que permite la explotación de esta vulnerabilidad
Hackmetrix Insight: En ingeniería de software, un archivo WAR (Web Application Resource o Web application ARchive) es un archivo que se utiliza para distribuir una colección de archivos JAR, JavaServer Pages, Java Servlets, clases Java, archivos XML, bibliotecas de etiquetas, páginas web estáticas (HTML y archivos relacionados) y otros recursos que juntos constituyen una aplicación web.
BLIND SERVER SIDE REQUEST FORGERY (SSRF)
Es posible modificar el archivo de configuración de la aplicación (web.xml) para que apunte a otra URL, esta puede ser local o remota, nosotros apuntamos el archivo a un servidor remoto para ver si recibíamos alguna interacción:
Luego de modificar la URL del archivo de configuración, se debe llamar al content de dicho archivo como se muestra en la siguiente imagen:
Después de enviar la solicitud anterior, se pudo evidenciar que efectivamente la aplicación interactuó con nuestro servidor remoto.
Este hallazgo puede ser escalado a un XXE si se desactiva la protección contra entidades externas, ya que al llamar al content del archivo de configuración, Tomcat tratará de parsear su contenido.
Hackmetrix Insight: La falsificación de solicitudes del lado del servidor (también conocida como SSRF) es una vulnerabilidad de seguridad web que permite a un atacante inducir a la aplicación del lado del servidor a realizar solicitudes a una ubicación arbitraria.
Internal Information Disclosure
Si el servidor no tiene una configuración donde se oculten los stack traces o mensajes de error, es posible enumerar los paquetes que han sido cargados en el contexto de la aplicación:
También es posible obtener el hostname de la máquina que ejecuta la aplicación web:
De igual manera se puede obtener el nombre de la clase actual donde se está realizando la inyección de propiedades:
Se puede obtener también, un Full Path Disclosure al llamar a propiedades de Tomcat cómo CATALINA_BASE .
Modify CORS
El equipo de AppSec detect que es posible deshabilitar o modificar la configuración CORS del servidor Tomcat:
Esto se obtuvo al revisar la configuración de la clase AuthenticatorBase:
Disable XML External Entity (XXE) Protections
Al modificar la propiedad XmlBlockExternal, se pueden desactivar las protecciones que por defecto tiene Tomcat para las entidades externas, volviendo la aplicación vulnerable a ataques XXE.
Hackmetrix Insight: La inyección de entidad externa XML (también conocida como XXE), es una vulnerabilidad de seguridad web que permite a un atacante interferir con el procesamiento de datos XML de una aplicación. A menudo, permite que un atacante vea archivos en el sistema de archivos del servidor de aplicaciones e interactúe con cualquier sistema externo o de back-end al que pueda acceder la propia aplicación.
La imagen anterior muestra las funciones y propiedades obtenidas desde la documentación oficial de Apache Tomcat.
Contramedidas
La mejor solución es actualizar a Spring Framework 5.3.18 y 5.2.20 o superior. Si ya hiciste esto, no se necesitan soluciones alternativas.
También es recomendable actualizar Tomcat. Para versiones anteriores de Spring Framework no compatibles, la actualización a Apache Tomcat 10.0.20, 9.0.62 o 8.5.78 proporciona la protección adecuada.
Sin embargo, esto debe verse como una solución táctica, y el objetivo principal debe ser actualizar a una versión de Spring Framework actualmente compatible lo antes posible. Si adoptas este enfoque, deberías considerar configurar campos no permitidos, también para el enfoque de defensa en profundidad.
Si quieres conocer otras medidas de remediación a parte de las que mencionamos aquí, te sugerimos visitar el sitio oficial del equipo de Spring, donde explican cómo mitigar la vulnerabilidad.
Conclusión
Spring4Shell es una vulnerabilidad cuyo impacto general puede variar según sea el escenario o contexto en el que se ejecuta una aplicación. Sin embargo, se origina por un error bastante común en el desarrollo de software, cuando no se valida y sanitiza apropiadamente la información ingresada por los usuarios.
Para evitar vulberabilidades como esta, te invitamos a leer sobre las buenas prácticas que se deben tener en cuenta en el desarrollo de software.
Referencias
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-22965
- https://tomcat.apache.org/tomcat-8.5- doc/api//org/apache/catalina/core/StandardContext.html
- https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement