转自先知 https://xz.aliyun.com/t/36
最近国外研究人员先后爆出Spring Data REST远程代码执行漏洞(CVE-2017-8046)和Spring
AMQP远程代码执行漏洞(CVE-2017-8045),CVE-2017-8046关注的人比较多,这里对CVE-2017-8045进行简单分析和复现
漏洞原因
在Spring AMQP的Message类中,文件路径为spring-amqp/src/main/java/org/springframework/amqp/core/Message.java。getBodyContentAsString方法中将接收到的消息进行反序列化操作,从而导致任意代码执行。代码如下:
1 | private String getBodyContentAsString() { |
可以看到这里如果要触发漏洞,其中一个条件是要将请求的ContentType设置为application/x-java-serialized-object。
1 | public static final String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object"; |
代码分析
先分析存在漏洞的代码版本spring-amqp-1.7.3.RELEASE,整个项目代码中共有两处提供反序列化方法的类,分别是SerializerMessageConverter类和SerializationUtils类。
其中SerializerMessageConverter继承了WhiteListDeserializingMessageConverter类并实现了反序列化方法deserialize,代码如下:
1 | private Object deserialize(ByteArrayInputStream inputStream) throws IOException { |
上面代码可以看到在deserialize函数中hook了objectInputStream的resolveClass方法并调用WhiteListDeserializingMessageConverter类的checkWhiteList方法对反序列化的类进行白名单检查,如果反序列化的类不在白名单就抛出异常。WhiteListDeserializingMessageConverter类中同时实现了setWhiteListPatterns方法来设置反序列化的白名单。但在1.7.3版本中并未见到任何地方使用该函数进行白名单设置,所以这个白名单控制还是依赖使用到spring-amqp的开发人员自行设置,如果开发人员不设置依旧可能存在反序列化漏洞。
在SerializationUtils类的反序列化方法中则未进行任何安全校验:
1 | public static Object deserialize(byte[] bytes) { |
而本次漏洞触发点getBodyContentAsString函数中调用的正是SerializationUtils的deserialize方法。
漏洞利用
Message类中toString方法调用了getBodyContentAsString函数,而该漏洞发现者介绍,该方法在代码中许多错误处理及日志记录中会调用到并给出了相关demo。该程序只允许接收JSON格式消息,此时使用ysoserial生成payload,并将
Content-Type设置为application/x-java-serialized-object,然后发送消息,因为demo程序只允许接收json格式消息,所以会触发异常,从而调用并将消息带入toString函数触发漏洞执行任意代码。
可以使用spring-amqp-samples中的demo,将Application中container方法中添加:
1 | listenerAdapter.setMessageConverter(new Jackson2JsonMessageConverter()); |
在测试用例中修改发送消息格式:
1 | public void test() throws Exception { |
安装RabbitMQ,mac下安装使用命令即可:
1 | brew install rabbitmq |
在resources目录创建application.properties文件,内容如下:
1 | spring.rabbitmq.host=localhost |
使用ysoserial生成payload文件,在pom依赖中添加commons-collections
3.1,接着调试运行即可进入到tosting函数,并弹出计算器:
补丁分析
在修复版本以1.7.4为例,getBodyContentAsString中反序列化接口改为调用SerializerMessageConverter的fromMessage方法将AMQP消息转换为对象,并使用setWhiteListPatterns函数设置了允许被反序列化类的白名单,只允许反序列化java.util.
和java.lang. 开头的类:
1 | static { |
详细见https://github.com/spring-projects/spring-amqp/commit/36e55998f6352ba3498be950ccab1d5f4d0ce655
参考
- https://lgtm.com/blog/spring_amqp_CVE-2017-8045
- http://www.cnvd.org.cn/webinfo/show/4247
- https://pivotal.io/security/cve-2017-8045
- https://jira.spring.io/browse/AMQP-766
- https://github.com/Cryin/Paper/blob/master/Spring%20AMQP%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E(CVE-2017-8045)%E5%88%86%E6%9E%90.md
