还记得IIS的解析漏洞吗?xx.asp;.jpg。而最近对java网站进行测试的时候发现了一个问题,也是由分号引起的,也因此去查看了一下源码,也许很多人已经知道了这个问题,但是也许有的人不知道,所以我将内容记录下来了并进行了分享。

起因

我在测试的时候的一个功能的配置文件片段为:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">

        <property name="prefix" value="/view/" />

        <property name="suffix" value=".jsp" />

</bean> 

代码片段:

 public static String PRE = "landingpage/"; @RequestMapping({"online"}) public String toOnline(String version) { if (StringUtils.isBlank(version)) {
      version = "1.0";
    } return PRE + "online-" + version;
  } 

很明显,version的值是可以通过客户端传递过来的,也就是返回的文件路径是可以被控制的:

当version=xxx时,返回的文件应该是:/view/landingpage/online-xxx.jsp

所以这一功能是存在任意文件下载漏洞的,前提是我们如何把后面的.jsp给分割出去,在很多时候我们会使用%00等空字符进行截断,但是这里并不能成功。

而经过一些测试,我发现分号在这里能有截断的功能,也就是当我输入../../WEB-INF/web.xml;的时候,我能够获取到web.xml的配置信息:

1.jpg

怀疑

漏洞已经测试成功,但是为什么分号能够有截断的功能呢?

我开始以为是spring mvc的框架中的问题,但似乎并不是,我又怀疑是tomcat中间件的问题,似乎也不全是。

如何验证这些疑问呢?

找一个java的网站,在路径的结尾也就是问号的前面输入:http://www.xxx.com/sdaf.jsp;xxxx?id=xx,你会发现和http://www.xxx.com/sdaf.jsp?id=xx返回的结果一样的,并没有提示找不到对应的页面。

也就是说;xxxx在处理的过程中与前面的内容被分隔开了。

也就是说这似乎是java web的一个普遍现象,而不仅仅是某个中间件或者spring的问题。

调试

于是直接写了一个简单的jsp的代码,来调试这个过程:

<% request.getRequestDispatcher(request.getParameter("filename")+".doc").include(request, response); %> 

作为突破口,使用tomcat作为中间件进行调试,打开接口requestDispatcher的一个实现类:ApplicationDispatcher

2.jpg

在ApplicationDispatcher中设置断点进行调试

访问下面地址来触发断点:

http://localhost:8080/Spring/test123.jsp?filename=/WEB-INF/web.xml; 

这时发现doForward函数中的变量servletPath中的值为:WEB-INF/web.xml,已经将分号以及后面的数据给去除了

3.jpg

而经过变量的追踪,就发现在经过wrequest.setServletPath(servletPath)这个方法前:wrequest.getServletPath=”test123.jsp”,而之后变成了/WEB-INF/web.xml,所以问题出在servletPath的获取上:servletPath的获取应该是在实例化的时候,也就是在代码中:

public ApplicationDispatcher   (Wrapper wrapper, String requestURI, String servletPath, String pathInfo, String queryString, String name) { super(); // Save all of our configuration parameters this.wrapper = wrapper; this.context = (Context) wrapper.getParent(); this.requestURI = requestURI; this.servletPath = servletPath; this.pathInfo = pathInfo; this.queryString = queryString; this.name = name; if (wrapper instanceof StandardWrapper) this.support = ((StandardWrapper) wrapper).getInstanceSupport(); else this.support = new InstanceSupport(wrapper);

} 

由此看出来servletPath的值也是从外部传递进来的

实例化该类的对象为:ApplicationContext.getRequestDispatcher:

4.jpg

查看代码

5.jpg

以及调试时发现初始的path传递的值为

6.jpg

而最终返回的内容的值为:/WEB-INF/web.xml

也因此定位了关键位置:

7.jpg

而这里并没有结束,因为在这个方法中,除了分号的一个截断外,还有一个符号也会被分割,就是问号“?”:

8.jpg

结束

也就是说在java web中我们使用分号和问号,在某种程度上来说,是可以起到截断的作用的,但会不会如xx.asp;.jpg一样,导致解析漏洞呢,事实上是没有的,当我们去访问http://www.xxx.com/1.jsp;.jpg的时候,事实上访问的是1.jsp这个文件,而不是1.jsp;.jpg这个文件,当我们上传了1.jsp;.jpg文件时,通过web是访问不到的。

PS:java servlet的重定向和转发:

request.getRequestDispatcher("http://www.xx.com").forward(request,reponse);
response.sendRedirect("/xxx.jsp"); 

*本文原创作者:wadcl