南通seo网站排名优化,网站性能优化的方法有哪些,四川做网站多少钱,好的设计公司网站1 文件上传漏洞审计
1.1 漏洞原理介绍
大部分文件上传漏洞的产生是因为Web应用程序未对文件的格式和进行严格过滤#xff0c;导致用户可上传jsp、php等webshell代码文件#xff0c;从而被利用。例如在 BBS发布图片 , 在个人网站发布ZIP压缩包, 在办公平台发布DOC文件等 , 只…1 文件上传漏洞审计
1.1 漏洞原理介绍
大部分文件上传漏洞的产生是因为Web应用程序未对文件的格式和进行严格过滤导致用户可上传jsp、php等webshell代码文件从而被利用。例如在 BBS发布图片 , 在个人网站发布ZIP压缩包, 在办公平台发布DOC文件等 , 只要 Web应用程序允许上传文件, 就有可能存在文件上传漏洞。
1.2 审计策略 文件上传可以搜索以下关键词 uploadwrite,fileName ,filePath 在查看时主要判断是否有检查后缀和文件的大小 同时要查看配置文件是否有设置白名单或者黑名单不推荐黑名单可能被绕过
1.3 修复方案 通过后端增加对上传文件后缀格式的验证验证的手段有两种分别是白名单校验和黑名单校验 推荐使用白名单校验绕过的危险小黑名单无法维护全面极容导致绕过校验成功上传脚本文件 只允许文件上传到固定目录且设置程序对该目录下只有读写权限不得具有执行权限 推荐存储文件的服务器和应用服务器相互独立 上传成功的文件不得真实的存储路径回显给前端但是对于我想下载禁止直接使用完整的路径【为了防止直接暴露真实路径到前端】应该通过key到服务端或数据库中找到真实的路径下载即可 必要的时候需要重命名文件名最合理的一定是后端生成的文件的目录
1.4 审计案例
1.4.1 无任何过滤
服务端脚本语言未对上传的文件进行任何限制和过滤导致恶意用户上传任意文件。 form action/file/upload01 methodpost enctypemultipart/form-datainput typefile nameuploadfile input typesubmit/form
上传文件的后端处理基于Spring Boot
package com.ms08067.fileupload.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
Controller
RequestMapping(/file)
public class FileUploadController {/*** 未对上传文件进行任何安全处理* param file* return*/PostMapping(/upload01)public String uploadFile01(RequestParam(uploadfile) MultipartFile file) {//获取文件名String filename file.getOriginalFilename();//文件保存路径
// String path /;File outfile new File(D:\\20230222filename);try {file.transferTo(outfile);} catch (IOException e) {e.printStackTrace();}return success;}}
上述代码未对上传的文件进行任何检测可以上传任意类型的文件包括exe文件和木马等。
运行页面如下 成功上传后 1.4.2 客户端检测
JS对文件后缀名检测绕过
通过前端js检测文件名是否合法没有任何意义因为任意用户都可以对前端js进行任意修改或者通过burp suite抓包修改上传的文件名。
以下代码限制上传文件的后缀名必须为.jpg和.png
form action/file/upload02 methodpost οnsubmitreturn judge() enctypemultipart/form-datainput typefile nameuploadfile idcheckfile input typesubmit value提交p idmsg/p
/form
script typetext/javascript
function judge(){var filedocument.getElementById(checkfile).value;if (filenull||file){alert(请选择要上传的文件);// location.reload(true);return false;}var isnextfalse;var filetypes[.jpg,.png];var fileendfile.substring(file.lastIndexOf(.));for (var i0;ifiletypes.length;i){if (filetypes[i]fileend){isnexttrue;break;}}if (!isnext){document.getElementById(msg).innerHTML文件类型不允许;
// location.reload(true);return false;
}else {return true;}
}
/script
后端没有进行任何限制将文件存储在src\main\resources\static\upload下 import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;/*** 前端通过JS进行文件名称限制* param file* return*/PostMapping(/upload02)public String uploadFile02(RequestParam(uploadfile) MultipartFile file) {String filename file.getOriginalFilename();String path D:\\20230222;File fileDir new File(path);File outfile new File(fileDir.getAbsolutePath()File.separator filename);try {file.transferTo(outfile);}catch (IOException e){e.printStackTrace();}
return success;}
绕过js检测方法一修改前端代码删除js检测部分或者禁用js 绕过js检测方法二使用代理Burp Suite上传文件;上传符合要求的文件类型抓包修改文件类型。例
如要上传1.jsp先将文件名改为1.jpg上传抓包再修改为1.jsp即可。 成功上传 1.4.3 服务端检测绕过
1.4.3.1 服务器端后缀名检测绕过
主要通过黑白名单进行过滤如果不符合过滤规则则不允许上传
一般有个专门的 blacklist 文件里面会包含常见的危险脚本文件后缀名。
1.4.3.2 大小写绕过
以下后端代码检测上传的文件的后缀名是否符合要求不允许上
传.jsp,.php,.exe,.dll,vxd,html结尾的文件可通过将文件后缀大写进行绕过
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
//基于黑名单大小写绕过的文件上传PostMapping(/upload03)public String uploadFile03(RequestParam(uploadfile)MultipartFile file, Model model){boolean flagtrue;String filename file.getOriginalFilename();System.out.println(filename);String suffixfilename.substring(filename.lastIndexOf(.));String[] blacklist{.jsp,.php,.exe,.dll,vxd,html};//后缀名黑名单for (String s : blacklist) {if (suffix.equals(s)){flagfalse;break;}}if (flag){String pathD:\\20230222;File fileDir new File(path);File outfile new File(fileDir.getAbsolutePath()File.separator filename);try {file.transferTo(outfile);return success;}catch (IOException e){e.printStackTrace();}
}else {model.addAttribute(msg,非法文件类型);}return index;}
通过大小写上传 上述黑名单仅过滤了少数后缀名可以上传其他后缀类型的恶意文件。
可利用Burp suite截断HTTP请求利用Intruder模块进行枚举后缀名寻找黑名单中没有过滤的后缀名。接收HTTP请求send to intruder选中变量在Payloads中加载相应的字典。
1.4.3.3 双写绕过
以下代码判断文件后缀名是否存在黑名单中的字符若存在则将对应的字符串替换为空
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
//基于双写绕过的文件上传如果后缀名为非法的字符将替换成空修复大小写绕过PostMapping(/upload04)public String uploadFile04(RequestParam(uploadfile)MultipartFile file){String filename file.getOriginalFilename();System.out.println(filename);String preFilenamefilename.substring(0,filename.lastIndexOf(.));String suffixfilename.substring(filename.lastIndexOf(.)).toLowerCase();String[] blacklist{jsp,php,exe,dll,vxd,html};//后缀名黑名单for (String s : blacklist) {if (suffix.indexOf(s)!-1){suffixsuffix.replace(s,);//后缀存在黑名单字符串则将字符串替换为空}}String pathD:\\20230222;File fileDir new File(path);File outfile new File(fileDir.getAbsolutePath()File.separator preFilenamesuffix);try {file.transferTo(outfile);return success;}catch (IOException e){e.printStackTrace();}return index;}
可通过双写后缀名进行绕过例如上传4.jjspsp文件过滤掉jsp后文件名正好是我们想要上传的 1.4.3.4 双后缀名绕过
以下代码后端判断后缀名使用的是filename.indexOf(.)而不是filename.lastIndexOf(.)
可通过双后缀名绕过检测例如欲上传1.jsp可将文件名改为1.jsp.jsp这样后端获得的后缀名
为.jsp.jsp可通过检测。 //文件后缀名双写绕过-未修复大小写绕过PostMapping(/upload05)public String uploadFile05(RequestParam(uploadfile)MultipartFile file,Model model){boolean flagtrue;String filename file.getOriginalFilename();System.out.println(filename);String suffixfilename.substring(filename.indexOf(.));String[] blacklist{.jsp,.php,.exe,.dll,.vxd,.html};//后缀名黑名单for (String s : blacklist) {if (suffix.equals(s)){flagfalse;break;
}}if (flag){String pathD:\\20230222;File fileDir new File(path);File outfile new File(fileDir.getAbsolutePath()File.separator filename);try {file.transferTo(outfile);return success;}catch (IOException e){e.printStackTrace();}
}else {model.addAttribute(msg,非法文件类型);
}return index;
} 上传不符合windows文件命名规则的文件名
上述代码可以通过抓包修改文件名为如下形式 点绕过1.jsp. 空格绕过1.jsp(空格) 1.jsp:1.jpg 1.jsp::$DATA
1.4.4 白名单检测
在jdk低版本1.7及以下中可以使用%00截断。图片木马
1.4.4.1 MIME类型检测绕过
以下代码限制上传文件的MIME类型需为image/jpeg,image/png或image/gif可通过抓包
修改Content-Type为合法类型绕过MIME类型检测 PostMapping(/upload07)public String uploadFile07(RequestParam(uploadfile)MultipartFile file,Model model){boolean flagfalse;String filename file.getOriginalFilename();String contentType file.getContentType();System.out.println(filename);String preFilenamefilename.substring(0,filename.lastIndexOf(.));String suffixfilename.substring(filename.lastIndexOf(.)).toLowerCase();//基于文件头类型进行白名单校验String[] whiteList{image/jpeg,image/png,image/gif};for (String s : whiteList) {if (contentType.equals(s)){flagtrue;}}if (flag){String pathD:\\20230222;File fileDir new File(path);File outfile new File(fileDir.getAbsolutePath()File.separator filename);try {file.transferTo(outfile);return success;}catch (IOException e){e.printStackTrace();}
}else {model.addAttribute(msg,非法文件类型);}return index;}
例如上传1.jsp文件可修改Content-Type值为 image/jpeg 1.4.4.2 文件头检测绕过
根据文件的前面几个字节即常说的魔术数字进行判断不同文件类型的开头几个字节不同。
常见文件头 以下代码通过检测文件头部分判断上传的文件是否为图片可利用如下两种方法绕过
package com.ms08067.fileupload.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
Controller
RequestMapping(/file1)
public class FileUploadController1 {public final static MapString,String FileTypenew HashMapString,String();static {getAllFileType();//初始化文件类型信息}PostMapping(/upload)public static String upload(RequestParam(uploadfile) MultipartFile file, Model model){String filename file.getOriginalFilename();boolean flagfalse;byte[] bnew byte[50];try {InputStream inputStream file.getInputStream();inputStream.read(b);System.out.println(b.toString());StringBuilder stringBuildernew StringBuilder();if (bnull ||b.length0){flagfalse;}for (int i 0; i b.length; i) {int vb[i]0xff;String hvInteger.toHexString(v);//十六进制stringBuilder.append(hv);}System.out.println(stringBuilderstringBuilder.toString());String fileTypeHex String.valueOf(stringBuilder.toString());IteratorMap.EntryString, String iterator FileType.entrySet().iterator();while (iterator.hasNext()){//判断文件前几个字节是否为FileType中三种类型之一Map.EntryString, String next iterator.next();System.out.println(fileTypeHex.toUpperCase(Locale.ROOT));if (fileTypeHex.toUpperCase(Locale.ROOT).startsWith(next.getValue())){flagtrue;}
}
inputStream.close();}catch (FileNotFoundException e){e.printStackTrace();}catch (IOException e){e.printStackTrace();
}
if (flag){String pathD:\\20230222;File fileDir new File(path);File outfile new File(fileDir.getAbsolutePath()File.separator filename);try {file.transferTo(outfile);return success;}catch (IOException e){e.printStackTrace();}
}else {model.addAttribute(msg,非法文件类型);
}return index;
}private static void getAllFileType(){FileType.put(jpeg,FFD8FF);FileType.put(png,89504E47);FileType.put(gif,47494638);FileType.put(jpg,GIF89a);}}
1.4.4.3 添加合法文件头绕过
通过抓包添加合法文件头例如GIF89ajpg格式文件头 上传两个注意事项
1编码前空格、编码上边空一行 1.4.4.4 制作图片木马绕过
copy 2.jpg/b1.jsp 3.jpg或者使用记事本等软件打开图片在末尾添加jsp木马数据将攻击脚本隐藏到图片中。
单纯的图片马并不能直接和蚁剑连接因为该文件依然是以image格式进行解析需要结合文件包含漏洞
1.4.4.5 ImageIO判断上传图片文件
通过ImageReader解码file并返回一个BufferedImage对象如果找不到合适的ImageReader则会返回null我们可以认为这不是图片文件。
如果能够正常的获取到一张图片的宽高属性那么该文件一定是图片因为非图片文件获取不到它的宽高属性的。
但若是在可以正常打开的图片里面加入非法代码或者病毒那就非常危险了
Controller
public class UploadImg {
//ImageIO判断上传的文件是否为图片
PostMapping(/upload)
public static String uploadImg(RequestParam(uploadfile)MultipartFile file , Model model){
boolean flagfalse;
String filename file.getOriginalFilename();
String suffix filename.substring(filename.lastIndexOf(.));
String pathsrc\\main\\resources\\static\\upload;
File fileDir new File(path);
File outfile new File(fileDir.getAbsolutePath()File.separator filename);
String[] whiteList{.jpg,.png};
for (String s : whiteList) {
if (suffix.toLowerCase(Locale.ROOT).equals(s)){
flagtrue;
break;
}
}
File tmpFilenull;
if (flag){
tmpFile new File(System.getProperty(java.io.tmpdir), filename);
try{
file.transferTo(tmpFile);
BufferedImage read ImageIO.read(tmpFile);
read.getWidth();
read.getHeight();
}catch (Exception e){
e.printStackTrace();
flagfalse;
}finally {
if (flag){
try {
FileCopyUtils.copy(new FileInputStream(tmpFile),
Files.newOutputStream(Paths.get(path,filename), StandardOpenOption.CREATE_NEW));tmpFile.delete();
return success;
}catch (FileNotFoundException e){
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}else {
model.addAttribute(msg,请上传图片文件);
}
}
}else {
model.addAttribute(msg,文件后缀名不符合要求);
}
return index;
}
}1.5 文件上传漏洞总结
文件上传漏洞的原因 未对文件做任何过滤可上传任意文件类型如木马、可执行文件等 仅在js端检验文件后缀可通过删除js或禁用js或抓包修改文件后缀等方法绕过 后端后缀过滤使用黑名单过滤不全可通过使用未过滤的后缀名、大小写变换、双写后缀名、双后缀名、文件名结尾加”.“或空格、%00截断等方式绕过 后端判断文件类型只判断Content-type可通过抓包修改Content-type字段的值进行绕过 后端检查文件内容仅检查文件头内容可通过抓包添加合法文件头或使用其他工具添加合法文件头进行绕过。
1.6 文件上传漏洞修复 服务器端的检查最好使用白名单过滤的方法黑名单极不可靠 使用随机数**改写文件名和文件路径**。文件上传如果要执行代码需要用户能够访问到这个文件。应用了随机数改写了文件名和路径可防止大小写绕过、双后缀、多后缀等手段将极大地增加攻击的成本 文件上传目录设置为不可执行只要web容器无法解析该目录下面的文件即使攻击者上传了脚本文件服务器本身也不会受到影响。 使用安全设备防御恶意文件千变万化隐藏手法也不断推陈出新对普通的系统管理员来说可以通过部署安全设备来帮助防御。