java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Spring Mvc CommonsMultipartFile特性

Spring Mvc中CommonsMultipartFile的特性实例详解

作者:zpchcbd

这篇文章主要给大家介绍了关于Spring Mvc中CommonsMultipartFile特性的相关资料,SpringMVC拥有强大的灵活性,非侵入性和可配置性,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言:

简单的记录下Spring <= 4.1.8的CommonsMultipartFile的特性,遇到一个springmvc的一套系统通过该方法进行绕过上传解决,不过只限于windows的情况下,这篇笔记先介绍下关于CommonsMultipartFile,然后给出实例利用的情况

参考文章:https://forum.butian.net/share/815

MultipartFile是什么

在springmvc中进行文件上传的时候,springmvc提供了两个封装好的上传组件来进行使用,如下图所示,分别是CommonsMultipartFile和StandardMultipartFile

StandardMultipartFile

pom.xml

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.1.8.RELEASE</version>
    </dependency>

如果要使用StandardServletMultipartResolver进行文件上传,需要进行如下两个步骤

先在springmvc-servlet.xml中配置如下multipartResolver为StandardServletMultipartResolver

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />

然后在web.xml中还需要进行如下配置multipart-config,配置在DispatcherServlet的servlet标签中

        <multipart-config>
            <!--上传的文件的最大限制,单位byte-->
            <max-file-size>4194304</max-file-size>
            <!--multipart/form-data请求的最大限制,单位byte-->
            <max-request-size>10485760</max-request-size>
            <!--将存储上载文件的目录位置-->
            <!--<location></location>-->
        </multipart-config>

对于StandardMultipartFile类中有一个问题就是在获取文件名的时候实现的getOriginalFilename方法是直接获取文件名,没有进行过滤一些特殊字符的情况,这样的情况就会产生安全问题比如路径跳跃

UploadController.java

@Controller
public class UploadController {
    @RequestMapping(value = "/fileupload")
    @ResponseBody
    public String test(HttpServletRequest request) throws Exception {
        MultipartHttpServletRequest req = (MultipartHttpServletRequest)request;
        MultipartFile file = req.getFile("uploadFile");
        String realFileName = file.getOriginalFilename();
        String ctxPath = req.getSession().getServletContext().getRealPath("/tmp/");
        File dirPath = new File(ctxPath);
        if (!dirPath.exists()) {
            dirPath.mkdir();
        }
        String serverPath = ctxPath + File.separator + realFileName;
        try {
            File uploadFile = new File(serverPath);
            FileCopyUtils.copy(file.getBytes(), uploadFile);
            return serverPath;
        } catch (Exception var9) {
            var9.printStackTrace();
            return "upload fail";
        }
    }
}

上面代码的情况下,我们直接上传文件的话会存在目录跳跃的问题,结果如下所示,可以看到readme.jsp可以直接跳出tmp目录

这里主要问题出在getOriginalFilename方法,这里可以观察下StandardMultipartFile的getOriginalFilename,下面的图中可以看到没有对../这些符号做相关的限制

CommonsMultipartFile

pom.xml

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.1.8.RELEASE</version>
    </dependency>

这里可以将代码改为CommonsMultipartFile来进行测试

将springmvc-servlet.xml中配置如下multipartResolver为CommonsMultipartResolver

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

重新进行发包可以发现就不会出现目录跳跃的问题了

这里同样可以看下org.springframework.web.multipart.commons.CommonsMultipartFile#getOriginalFilename,可以看到首先就会匹配/符号,然后取/之后的内容

这里主要利用了org.springframework.web.multipart.commons.CommonsMultipartFile#getOriginalFilename,而这里有个逻辑问题就是如果在windows下的话\\同样可以作为分隔符来进行识别,所以如果对于/..\..\readme.jsp这种payload的话,那么在windows的情况下同样可以进行利用

这边拿windows的环境来进行测试,结果如下所示

调试过程可以看到org.springframework.web.multipart.commons.CommonsMultipartFile#getOriginalFilename最终取到的就是/之后的内容

漏洞修复

这边将pom.xml中的springmvc修改为4.1.9.RELEASE

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>4.1.9.RELEASE</version>
    </dependency>

重新测试的情况下,就无法进行绕过了

实战遇到的代码

这边拿前面篇头说的实际审计的情况,这个环境下是在/tmp/目录下禁止访问,所以如果要利用的话那么就需要上传的文件不在该目录下,那么这边的话就可以用getOriginalFilename跨越目录,用/..\..\readme.jsp来利用即可

    public static String upLoadFile(HttpServletRequest request) {
        MultipartHttpServletRequest req = (MultipartHttpServletRequest)request;
        MultipartFile file = req.getFile("uploadFile");
        String realFileName = file.getOriginalFilename();
        String ctxPath = request.getContextPath();
        ctxPath = req.getSession().getServletContext().getRealPath("/tmp/");
        File dirPath = new File(ctxPath);
        if (!dirPath.exists()) {
            dirPath.mkdir();
        }

        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
        String serverPath = ctxPath + File.separator + format.format(new Date()) + realFileName;

        try {
            File uploadFile = new File(serverPath);
            FileCopyUtils.copy(file.getBytes(), uploadFile);
            return serverPath;
        } catch (Exception var9) {
            var9.printStackTrace();
            return null;
        }
    }

总结

到此这篇关于Spring Mvc中CommonsMultipartFile特性的文章就介绍到这了,更多相关Spring Mvc CommonsMultipartFile特性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文