[备份]CVE-2017-4971分析

简介

Spring Web Flow

Spring系列一个冷门框架。session之下request之上的一个框架,定义多个流程,尤其适合需要多个步骤的业务,理论上可以简化开发,实际上很少有人选择。它将XML作为语言,这无疑是落后的

漏洞简介

Spring Web Flow在Model的数据绑定上存在漏洞,导致RCE。由于没有明确指定相关Model的具体属性,导致从表单可以提交恶意的表达式从而被执行。漏洞出发条件比较苛刻

环境搭建

下载Spring官方示例:https://github.com/spring-projects/spring-webflow-samples 使用其中的booking-mvc项目,打开后发现是Maven+JPA的项目。启动比较麻烦,先git checkout到2.3.x分支,导入IDEA处理完依赖后,配置Tomcat,通过Tomcat启动war包 (IDEA比较方便,配好Tomcat指定Deployment即可) img

访问localhost:8080如下

img

修改配置文件:src\main\webapp\WEB-INF\config\webflow-config.xml

漏洞复现

进入系统后,根据左边提供的用户名密码登录一个。找任意一个酒店下单,在Confirm按钮点击前使用burp抓包(如果burp无法firefox在localhost的包,尝试进入about:config,搜索下面这个配置network.proxy.allow_hijacking_localhost并修改为true) img

修改请求,加入payload后发送,成功启动计算器

img

漏洞分析

这个漏洞如果从正面角度分析,比较困难,所以先在github找到补丁:https://github.com/spring-projects/spring-webflow/commit/57f2ccb66946943fbf3b3f2165eac1c8eb6b1523

分析后发现替换了addEmptyValueMapping方法的解析器为BeanWrapperExpressionParser img

img 这里通过调用关系我们可以大概的搞明白Spring Web Flow的执行顺序和流程,由 FlowController决定将请求交给那个handler去执行具体的流程。这里我们需要知道当用户请求有视图状态处理时,会决定当前事件下一个执行的流程,同时对于配置文件中我们配置的view-state元素,如果我们指定了数据的 model,那么它会自动进行数据绑定,xml 结构如下(这里以官方的example中的 book 项目为例子) img

其中数据绑定部分的代码如下,跟踪后发现其中addModelBindings和addDefaultMappings都间接调用了addEmptyValueMapping方法

addEmptyValueMapping方法如下,其中Expression就是SPEL。如果传入的field是恶意代码,经过getValueType就会造成RCE

之前分析有两处调用addEmptyValueMapping,分析传入的field参数

首先分析addModelBindings,其中关键是binderConfiguration,断点调试发现这里是xml配置中硬编码的,也就是无法修改的部分。放弃分析这里,前往addDefaultMappings函数 img

之前要提到bind方法并不是没有意义的,其中这段代码正是核心,只有binderConfiguration为空,也就是xml的binder节点为空的时候,才会调用addDefaultMappings方法

其中reviewBooking的view-state中不存在binder节点,意味着binderConfiguration为空,成功调用到addDefaultMappings(reviewBooking翻译过来大概是确认预定,也就是上文复现中的Confirm确认按钮,所以可以定位到这里)

在addDefaultMappings这一段,fieldMarkerPrefix是“”,所以我们POST的key以开头,substring后正好是payload(new+java.lang.ProcessBuilder("calc.exe")).start(),而parameterNames是表单传的value,value中不存在payload,调用addEmptyValueMapping

关于一开始为什么要将useSpringBeanBinding设置为false,我们返回addEmptyValueMapping org\springframework\webflow\mvc\builder\MvcViewFactoryCreator.java

如果useSpringBeanBinding为true,使用BeanWrapperExpressionParser,具体的解析方法中会判断allowDelimitedEvalExpressions,这个值不可控并且默认是false,会直接抛出异常

修复

现在看修复方案,应该比较清晰了,直接规定了使用BeanWrapperExpressionParser