某通用系统任意文件上传分析-网络安全论坛-网络安全-阻击者联盟

某通用系统任意文件上传分析

免责声明:传播、利用本公众号所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号及作者不为此承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,会立即删除并致歉。

代码定位

打开源码在控制器里面定位到FileManageController

d2b5ca33bd20250816080019

可以根据控制器找到/FileDir.do 然后根据代码定位到一个upload方法

d2b5ca33bd20250816080035

代码如下:

@RequestMapping(
        params = {"Action=Upload"}
    )
    @ResponseBody
    public Object uploadFile(HttpServletRequest request, HttpServletResponse response) {
        intcode=200;
        Map<String, Object> result = newHashMap();
        StringfileName="";
        MultipartFilemultipartFile=null;

        Map filePath;
        try {
            StringtempName= System.currentTimeMillis() + "" + (newRandom()).nextInt(100);
            StringtempDirPath= request.getSession().getServletContext().getRealPath(this.TEMPPATH);
            if (!CommonFunction.isDirExist(tempDirPath)) {
                CommonFunction.createDir(tempDirPath);
            }

            MultipartHttpServletRequestmRequest= (MultipartHttpServletRequest)request;
            multipartFile = mRequest.getFile("file");
            StringrealName= multipartFile.getOriginalFilename();
            Stringsuffix="";
            if (realName.lastIndexOf(".") > 0) {
                suffix = realName.substring(realName.lastIndexOf("."));
            }

            if (!"jsp".equals(suffix)) {
                StringfilePath= tempDirPath + File.separator + tempName + suffix;
                Filefile=newFile(filePath);
                FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
                if (CommonFunction.isExistFile(filePath)) {
                    fileName = file.getName();
                    result = this.service.parseFile(file);
                }

                result.put("FileName", fileName);
                return CommonFunction.createResultMap(code, result);
            }

            filePath = CommonFunction.createResultMap(202, result);
        } catch (Exception e) {
            code = 202;
            CommonFunction.writeExceptionLog("FileManage", e);
            return CommonFunction.createResultMap(code, result);
        } finally {
            try {
                if (multipartFile != null && multipartFile.getInputStream() != null) {
                    multipartFile.getInputStream().close();
                }
            } catch (Exception e) {
                CommonFunction.writeExceptionLog("FileManage", e);
            }

        }

        return filePath;
    }

漏洞点分析

d2b5ca33bd20250816080103

// 将 HttpServletRequest 转换为 MultipartHttpServletRequest,以处理 multipart/form-data 类型的文件上传请求
MultipartHttpServletRequestmRequest= (MultipartHttpServletRequest) request;

// 从请求中获取名为 "file" 的文件对象
multipartFile = mRequest.getFile("file");

// 获取上传文件的原始文件名(由客户端提供)
StringrealName= multipartFile.getOriginalFilename();

// 初始化文件后缀名为空字符串
Stringsuffix="";

// 检查文件名是否包含扩展名(即是否有 ".")
if (realName.lastIndexOf(".") > 0) {
    // 提取文件扩展名
    suffix = realName.substring(realName.lastIndexOf("."));
}

这里是很正常的,但是在比较的时候suffix的值并不是jsp而是.jsp

if (!"jsp".equals(suffix)) {
                String filePath = tempDirPath + File.separator + tempName + suffix;
                File file = new File(filePath);
                FileUtils.copyInputStreamToFile(multipartFile.getInputStream(), file);
                if (CommonFunction.isExistFile(filePath)) {
                    fileName = file.getName();
                    result = this.service.parseFile(file);
                }

本地写的一个Demo如下:

package com.student;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
publicclassMain {
    publicstaticvoidmain(String[] args) {
        // 定义结果 Map 和文件名
        Map<String, Object> result = newHashMap<>();
        StringfileName="";
        intcode=200; // 默认状态码
        try {
            // 指定文件路径为 src/main/resources/111.jsp
            StringfilePath="src/main/resources/111.jsp";
            // 创建文件对象
            Filefile=newFile(filePath);
            // 检查文件是否存在
            if (!file.exists()) {
                code = 202;
                System.out.println("文件不存在: " + filePath);
                result.put("error", "文件不存在");
                printResult(code, result);
                return;
            }
            // 检查文件后缀
            StringrealName= file.getName();
            Stringsuffix="";
            if (realName.lastIndexOf(".") > 0) {
                suffix = realName.substring(realName.lastIndexOf("."));
            }
            if ("jsp".equals(suffix)) {
                code = 202;
                System.out.println("禁止读取 JSP 文件: " + realName);
                result.put("error", "禁止读取 JSP 文件");
                printResult(code, result);
                return;
            }
            // 验证文件存在并读取
            if (file.exists() && file.isFile()) {
                fileName = file.getName();
                System.out.println("文件存在: " + fileName);
                result.put("FileName", fileName);
                result.put("Suffix", suffix);
                // 模拟 parseFile 方法,这里仅打印文件后缀
                System.out.println("文件后缀: " + suffix);
            } else {
                code = 202;
                System.out.println("无效文件路径: " + filePath);
                result.put("error", "无效文件路径");
            }
        } catch (Exception e) {
            code = 202;
            System.out.println("发生错误: " + e.getMessage());
            result.put("error", e.getMessage());
        }
        printResult(code, result);
    }
    // 模拟 CommonFunction.createResultMap,打印结果
    privatestaticvoidprintResult(int code, Map<String, Object> result) {
        System.out.println("状态码: " + code);
        System.out.println("结果: " + result);
    }
}

d2b5ca33bd20250816080152

正确写法:

d2b5ca33bd20250816080203

 

请登录后发表评论

    没有回复内容