前言
开源产品RCE年年有,今年特别多。很多同学可能都有过这样一种困惑,即面对完全未知或者不是很熟悉的的开源产品的RCE时,不知道该如何下手去分析。
本篇文章中,笔者将以最近的Spring Cloud GateWay RCE(CVE-2022-22947)漏洞举个栗子,分享当面对一个陌生的开源产品漏洞时如何快速定位问题,分析问题并找到修复方案
。
当然,笔者能力有限,如有纰漏,烦请各位同学不吝赐教。
漏洞分析
首先我们使用搜索引擎搜索CVE-2022-22947 Spring Cloud GateWay RCE
,尽量找到最开始的漏洞公告(https://tanzu.vmware.com/security/cve-2022-22947)。笔者在这里找到了最早的一篇公告公告中显示3.0.0 to 3.0.6
版本都是受影响的版本,那么意味着3.0.7
是修复版本。此时我们找到官方的代码仓库(https://github.com/spring-cloud/spring-cloud-gateway/tags),发现3.0.7是 17 days ago发布的。所以commit里面
17 days ago
对应的那次提交就是官方针对漏洞修复的提交。顺着这个思路我们找到了原作者针对漏洞修复的提交(https://github.com/spring-cloud/spring-cloud-gateway/commits/main),如下所示:
最核心的修复逻辑则存在于最近的这几次提交之中,如图所示:
环境搭建
一般来讲官方仓库中都有现成的demo
代码,我们拿来即可直接搭建使用,官方仓库中带有test
,demo
,sample
,example
字眼的文件夹即为官方提供的直接可以使用的案例。
比如spring-cloud-gateway
官方仓库提供了现成的测试demo(https://github.com/spring-cloud/spring-cloud-gateway/tree/main/spring-cloud-gateway-sample)
本次环境搭建以3.0.6版本(https://github.com/spring-cloud/spring-cloud-gateway/archive/refs/tags/v3.0.6.zip)为例来进行演示。
运行../spring-cloud-gateway-3.0.6/spring-cloud-gateway-sample
中的GatewaySampleApplication.java
文件,如下所示:此时环境已经已经搭建成功,直接访问
http://127.0.0.1:8888/actuator
如果出现以下所示说明服务已经搭建成功
漏洞调试
本次RCE主要问题出现在 Actuator API
处。从官方的代码推送(https://github.com/spring-cloud/spring-cloud-gateway/tree/main/spring-cloud-gateway-server/src/main/java/org/springframework/cloud/gateway/actuate)记录上可以看到本次修复的方法也非常简单粗暴:直接将 gateway actuator状态设置成关闭
,这个修复方法是不是似曾相识?(和前段时间log4j2的官方修复方法如出一辙)
POC可以参考vulhub(https://github.com/vulhub/vulhub/blob/master/spring/CVE-2022-22947/README.zh-cn.md)这里不再赘述,POC成功执行说明目前测试的版本是存在漏洞的要调试代码,第一步需要打断点,笔者在第一个有效断点上也花了一些功夫,经过这一番折腾发现这其实也是有经验可循的。
我这里作一下总结希望能给那些想亲自调试的同学提供一些思路。
(1)首先肯定仔细对比一下官方仓库代码中哪几个文件被改动的最多
,改动最多的文件大概率就是造成漏洞的地方,在这些文件里下断点则很有可能捕获到前端的请求。(2)善用IDE寻找函数调用和被调用的链路
经过一番寻找最终在../spring-cloud-gateway-server/3.0.6/spring-cloud-gateway-server-3.0.6.jar!/org/springframework/cloud/gateway/route/RouteDefinitionRouteLocator.class:131
找到了第一个有效断点,并且在前端请求POST /actuator/gateway/refresh HTTP/1.1
时后端断点捕获到了请求如下所示:
在找到第一个有效断点之后接下来的工作就很轻松了。我们只需要跟着断点一步一步分析后台程序是如何处理前端用户传入的参数,顺着这个思路我们也就能慢慢揭开此次RCE的根本原因
了。
经过一番跟进我们发现后台程序在org.springframework.cloud.gateway.support.getValue:40
处判断用户传入的参数是否是以“#{”开头,以“}”为结尾,如果满足条件则进入循环,看到这里各位同学是不是就明白了为什么POC是以"#{}"这种格式构造了。继续跟进发现只要程序进入了这个循环就会解释SpEL(Spring Expression Language )从而造成RCE,我们在
org.springframework.expression.spel.standard.getValue:180
发现了系统对SpEL的执行结果如下所示
至此链路大概就很清晰了,攻击者按照"#{}"这种格式的POC,创建Actuator的路由,此时后台系统判断逻辑是否满足SpEL解析条件,满足则直接解析并将结果保存在
result
里面。这里即为此次RCE形成的根本原因。
细心的同学可能注意到了,最近披露出来针对该漏洞的POC大同小异,但是还是有一点细微差别的,比如有的POC使用的是AddResponseHeader
然而有的POC使用的是
RewritePath
这是为什么呢?我们重新再调试一次代码去一探究竟,在
org.springframework.cloud.gateway.route.loadGatewayFilters:106
处我们发现我们创建的两个filter都是在gatewayFilterFactories
之中。那是不是意味着gatewayFilterFactories
中的28个filter都是可以用来构造POC的?我们可以动手实践一下:此时我分别使用
AddRequestHeader
和SetStatus
来试验一下。经过尝试之后发现并不是所有的filter也都可以用作构造POC。下面是使用AddRequestHeader
构造POC并成功执行命令的截图使用
SetStatus
构造POC则会直接404原因是后台
没有创建成功
至此,我们对该漏洞的整个链路应该已经有了一个非常清晰的认识。
0x06后言
本文中用到的所有代码已经上传到GitHub(https://github.com/ba1ma0/Spring-Cloud-GateWay-CVE-2022-22947-demon-code)我已经将断点信息保存方便读者直接下载调试~
作者能力有限,文章若有纰漏请读者不吝赐教。WeChat:5ed0c42e63c9c2145990351ccaec4da5
漏洞悬赏计划:涂鸦智能安全响应中心(https://src.tuya.com) 欢迎白帽子来探索。
招聘内推计划:涵盖安全开发、安全测试、代码审计、安全合规等所有方面的岗位,简历投递[email protected],请注明来源。
- END -
原文始发于微信公众号(涂鸦安全应急响应中心):如何从零开始分析调试开源软件RCE?
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论