1. 介绍
在代码审计时发现以下功能点,Checkmarx显示存在Spring ModelView Injection
,是由ModelAndView
中的参数可被用户控制导致。这个漏洞的历史还是比较久的,但之前没有碰到过,于是就自己搭建环境调试一番,动手学习一下利用方法。
源码如下:
1 | "/menuitem") ( |
2. 实践
首先自己搭建一下测试环境,在本地用此代码Demo进行漏洞验证,Springframework版本为5.0.0.RELEASE
。
1 |
|
ModelAndView
是Spring中的一个模型视图对象,作用是设置跳转的视图地址或把controller方法中处理的数据传到jsp页面。
ModelAndView
有两种使用形式:
- forward:/view
- redirect:/view
若ModelAndView(view)
中的view
参数可被用户控制,可能导致文件被读取的问题。
若直接访问 http://localhost:8089/WEB-INF/web.xml ,返回404
而使用ModelAndView
注入,访问 http://localhost:8089/menuitem?url=forward:/WEB-INF/web.xml ,就可以看到web.xml
的内容
但是仅能读取web目录下的文件,不能读取系统其他文件。尝试读取web目录外的文件时产生如下报错:Check that the corresponding file exists within your web application archive!
除了文件读取,当然也能进行一些权限认证的绕过,这需要考虑具体的代码场景,不一定通用。
不过实际项目代码中多了RedirectView()
方法变成以下情形:
1 |
|
RedirectView
会触发302跳转的结果,等效于使用url=redirect:/WEB-INF/web.xml
虽然存在RedirectView
不能直接读取文件,但能利用302跳转这一特性,实现URL重定向
302跳转处回显了我们的输入,那么能进行CRLF注入吗?
答案是不能,Spring会将\r\n进行处理,转换成空格。在下图的请求中可以看到%0d
和%0a
被转换成\x20
3. 分析
/spring-framework/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java:468
1 | protected View createView(String viewName, Locale locale) throws Exception { |
从代码中可以看到,存在三种viewName
的处理方法:
- 以
redirect:
为前缀 - 以
forward:
为前缀 - 没有前缀
3.1 以redirect为前缀
新建一个RedirectView
对象,表现结果是根据视图名进行302跳转,返回包中的Location
头为redirectUrl
变量。
3.2 以forward为前缀
新建一个InternalResourceView
对象,根据视图名到指定的位置获取视图模板
在spring的配置文件中,会存在如下的视图解析器配置
1 | <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
InternalResourceView
对象会受到该视图解析器配置的影响。
InternalResourceViewResolver
会把返回的视图名称都解析为InternalResourceView
对象,InternalResourceView
会把Controller处理器方法返回的模型属性都存放到对应的request
属性中,然后通过RequestDispatcher
在服务器端把请求forword重定向到目标URL。比如在InternalResourceViewResolver
中定义了prefix=/WEB-INF/
,suffix=.jsp
,然后请求的Controller处理器方法返回的视图名称为test
,那么这个时候InternalResourceViewResolver
就会把test
解析为一个InternalResourceView
对象,先把返回的模型属性都存放到对应的HttpServletRequest
属性中,然后利用RequestDispatcher
在服务器端把请求forword到/WEB-INF/test.jsp
。
1 | <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> |
/spring-framework/spring-webmvc/src/main/java/org/springframework/web/servlet/view/UrlBasedViewResolver.java:549
1 | protected AbstractUrlBasedView buildView(String viewName) throws Exception { |
view.setUrl(getPrefix() + viewName + getSuffix())
会将前缀后缀拼接到view
中,会导致可访问的文件有限(此时的前缀后缀是配置文件中的prefix
和suffix
,不是传入时的forward:
)。
3.3 没有前缀
则调用super.createView()
方法,等效于用户直接访问viewName
。
/spring-framework/spring-webmvc/src/main/java/org/springframework/web/servlet/view/AbstractCachingViewResolver.java:274
1 | protected View createView(String viewName, Locale locale) throws Exception { |
4. 总结
Spring ModelView Injection
有以下几种利用方式:
- web目录下的文件读取,但存在一定的限制(
InternalResourceViewResolver
中前后缀的配置) - 权限认证绕过
- 重定向
参考
https://o2platform.files.wordpress.com/2011/07/ounce_springframework_vulnerabilities.pdf