作者:[**iswin@ThreatHunter**](https://threathunter.org/topic/593d562353ab369c55425a90)
#### 一. 漏洞简介
这个漏洞在今年6月初刚被提交([传送门](https://pivotal.io/security/cve-2017-4971)), 官方并没有详细的信息,通过官方描述和补丁的对比,我们可以大致推断应该是 Spring Web Flow 在 Model 的数据绑定上面,由于没有明确指定相关 model 的具体属性导致从表单可以提交恶意的表达式从而被执行,导致任意代码执行的漏洞,这个漏洞利用除了版本的限制之外还有两个前置条件,这两个前置条件中有一个是默认配置,另外一个就是编码规范了,漏洞能不能利用成功主要就取决于后面的条件。
整体来说这个漏洞危害应该还是有一些的,如果满足2个前置条件,那么直接 RCE 是没什么问题的。在分析这个漏洞之前需要一些 Spring Web flow 的基础知识,给大家推荐[这篇文章](https://www.ibm.com/developerworks/cn/education/java/j-spring-webflow/index.html)。
#### 二. 漏洞分析
一开始我也不清楚这个漏洞到底是怎么触发,对于这个漏洞的理解,最好去看下 Spring Web Flow 的教程,搞明白里面的 view-state 是啥,这里不过多对 Spring Web Flow 的基础知识过多解释,那么我们直接看补丁,如下图:

我们发现这里对 *addEmptyValueMapping(DefaultMapper mapper, String field, Object model)* 这个方法里面表达式解析的实现类进行了替换,直接使用了 BeanWrapperExpressionParser 来解析,关于这个类我们后面再详细说,那么知道触发漏洞的函数后,我们就可以用 Eclipse 或者 Spring Tools 来跟踪下函数调用栈,具体如下:

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

言归正传,本次漏洞出现的原因就是在 view-state 节点中数据绑定上,我们继续跟踪
addEmptyValueMapping 方法的调用过程,这里通过 eclipse 我们可以发现 bind 方法间接的调用了
addEmptyValueMapping 函数,

到这里我们知道了addEmptyValueMapping 函数存在表达式执行的点,我们现在来详细看下这个
addEmptyValueMapping 函数,如下图

这里我们可以看见,只有控制了 field 参数才能出发漏洞,所以我们重点是找到有没有点我们可以控制从而控制 field 参数来进行任意代码执行,这里明确目标后,我们回过头来看 addDefaultMappings 和
addModelBindings 这两个函数,既然这两个函数都调用了存在缺陷的函数,那么我们看看这两个函数的区别是什么,而且那个函数能能能控制 field 参数,两个函数的区别如下:


这里比较明显的区别就是 addModelBindings 函数中 `for (Binding binding : binderConfiguration.getBindings())` 存在这样一个循环,而且就是这个循环的控制决定了 field 参数的值,经过进一步分析,这里控制 field 的参数的决定性因素就是 binderConfiguration 这个变量所控制的值,这里经过源码的跟踪我们可以发现,binderConfiguration 函数的值就是 webflow-*.xml 中 view-state 中 binder 节点的配置,所以这个函数的值来源于配置文件,所以这个函数我们无法控制,从而无法触发漏洞,所以我们重点来看看 addDefaultMappings 这个函数,我们发现 addDefaultMappings 中我们可以控制 field 参数,所以我们重点来看看如何去触发这个函数。
现在我们基本上可以确定了 addDefaultMappings 函数是我们触发漏洞的关键点,那么如上图所示,bing 函数中调用了这两个函数,那么我们可以看出只有当 binderConfiguration 为空的时候才能触发我们的漏洞,那么我们刚才也说了 binderConfiguration 这个值是由配置文件中是否有 binder 节点来控制的(这里需要注意的是程序执行到 bind 方法的前置条件是 view-state 节点中是否配置了 model 属性,即绑定的
javabean 对象是什么),而且 addDefaultMappings 函数中 parameterNames 参数就是我们从表单中传递的值,所以到这里漏洞的触发流程和触发条件基本上清楚了,触发条件如下:
* 在 webflow 配置文件中 view-state 节点中指定了 model 属性,并且没有指定绑定的参数,即 view-state 中没有配置 binder 节点
* 而且 MvcViewFactoryCreator 类中 useSpringBeanBinding 默认值(false)未修改
这里为什么一定要 useSpringBeanBinding 的值为 false ,我们来看一下 addEmptyValueMapping 函数,这里的 expressionParser 变量的声明类是 ExpressionParser 接口,那么决定最后 `
expressionParser.parseExpression(field, parserContext)` 这个函数来执行任意表达式是这个变量的赋值,那么在 spring web flow 中这个 expressionParser 的默认值就是 WebFlowELExpressionParser 的实例,这个类表达式默认的解析是有 spel 来执行的,具体可以去跟踪函数,那么在org.springframework.webflow.mvc.builder.MvcViewFactoryCreator.createViewFactory(Expression, ExpressionParser, ConversionService, BinderConfiguration, Validator, ValidationHintResolver)这个类如下图:

我们可以看见如果 useSpringBeanBinding 这个属性为 false 那么久使用默认的解析类,如果这个值为 true 就由 BeanWrapperExpressionParser 这个类来解析,这个类的 parseExpression 函数我们来看看

首先决定了能不能执行的第一个控制变量是 allowDelimitedEvalExpressions ,这个默认值是 false ,所以这里是执行不了表达式的。
所以这里必须满足 useSpringBeanBinding 这个默认值不被改变。
这里需要注意一点,我们构造的恶意参数名称必须以_开头,具体原因看 addDefaultMappings 函数中的
fieldMarkerPrefix 变量。
OK,到这里漏洞的触发条件和流程已经很明确了,下面说说具体怎么利用。
#### 三. 漏洞利用
这次漏洞测试是以 Spring Web flow 官方的 Example 中的例子来进行,因为这里的某个 flow 满足我们的条件,具体配置如下:

[项目地址](https://github.com/spring-projects/spring-webflow-samples/tree/master/booking-mvc),这里在测试时需要注意修改
org.springframework.webflow.samples.booking.config.WebFlowConfig.mvcViewFactoryCreator()
方法中的改成 `factoryCreator.setUseSpringBeanBinding(false);` 因为这个工程修改了
useSpringBeanBinding 的默认值。
这里直接到订阅图书,上图说了在 reviewBooking flow 中就能出发,如下图:

点击 confirm ,然后抓包添加恶意参数变量,如下图:

OK,大功告成。
暂无评论