Demostración en vídeo de este post
La vulnerabilidad conocida como Spring4Shell ha aparecido hace algunas semanas y según su descripción, le permite a un atacante ejecutar código Java arbitrario en una aplicación que utilice alguna de las versiones afectadas de Spring Framework. Su CVE es el CVE-2022-22963 y tiene asignado un score de 9.8 y aunque ya se encuentra parcheada a partir de la versión 5.3.18 de Spring Framework (core) y la versión de 2.6.6 de Spring Boot, es probable que afecte a aplicaciones Java/J2EE que aún no han actualizado las dependencias de sus ficheros Gradle o POM. Lo más curioso de esta vulnerabilidad es que no es nueva, se trata de un bypass de las medidas de seguridad que se implementaron en su día para mitigar otra vulnerabilidad que apareció en el año 2010 con el identificador CVE-2010-1622.
Si tu aplicación utiliza un JDK igual o superior a la versión 9, en el classpath de la aplicación se encuentra la librería spring-beans*.jar y además, estás utilizando una versión Spring 5.3.0 – 5.3.17 o 5.2.0 – 5.2.20 es probablemente que tu aplicación sea vulnerable. La forma más rápida de comprobarlo es simplemente abrir el fichero spring-beans*.jar y verificar si se encuentra la clase CachedIntrospectionResults.class. Si la aplicación está en ejecución, se puede comprobar realizando una petición HTTP a uno de los endpoints disponibles en la aplicación, ya sea que se encuentre desarrollada con Spring MVC, WebFlux o Spring Rest, el comportamiento será el mismo si la aplicación es vulnerable. Dicha petición HTTP se enseña en la siguiente imagen.
Como se puede ver, en la URL se ha introducido el siguiente payload: ?class.module.classLoader.URLs%5B0%5D=0
En el caso de que la aplicación sea vulnerable, el servidor devolverá un HTTP 400, si la respuesta es un código de estado diferente lo más probable es que la aplicación no sea vulnerable o bien, exista algún tipo de filtro que este impidiendo la explotación, como por ejemplo un WAF capaz de detectar el patrón de ataque.
Otro payload que ayuda a verificar si la aplicación es vulnerable es el siguiente: ?class.module.classLoader.DefaultAssertionStatus=nothing
Nuevamente, si la aplicación es vulnerable, se podrá ver un error HTTP 400.
Ahora mismo hay múltiples pruebas de concepto disponibles en repositorios de GitHub. Probar la existencia de esta vulnerabilidad y su explotación no es una labor complicada, solo hace falta que la aplicación utilice alguna de las versiones vulnerables del framework y ejecutar peticiones HTTP que obliguen al cargador de clases de Java a ejecutar las instrucciones que se le indiquen, las cuales típicamente, incluirían la carga de la clase java.lang.Runtime y ejecución de los métodos getRuntime() y exec(). Una prueba de concepto interesante se encuentra disponible en el repositorio de reznok la cual cuenta con exploit en Python y una aplicación con Spring MVC simple para probar. La aplicación se encuentra dockerizada, por lo tanto basta con crear una imagen y un contenedor partiendo de dicha imagen para realizar las pruebas. A continuación, se puede ejecutar el fichero exploit.py indicando la URL donde se encuentra la aplicación y si todo va bien, se encargará de generar un fichero «shell.jsp» en la aplicación «ROOT» de Tomcat.
Como se ha mencionado anteriormente, para resolver este problema solo hace falta actualizar Spring Framework a una versión superior a la 5.3.17 y si se utiliza Spring Boot, actualizar a una versión superior a la 2.6.5. Es una vulnerabilidad critica, pero no significa que se desaconseje el uso de Spring Framework, de hecho, a diferencia de otras tecnologías, la comunidad de Spring lleva dos décadas de trabajo continuo y los defectos que se reportan, que no solamente son de seguridad, se suelen corregir al cabo de pocos días. Además, las actualizaciones, salvo en casos puntuales, no suelen presentar conflictos con las aplicaciones que utilizan una versión antigua, siempre y cuando sean de la misma rama. Como ya ha ocurrido con otra vulnerabilidad muy sonada en el mundo de Java/J2EE (log4shell), no hay que olvidar que muchos de los componentes que utilizamos en desarrollo de software son mantenidos por comunidades y voluntarios, lo que significa que se espera que este tipo de problemas se presenten con cierta frecuencia y lo mejor que se puede hacer es estar atento a los avisos de seguridad y parchear cuanto antes. Como siempre, es buena idea aportar a estos proyectos a través de donaciones o código, después de todo, son tecnologías que usamos casi a diario ya sea como usuarios finales o como desarrolladores.
Un saludo y Happy Hack!
Adastra.