这是大概两年前刚学习spring源码的时候写的一篇文章。一直没发出来,最近有点时间,整理下发在了博客上。by dingo
一、简介
Cve-2010-1622是spring框架在2010年被发现的一个漏洞(我知道很古老),该漏洞可以让攻击者通过url等方式注入自己的代码,并在服务端执行。如果服务器权限设置不当,甚至可以让攻击者执行自定义的任意代码。
二、准备
分析了这个漏洞的原理,我们基本就可以窥视出spring框架,尤其是springmvc的一些实现过程。鉴于国内对这个漏洞的讨论还比较少,个人觉得分析一下还是有一些意义的。
预备知识:
要分析该漏洞,需要有一些java,spring的基础知识。(当然不需要太多,☺)。除了对spring和java的简单了解外,我们需要首先了解一下spring中利用java反射原理对bean的操作方式。
a) BeanWrapperImpl的作用
我们都知道,Spring里面有一个很重要的概念就是容器,容器里面存放的是用户或者系统本身创建的bean对象。Spring通过容器创建和管理这些bean对象,并把他们注入到需要使用这些对象的方法或者类中。
在spring中org.springframework.beans.BeanWrapperImpl这个类发挥了很大的作用,它直接或间接实现了两个接口,BeanWrapper和PropertyAccessor。第一个接口定义了持有bean的方法,第二个接口定义了获取和修改bean的属性的方法。所以BeanWrapperImpl的功能就是具体实现了创建,持有以及修改bean的方法。
其中我们先重点提一下BeanWrapperImpl中的setPropertyValue方法。通过多种不同参数的setPropertyValue的方法,可以将简单类型的参数值或者复杂类型的参数值,比如array,list,map等,注入到指定bean的相关属性中。
b) 准备环境的搭建
准备环境很简单,我们简单搭了一个spring-mvc的环境。其中包括:
i. 一个简单的基于注释的controller:
@Controller
public class TestController {
@RequestMapping("/test.htm")
public String execute(User user){
return "success";
}
}
ii. 一个简单pojo,User类
public class User {
private String name;
getter and setters ……
}
iii. Success.jsp 模板
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
<form:form commandName="user">
<form:input path="name"/>
</form:form>
三、分析
接下来具体来调试漏洞
我们在spring的总入口DispatcherServlet.java的doDispatch方法出加上断点,
在启动测试环境之后,我们向测试环境的8080端口提交如下的get请求。
请记住这个参数,
后面会不停地提到。
1、spring中的代码分析
Spring通过调用总入口DispatcherServlet.java的doDispath方法来路由处理本次的http请求。通过源码,我们可以看到doDispatch的两个参数分别为HttpServletRequest request, HttpServletResponse response,也就是当前请求的request和response对象。这是由tomcat容器传递给spring的。
我们先来总体预览一下doDispatch对于本次http请求的执行过程。其实主要就是有3步。
a) 通过传入的Rquest,获取响应处理的controller
b) 传入get参数,执行controller的方法
c) 获取controller中相关方法的返回值,渲染模版对象,返回response
接下来,按照这个大纲,我们来看spring是怎么做的。
1.1 获取响应处理的controller
在springmvc中,一个controller常常对应着一个url路径,controller往往也是我们分析程序的入口处。但我们知道,spring不仅仅自己实现了springmvc框架,它与其他的mvc框架,比如stucts等都可以做到很好的结合。但是stucts中不是controller,而是action。所以Spring为了达到很好的扩展性,自定义了一种类型,handler,handler可以是任意框架的执行类,对于spring就是controller,对于stucts就是action.
为了正确解析本次http请求,我们首先需要找到处理这次请求的handler,也就是springmvc中的对应的controller,对应到本次的测试例子,应该就是com.dingo.controller.TestController.
我们来看doDispatch的源码:
processedRequest = checkMultipart(request);
//检查是不是上传类型等
mappedHandler = getHandler(processedRequest, false);
//通过传入的request从容器中找到相应的handler
getHandler通过传入的request对象获取了响应的处理handler,也就是我们的TestController,并且包装了其他一些interceptor,使之构成了一个内部对象——mappedHandler。(如图)
下面就是具体对获取的handle对象进行处理了。框架在处理http请求的时候不是使用的handle类,而肯定是使用的handler中的某个方法。对于各种不同handle中的方法,Spring都是通过HandlerAdapter的handle方法,进行统一调用,然后返回我们熟悉的spring的ModelAndView对象。
代码如下:
ModelAndView mv = null;
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
当ModelAndView对象返回之后,再调用:render(mv, processedRequest, response)
从而真正将模版渲染。这行代码也就是我们触发shellcode的地方。
以上就是doDispatch中的大体逻辑,我们从中看到了框架是如何找到相应的handle,以及如何触发提交的shellcode.但是还有很多具体细节我们并不清楚,比如class.classLoader.Url[0]是如何被绑定到tomcat中对于的classloader中的呢,比如spring在渲染的时候又是在哪执行的命令代码的呢。
接下来我们可以分两部分来分别分析,分别是:
1) handle如何执行contro