一、前言
1、漏洞原理
大部分的网站和应用系统都有上传功能,而程序员在开发文件上传功能时,并未考虑文件格式后缀的合法性校验或者是否只在前端通过js进行后缀检验。
这时攻击者可以上传一个与网站脚本语言相对应的恶意代码动态脚本,例如(jsp、asp、php、aspx文件后缀)到服务器上,从而访问这些恶意脚本中包含的恶意代码,进行动态解析最终达到执行恶意代码的效果,进一步影响服务器安全。
文件上传漏洞是指用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力。一般都是指“上传Web脚本能够被服务器解析”的问题。
2、漏洞危害
可能会导致用户信息泄露,被钓鱼,甚至使攻击者可以直接上传WebShell到服务器,进而得到自己想要的信息和权限。最终达到对数据库执行、服务器文件管理、服务器命令执行等恶意操作,甚至完全控制服务器系统。
webshell:运行在web应用之上的远程控制程序 。 webshell分为大马、小马等。功能简易的webshell称为小马,拥有较完整功能的webshell,称为大马。
3、漏洞利用
文件上传漏洞利用条件:
(1)能够成功上传木马。
(2)上传的木马能够被web容器解析执行,所以上传路径要在web容器覆盖范围内。
(3)用户能够访问上传的木马,所以得知道上传的木马准确路径。
4、文件上传攻击满足条件
为实现一次攻击利用,必须满足以下条件:
- 文件能够通过前端和后端过滤和文件处理
- 文件内容不会改变,能够被正确存储
- 存储位置在Web容器控制范围内
- 攻击者有权限访问存储目录
文件上传漏洞高危触发点:
存在文件上传功能的地方都有可能存在文件上传漏洞,如:
- 相册、头像上传
- 视频、照片分享
- 附件上传(论坛发帖、邮箱)
- 文件管理器
文件上传漏洞类型如图所示:
二、文件上传漏洞
1、无任何过滤
服务端脚本语言未对上传的文件进行任何限制和过滤,导致恶意用户上传任意文件。
2、文件上传客户端检测绕过
2.1 JS对文件后缀名检测绕过
通过前端js检测文件名是否合法没有任何意义,因为任意用户都可以对前端js进行任意修改或者通过burp suite抓包修改上传的文件名。
客户端JavaScript检测
开发者在前端使用JavaScript做了白名单验证,如果文件名不符合规则那么就不允许被上传
绕过方式:
绕过js检测方法一:修改前端代码,删除js代码检测部分,或者禁用js代码
绕过js检测方法二:使用代理Burp Suite上传文件;上传符合要求的文件类型,抓包修改文件类型。例如要上传1.jsp,先将文件名改为1.jpg,上传,抓包,再修改为1.jsp即可。 使用火狐插件禁用JavaScript代码:
3、 服务端检测绕过
3.1 服务器端后缀名检测绕过
主要通过黑白名单进行过滤,如果不符合过滤规则,则不允许上传
一般有个专门的 blacklist 文件,里面会包含常见的危险脚本文件后缀名。
绕过方式:
首先将木马文件改为规则的后缀名,通过burp suite抓包,如果头文件中含有文件名以及存储路径。将路径改为xx.php后面跟%00,文件名不变。
那么在存储路径和文件名拼接时%00及以后的信息将被丢弃。即符合白名单验证,文件又会被存储为xx.php。
注:在jdk低版本(1.7及以下)中可以使用%00截断。
![](/i/l/?n=22&i=blog/782175/202211/782175-20221101151819839-663361613.png)
3.2、 大小写绕过
检测上传的文件的后缀名是否符合要求,不允许上传".jsp",".php",".exe",".dll","vxd","html"结尾的文件,可通过将文件后缀大写进行绕过。
3.3、黑名单漏网之鱼
黑名单仅过滤了少数后缀名,可以上传其他后缀类型的恶意文件。
可利用Burp suite截断HTTP请求,利用Intruder模块进行枚举后缀名,寻找黑名单中没有过滤的后缀名。接收HTTP请求,send to intruder,选中变量,在Payloads中加载相应的字典。
3.4、 双写绕过
以下代码判断文件后缀名是否存在黑名单中的字符,若存在则将对应的字符串替换为空
@Controller public class UploadFile { @PostMapping("/upload") public String uploadFile(@RequestParam("uploadfile")MultipartFile file){ String filename = file.getOriginalFilename(); System.out.println(filename); String preFilename=filename.substring(0,filename.lastIndexOf(".")); String suffix=filename.substring(filename.lastIndexOf(".")); String[] blacklist={"jsp","php","exe","dll","vxd","html"};//后缀名黑名单 for (String s : blacklist) { if (suffix.indexOf(s)!=-1){ suffix=suffix.replace(s,"");//后缀存在黑名单字符串,则将字符串替换为空 } } String path="src\\main\\resources\\static\\upload"; File fileDir = new File(path); File outfile = new File(fileDir.getAbsolutePath()+File.separator + preFilename+suffix); try { file.transferTo(outfile); return "success"; }catch (IOException e){ e.printStackTrace(); } return "index"; } }
可通过双写后缀名进行绕过,例如上传1.jjspsp文件,过滤掉jsp后,文件名正好是我们想要上传的。
3.5、 双后缀名绕过
以下代码,后端判断后缀名使用的是filename.indexOf("."),而不是filename.lastIndexOf("."),可通过双后缀名绕过检测,例如欲上传1.jsp,可将文件名改为1.jsp.jsp,这样后端获得的后缀名为.jsp.jsp,可通过检测。
@Controller public class UploadFile { @PostMapping("/upload") public String uploadFile(@RequestParam("uploadfile")MultipartFile file,Model model){ boolean flag=true; String filename = file.getOriginalFilename(); System.out.println(filename); String suffix=filename.substring(filename.indexOf(".")); String[] blacklist={".jsp",".php",".exe",".dll",".vxd",".html"};//后缀名黑名单 for (String s : blacklist) { if (suffix.equals(s)){ flag=false; break; } } if (flag){ String path="src\\main\\resources\\static\\upload"; 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"; } }
3.6、上传不符合windows文件命名规则的文件名
可利用Burp suite截断HTTP请求,修改文件名为如下形式:
- 点绕过1.jsp.
- 空格绕过1.jsp(空格)
- 1.jsp:1.jpg
- 1.jsp::$DATA
3.7、MIME类型检测绕过
MIME类型用来设定某种扩展名文件的打开方式,当具有该扩展名的文件被访问时,浏览器会自动使用指定的应用程序来打开。上传文件时可以通过服务端对上传文件的MIME类型进行判断。
绕过方式:
通过burp suite抓包修改Content-Type字段改为:Content-Type: image/jpeg
3.8、服务端文件头检测
文件头检测是在文件上传时取文件的前2个字节进行特征对比。
木马文件直接更改后缀名可以通过服务端白名单检测,但是无法绕过文件头检测。
常见文件头:
文件类型 | 文件头 |
JPEG (jpg) | FFD8FF |
PNG (png) | 89504E47 |
GIF (gif) | 47494638 |
ZIP Archive (zip) | 504B0304 |
RAR Archive (rar) | 52617221 |
@Controller public class UploadFile2 { public final static Map<String,String> FileType=new HashMap<String,String>(); static { getAllFileType();//初始化文件类型信息 } @PostMapping("/upload") public static String upload(@RequestParam("uploadfile")MultipartFile file,Model model){ String filename = file.getOriginalFilename(); boolean flag=false; byte[] b=new byte[50]; try { InputStream inputStream = file.getInputStream(); inputStream.read(b); System.out.println(b.toString()); StringBuilder stringBuilder=new StringBuilder(); if (b==null ||b.length<0){ flag=false; } for (int i = 0; i < b.length; i++) { int v=b[i]&0xff; String hv=Integer.toHexString(v);//十六进制 stringBuilder.append(hv); } System.out.println(stringBuilder.toString()); String fileTypeHex = String.valueOf(stringBuilder.toString()); Iterator<Map.Entry<String, String>> iterator = FileType.entrySet().iterator(); while (iterator.hasNext()){//判断文件前几个字节是否为FileType中三种类型之一 Map.Entry<String, String> next = iterator.next(); if (fileTypeHex.toUpperCase(Locale.ROOT).startsWith(next.getValue())){ flag=true; } } inputStream.close(); }catch (FileNotFoundException e){ e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); } if (flag){ String path="src\\main\\resources\\static\\upload"; 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"); } }
3.8.1 添加合法文件头绕过
通过抓包,添加合法文件头,例如CIF89a(jpg格式文件头)
标签:文件,String,十一,后缀名,漏洞,jsp,File,上传 From: https://www.cnblogs.com/uestc2007/p/16847848.html