Spring Mvc中CommonsMultipartFile的特性实例详解

 更新时间:2023年11月20日 15:30:59   作者: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特性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot war包部署过程详解

    springboot war包部署过程详解

    这篇文章主要为大家介绍了springboot war包部署过程详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • Java8日期类LocalDate、LocalTime和LocalDateTime使用方法详解

    Java8日期类LocalDate、LocalTime和LocalDateTime使用方法详解

    这篇文章主要给大家介绍了关于Java8日期类LocalDate、LocalTime和LocalDateTime使用方法的相关资料,LocalDateTime是JDK1.8出现的新特性,解决线程不安全的问题,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-11-11
  • Spring 实现自定义监听器案例

    Spring 实现自定义监听器案例

    这篇文章主要介绍了Spring 实现自定义监听器案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-01-01
  • 使用Spring Initializr创建Spring Boot项目没有JDK1.8的解决办法

    使用Spring Initializr创建Spring Boot项目没有JDK1.8的解决办法

    很久没创建springboot项目,今天使用idea的Spring Initializr 创建 Spring Boot项目时,发现java版本里,无法选择jdk1.8,只有17、21、22,所以本文介绍了使用Spring Initializr创建Spring Boot项目没有JDK1.8的解决办法,需要的朋友可以参考下
    2024-06-06
  • redis.clients.jedis.exceptions.JedisMovedDataException异常解决

    redis.clients.jedis.exceptions.JedisMovedDataException异常解决

    redis.clients.jedis.exceptions.JedisMovedDataException 异常是在使用 Jedis 客户端与 Redis 集群进行交互时发生的,下面就来介绍一下解决方法,感兴趣的可以了解一下
    2024-05-05
  • SpringBoot将项目打成war包步骤解析

    SpringBoot将项目打成war包步骤解析

    这篇文章主要介绍了SpringBoot将项目打成war包步骤解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Springboot 集成 lombok.jar过程解析

    Springboot 集成 lombok.jar过程解析

    这篇文章主要介绍了Springboot 集成 lombok.jar过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Java 程序设计总复习题(java基础代码)

    Java 程序设计总复习题(java基础代码)

    这篇文章主要介绍了Java 程序设计总复习题,主要是java基础代码,方便学习java的同学
    2021-05-05
  • JAVA堆排序算法的讲解

    JAVA堆排序算法的讲解

    这篇文章主要介绍了JAVA堆排序算法的知识点,文中代码非常详细,配合上图片讲解,帮助大家更好的参考和学习,感兴趣的朋友可以了解下
    2020-06-06
  • Java单例模式的五种实现方式

    Java单例模式的五种实现方式

    单例模式(Singleton Pattern)是Java中最简单的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式,下面这篇文章主要给大家介绍了关于Java单例模式的五种实现方式 ,需要的朋友可以参考下
    2022-06-06

最新评论