前段时间听园长和su18师傅在群里谈起,Tomcat Servlet 3.0的文件名解析规则有稍许奇特,上周跟了一下,以下为笔记:
Servlet3.0 新增了对文件上传请求解析的支持,
javax.servlet.http.HttpServletRequest#getParts,使用
request.getParts();即可获取文件上传包解析后的结果,从此不再需要使用第三方jar来处理文件上传请求了。
demo:
`package com.example.tomcat_bypass;`` ``import org.apache.commons.io.FileUtils;``import org.apache.commons.io.IOUtils;`` ``import javax.servlet.ServletException;``import javax.servlet.annotation.MultipartConfig;``import javax.servlet.annotation.WebServlet;``import javax.servlet.http.HttpServlet;``import javax.servlet.http.HttpServletRequest;``import javax.servlet.http.HttpServletResponse;``import javax.servlet.http.Part;``import java.io.*;``import java.util.Collection;`` ``@MultipartConfig``@WebServlet(name = "upload",value = "/upload")``public class upload extends HttpServlet {`` ` `@Override` `protected void doGet(HttpServletRequest req , HttpServletResponse resp) throws IOException {` `resp.getWriter().println("doPost!");`` ` `}`` `` ` `@Override` `protected void doPost( HttpServletRequest request , HttpServletResponse response) throws IOException, ServletException {` `PrintWriter out = response.getWriter();` `String contentType = request.getContentType();`` ` `// 检测是否是multipart请求` `if (contentType != null && contentType.startsWith("multipart/")) {` `String dir = request.getSession().getServletContext().getRealPath("/uploads/");` `File uploadDir = new File(dir);`` ` `if (!uploadDir.exists()) {` `uploadDir.mkdir();` `}`` ` `Collection<Part> parts = request.getParts();`` ` `for (Part part : parts) {` `String fileName = part.getSubmittedFileName();`` ` `if (fileName != null) {` `File uploadFile = new File(uploadDir, fileName);` `out.println(part.getName() + ": " + uploadFile.getAbsolutePath());`` ` `FileUtils.writeStringToFile(uploadFile, IOUtils.toString(part.getInputStream(), "UTF-8"));` `} else {` `out.println(part.getName() + ": " + IOUtils.toString(part.getInputStream()));` `}` `}` `}`` ` `out.flush();` `out.close();` `}`` ``}`` `
其中使用ApplicationPart来存储从multipart请求中接收的DiskFileItem对象信息:
而获取文件名所使用的方法为getSubmittedFileName(),如上图断点处所示。
跟进ApplicationPart类,查看其getSubmittedFileName方法:
使用unquote方法处理fileName,跟进查看:
一共两个特性:
case1:
当input String中含有双引号时‘ ” ’,整体字符长度将会减1。
case2:
当字符串中含有' \ '时,则会跳过该字符,将后一位字符直接放入result中。
针对文件名我们可以尝试构造如下类型的payload:
123\.\j\s\p
123.\j\s\p\
"123.js\p\xg
.....