要想分析首先要了解什么是Spring HTTP Invoker,HttpInvoker是基于HTTP之上提供RPC,同时又使用了Java的对象序列化机制,实现了穿透防火墙或多系统之间的通信。
具体的实现过程很复杂,我们不用太深入的去了解,只需要知道HttpInvoker主要是使用http协议通过传输序列化数据来实现通信,一旦传输序列化数据,如果使用不当就会产生反序列化漏洞。
漏洞版本:spring-web<6.0版本中
漏洞发生在,HttpInvokerServiceExporter和RemoteInvocationSerializingExporter中,序列化数据未进行检测,当传输恶意序列化数据的时候,反序列化中就会执行恶意代码。
首先查看漏洞的存在位置,这里可以看到执行的栈关系:
调用层级如下所示,首先通过handleRequest接收发送来的数据,然后调用readRemoteInvocation,createObjectInputStream最后通过doReadRemoteInvocation的readObject实现反序列化。
httpinvoker.HttpInvokerServiceExporter.handleRequest
httpinvoker.HttpInvokerServiceExporter.readRemoteInvocation
RemoteInvocationSerializingExporter.createObjectInputStream
RemoteInvocationSerializingExporter.doReadRemoteInvocation
RemoteInvocationSerializingExporter.readObject
漏洞修复其实直接升级到6.0版本就可以了,但是麻烦的点在于:
spring-web 6.0版本变动比较大,6.0之后jdk1.8的版本就不支持了.
转而Spring6jdk版本要求至少jdk17以上
对maven版本的要求是3.6以上
项目中使用的jBPM 6.2.0和Hibernate 4.2不兼容Spring Framework 6 ,Spring Framework 6需要JPA 2.2或更高版本,Hibernate 4.2也是基于JPA 2.0的,与Spring Framework 6不兼容。这样的话要想修复漏洞就不能采用升级的方式,只能手工修复:
1. 第一种方案就是添加执行限制,对序列化数据进行限制,如果存在调用恶意cc链就禁止,但是这样存在被绕过风险,并不安全
2. 第二种方案就是直接把HttpInvokerServiceExporter功能关闭,如果业务上没有使用并不会产生什么影响。
这里就采用第二种方案,将handleRequest方法置空,关闭其回调。
修改后代码如下:
以spring-web这个包为例.本质上来说就是创建一个和HttpInvokerServiceExporter.class内容相同的HttpInvokerServiceExporter.java的文件,然后在handleRequest中去除那段多余的代码,然后将HttpInvokerServiceExporter.java文件生成一个新的.class文件,然后将新的.class文件替换到原来的spring-web的原jar包中;
1.将新生成的HttpInvokerServiceExporter.java文件放到这个目录下面
2.进入cmd
3.javac -cp C:\Users\wonder\Desktop\spring-web漏洞修复\jar\* HttpInvokerServiceExporter.java
4.cp是指向这个HttpInvokerServiceExporter.java依赖的jar包的位置,javac是将.java文件生成.class文件
5.如果在执行javac -cp C:\Users\wonder\Desktop\spring-web漏洞修复\jar\* HttpInvokerServiceExporter.java出现了notfound的时候,检查自己的依赖是否正确,直到执行命令之后无异常.
6.执行命令成功之后会在当前目录下面生成.class文件,然后将生成的.class文件直接替换到原有的jar中的位置即可.
7.复制这两个.class文件,将spring-web-5.3.29.jar通过解压工具预览,注意不要解压;找到原来当中这个文件在jar中的原始位置;
8.替换即可;打开idea刷新maven之后重新验证,可以看到已经成功修改;
反编译工具:
jd-gui:https://github.com/java-decompiler/jd-gui/releases
参考:
CVE-2016-1000027分析
手动实现第三方jar包修改并重新打包