【创宇小课堂】任意文件上传漏洞代码审计

admin 2022年3月23日06:32:28代码审计评论29 views3485字阅读11分37秒阅读模式

作者:W3Qr




任意文件上传示例


public class FileUploadServlet extends HttpServlet {

private static final long serialVersionUID = 1L;

protected void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

//判断请求是否为multipart请求

if(!ServletFileUpload.isMultipartContent(request)){

throw new RuntimeException("当前请求不支持文件上传");

}

try {

/*

DiskFileItemFactory可以设置缓存大小以及临时文件保存的位置

临时文件默认村粗在系统的临时文件目录下

*/

DiskFileItemFactory factory = new DiskFileItemFactory();

/*

ServletFileUpload(factory)创建一个上传工具,指定使用缓存区与零食文件存储位置

*/

ServletFileUpload servletFileUpload = new ServletFileUpload(factory);

//解析请求,获取到所有的item,每一个item相当于一个上传项

List<FileItem> items = servletFileUpload.parseRequest(request);

//遍历items

for(FileItem item : items){

//isFormField,True表示是普通表单项,false为文件表单项

if(item.isFormField()){  //若item为普通表单项

String fieldName = item.getFieldName();  //获取表单项名称

String fieldValue = item.getString();  //获取表单项的值

System.out.println(fieldName + " = " + fieldValue);

}else{  //若item为文件表单项

//获取上传文件原始名称

String fileName = item.getName();

//获取输入流,其中有上传 文件的内容

InputStream is = item.getInputStream();

//获取文件保存在服务器的路径

String path = this.getServletContext().getRealPath("/images");

//创建目标文件,将用来保存上传文件

File file = new File(path, fileName);

//将输入流中的数据写入到输出流中

OutputStream os = new FileOutputStream(file);

//将输入流中的数据写入输出流中

int len = -1;

byte[] buf = new byte[1024];

while((len = is.read(buf)) != -1){

os.write(buf, 0, len);

}


os.close();

is.close();

}

}

} catch (FileUploadException e) {

e.printStackTrace();

}

}


}





几种修复方式

通过后缀名进行判断


String fileType= "";

int i = fileName.lastIndexOf('.');

if (i > 0) {

fileType= fileName.substring(i+1);

}

//...

if("jpg".equals(fileType) || "png".equals(fileType) ....){

//your code

}


通过文件头校验



// 获得文件头部字符串

public static String bytesToHexString(byte[] src) {

StringBuilder stringBuilder = new StringBuilder();

if (src == null || src.length <= 0) {

return null;

}

for (int i = 0; i < src.length; i++) {

int v = src[i] & 0xFF;

String hv = Integer.toHexString(v);

if (hv.length() < 2) {

stringBuilder.append(0);

}

stringBuilder.append(hv);

}

return stringBuilder.toString();

}

FILE_TYPE_MAP.put("jpg", "FFD8FF"); //JPEG

FILE_TYPE_MAP.put("png", "89504E47"); //PNG

FILE_TYPE_MAP.put("gif", "47494638"); //GIF


通过ImageIO判断


/**

* 通过读取文件并获取其width及height的方式,来判断判断当前文件是否图片,这是一种非常简单的方式。

* @param imageFile

* @return

*/

public static boolean isImage(File imageFile) {

if (!imageFile.exists()) {

return false;

}

Image img = null;

try {

img = ImageIO.read(imageFile);

if (img == null || img.getWidth(null) <= 0 || img.getHeight(null) <= 0) {

return false;

}

return true;

} catch (Exception e) {

return false;

} finally {

img = null;

}

}


【创宇小课堂】任意文件上传漏洞代码审计




任意文件下载漏洞代码审计

任意文件下载漏洞代码示例


//服务端

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String file = request.getParameter("filename");

String dpath = request.getParameter("path");

ServletContext con = request.getServletContext();

String type = file.substring(file.lastIndexOf(".")+1);

System.out.println(type);

System.out.println(type=="php");

System.out.println(type.equals("php"));

if (!type.equals("php")){

String path = con.getRealPath("/")+dpath+file;

System.out.println(path);

FileInputStream stream = new FileInputStream(path);

String mime = con.getMimeType(path);

response.setHeader("content-type",mime);

response.setHeader("content-disposition","attachment;filename="+file);

byte[] bytes = new byte[1024];

int len=0;

ServletOutputStream out = response.getOutputStream();

while ((len=stream.read(bytes))!=-1){

out.write(bytes);

}

}else {

System.out.println("文件类型不允许");

}

}


此处替换文件名为“WEB-INF/web.xml”,下载系统配置文件:

【创宇小课堂】任意文件上传漏洞代码审计

综上所述文件下载漏洞的成因是由于未对用户传输的路径做过滤





任意文件下载漏洞修复


1、漏洞修复可以根据自身业务需要修改,大致修复方法如下:


对文件下载进行过滤,过滤掉“./”、“../”、“%”等,代码如下:

【创宇小课堂】任意文件上传漏洞代码审计


但是可以构造完整路径,下载任意文件:

【创宇小课堂】任意文件上传漏洞代码审计


2、对下载的文件路径进行严格控制,只允许下载某部分目录下的文件:

【创宇小课堂】任意文件上传漏洞代码审计


【创宇小课堂】任意文件上传漏洞代码审计

但仍然可以被绕过,在文件名那里构造即可


3、对下载文件后缀名做严格控制

【创宇小课堂】任意文件上传漏洞代码审计


【创宇小课堂】任意文件上传漏洞代码审计

【创宇小课堂】任意文件上传漏洞代码审计

【创宇小课堂】任意文件上传漏洞代码审计

原文始发于微信公众号(安全宇宙):【创宇小课堂】任意文件上传漏洞代码审计

特别标注: 本站(CN-SEC.COM)所有文章仅供技术研究,若将其信息做其他用途,由用户承担全部法律及连带责任,本站不承担任何法律及连带责任,请遵守中华人民共和国安全法.
  • 我的微信
  • 微信扫一扫
  • weinxin
  • 我的微信公众号
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年3月23日06:32:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                  【创宇小课堂】任意文件上传漏洞代码审计 http://cn-sec.com/archives/590025.html

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: