基于 java 【Web安全】文件上传漏洞及目录遍历攻击

时间:2022-01-18 21:24:08

 前言:web安全之文件上传漏洞,顺带讲一下目录遍历攻击。本文基于 java 写了一个示例。

原理

  在上网的过程中,我们经常会将一些如图片、压缩包之类的文件上传到远端服务器进行保存。文件上传攻击指的是恶意攻击者利用一些站点没有对文件的类型做很好的校验,上传了可执行的文件或者脚本,并且通过脚本获得服务器上相应的权利,或者通过诱导外部用户访问、下载上传的病毒或木马文件,达到攻击的目的。

  文件上传漏洞指攻击者利用程序缺陷绕过系统对文件的验证与处理策略将恶意程序上传到服务器并获得执行服务器端命令的能力。这种攻击方式直接、有效,在对付某些脆弱的系统时甚至没有门槛。

  文件上传漏洞的常见利用方式有:

    上传Web脚本程序,Web容器解释执行上传的恶意脚本。

    上传Flash跨域策略文件crossdomain.xml,修改访问权限(其他策略文件利用方式类似)。

    上传病毒、木马文件,诱骗用户和管理员下载执行。

    上传包含脚本的图片,某些浏览器的低级版本会执行该脚本,用于钓鱼和欺诈。

  总的来说,为了实现一次攻击利用,必须要满足以下条件:

    文件能通过前端和后端的过滤和文件处理.

    文件内容不会被改变,能够被正确的存储

    存储位置是在Web容器控制范围

    攻击者有权限访问存储目录

攻击示例

基于 springmvc 的代码

jsp 代码

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />

<html>
<head>
    <title>web 安全之文件上传漏洞</title>
</head>

<body>
    <form  action="${ctx}/uploadFileDemoCtrl/uploadFile" method="post" enctype="multipart/form-data">
        选择文件进行上传:<input type="file" name="file"/>
        <input type="submit" value="上传"/>
    </form>

    <br/>

    <form  action="${ctx}/uploadFileDemoCtrl/downLoadFile" method="get">
        输入需要下载的文件名称:<input type="text" name="filename"/>
        <input type="submit" value="下载"/>
    </form>

</body>
</html>

java 代码

controller 层 到jsp

@RequestMapping("/index")
    public String index(){
        return "yule/uploadfile/uploadFileDemo";
    }

 

上传文件后台处理

/**
     * 文件上传
     * 有漏洞的上传文件代码
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("/uploadFile")
    public String uploadFile(HttpServletRequest request) throws IOException {
        // 转型为MultipartHttpRequest
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        // 获得文件到map容器中
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        if(fileMap == null || fileMap.size() == 0){
            System.out.println("没有文件!");
            return "yule/uploadfile/uploadFileDemo";
        }

        String root = request.getServletContext().getRealPath("/upload");
        File savePathFile = new File(root);
        if(!savePathFile.exists()){
            savePathFile.mkdirs();
        }

        String fileName = null;
        String suffixName = null;
        MultipartFile mf = null;
        InputStream fileIn = null;
        List<InputStream> isList = new ArrayList<InputStream>();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            mf = entity.getValue();
            fileName = mf.getOriginalFilename();//获取原文件名
            suffixName = fileName.substring(fileName.lastIndexOf("."), fileName.length());
            try {
                fileIn = mf.getInputStream();
                isList.add(mf.getInputStream());
                LocalFileUtils.upload(fileIn, root, fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if(fileIn != null){
                  fileIn.close();
                }
            }
        }

        return "yule/uploadfile/uploadFileDemo";
    }

运行,页面如下:

基于 java 【Web安全】文件上传漏洞及目录遍历攻击

上传各种文件到工程下的 upload 文件夹下。

基于 java 【Web安全】文件上传漏洞及目录遍历攻击

 

这里可以上传各种文件,因为代码没有做任何的防止文件上传漏洞的行为。这里代码的漏洞非常容易被利用,比如,上传一个有脚本的 jsp 文件 1.jsp,文件如下:

<%@page import="java.io.File"%>
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%
    String root = request.getServletContext().getRealPath("/upload");
    out.write("系统部署文件上传的绝对路径:"+root);
    File file = new File(root);
    String[] tempList = file.list();
    File temp = null;
    String fileName;
    for (int i = 0; i < tempList.length; i++) {
        if (root.endsWith(File.separator)) {
            fileName = root + tempList[i];
        } else {
            fileName = root + File.separator + tempList[i];
        }
        temp = new File(fileName);
        if (temp.isFile()) {
            out.write("删除文件:" + fileName + "");
            temp.delete();
        }
    }
    file.delete();
%>

上传成功后,用地址访问该文件,可怕的事情发生了,利用漏洞,会导致 upload 文件夹及下面的文件全部被删除。

 基于 java 【Web安全】文件上传漏洞及目录遍历攻击

 

目录遍历攻击

  文件交互是一种简单的过程,但是由于文件名可以任意更改而服务器支持“~/”,“../”等特殊符号的目录回溯,从而使攻击者越权访问或者覆盖敏感数据,如网站的配置文件、系统的核心文件,这样的缺陷被命名为路径遍历漏洞

  示例:

 在 jsp 中加入 form 表单下载

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<c:set var="ctx" value="${pageContext.request.contextPath}" />

<html>
<head>
    <title>web 安全之文件上传漏洞</title>
</head>

<body>
    <form  action="${ctx}/uploadFileDemoCtrl/uploadFile" method="post" enctype="multipart/form-data">
        选择文件进行上传:<input type="file" name="file"/>
        <input type="submit" value="上传"/>
    </form>

    <br/>

    <form  action="${ctx}/uploadFileDemoCtrl/downLoadFile" method="get">
        输入需要下载的文件名称:<input type="text" name="filename"/>
        <input type="submit" value="下载"/>
    </form>

</body>
</html>

java 代码

/**
     * 文件下载
     * 有目录遍历攻击漏洞的代码
     */
    @RequestMapping("/downLoadFile")
    public void downLoadFile(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取项目部署绝对路径下的upload文件夹路径,下载upload目录下面的文件
        String root = request.getServletContext().getRealPath("/upload");
        //获取文件名
        String filename = request.getParameter("filename");
        File file = new File(root + "/" + filename);
        //根据文件路径创建输入流
        FileInputStream fis = new FileInputStream(file);
        //设置响应头,弹出下载框
        response.addHeader("Content-Disposition", "attachment;filename=" + new String(filename.getBytes()));
        response.addHeader("Content-Length", "" + file.length());
        byte[] b = new byte[fis.available()];
        fis.read(b);
        response.getOutputStream().write(b);
    }

运行,页面显示如下:

基于 java 【Web安全】文件上传漏洞及目录遍历攻击

在输入框中输入文件名,即可下载 upload 文件夹下的文件。但是这里如果输入类似 “../WEB-INF/web.xml” 的文件名,则会下载 web.xml 文件,同理,很多文件都可以下载下来,包括一些配置文件,这就是目录遍历攻击。

解决方案

  这里可以通过数据库存储文件信息,下载利用数据库 id 下载,同时后台传给前端使用加密形式来防止这个漏洞。