01
文件上传漏洞原理
在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户上传恶意的脚本文件时,就有可能获取执行服务端命令的能力,这就是文件上传漏洞。
02
文件上传漏洞触发点
相册、头像上传、视频、照片分享、附件上传(论坛发帖、邮箱)、文件管理器等。
03
文件上传漏洞的形成条件
文件能够通过前端和后端过滤和文件处理
文件内容不会改变,能够被正确存储
存储位置在Web容器控制范围内
攻击者有权限访问存储目录并有权执行文件
只要破坏了其中的任一条件即可防止文件上传漏洞。
04
文件上传漏洞常见防御方法
0.无防护
以下代码实现了一个简单的文件上传功能
index.html
1
上传文件的后端处理,基于Spring Boot
1package com.example.fileuploadvul.Controller;
2
3import org.springframework.stereotype.Controller;
4import org.springframework.web.bind.annotation.PostMapping;
5import org.springframework.web.bind.annotation.RequestParam;
6import org.springframework.web.multipart.MultipartFile;
7
8import java.io.File;
9import java.io.IOException;
10
11@Controller
12public class UploadFile {
13 @PostMapping("/upload")
14 public String uploadFile(@RequestParam("uploadfile")MultipartFile file){
15//获取文件名
16 String filename = file.getOriginalFilename();
17 //文件保存路径
18 String path="F:\tmp\";
19 File outfile = new File(path + filename);
20 try {
21 file.transferTo(outfile);
22 }catch (IOException e){
23 e.printStackTrace();
24 }
25 return "success";
26 }
27}
上面的代码没有任何的防护功能,存在文件上传漏洞。用户可以随意的上传任何文件、木马。
1.前端进行js校验
增加攻击成本,该种方式容易被绕过。
javascript示例:
1
6
绕过php:
1
同时绕过:
1
6.对文件的处理逻辑。
若先将文件放入路径,再去检验文件合法性并删除,会存在条件竞争漏洞。
6.1示例:
1if(isset($_POST['submit'])){
2 $ext_arr = array('jpg','png','gif');
3 $file_name = $_FILES['upload_file']['name'];
4 $temp_file = $_FILES['upload_file']['tmp_name'];
5 $file_ext = substr($file_name,strrpos($file_name,".")+1);
6 $upload_file = UPLOAD_PATH . '/' . $file_name;
7
8 if(move_uploaded_file($temp_file, $upload_file)){
9 if(in_array($file_ext,$ext_arr)){
10 $img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
11 rename($upload_file, $img_path);
12 $is_upload = true;
13 }else{
14 $msg = "只允许上传.jpg|.png|.gif类型文件!";
15 unlink($upload_file);
16 }
17 }else{
18 $msg = '上传出错!';
19 }
20}
先用move_uploaded_file 将上传的文件移动到上传目录,再判断后缀名并就删除文件。
我们多线程异步上传文件A并不断地访问自己上传的文件A,可以文件A进行删除之前,成功执行文件A,
若文件A代码为:
1');?>
则执行成功可以生成稳定的shell.php
解决方案:经过充分完整的检查之后再上传。
7.禁止上传文件被执行
7.1存储服务器
将存储上传文件的位置设计在另一台只具备存储功能的文件服务器或数据库上,与Web应用服务器分开,这样即使木马被上传进来,也因为文件服务器不能执行脚本而没有办法实施攻击。
7.2设置权限
改存储上传文件的目录的执行脚本的权限。如linux系统下使用chmod命令修改目录的rwx权限。
7.3修改配置
修改.htaccess、apache的httpd.conf配置文件、Nginx增加配置
7.3.1 .htaccess
1
2Order allow,deny
3Deny from all
4
7.3.2 修改apache的配置文件httpd.conf
1
2
3 Order allow,deny
4 Deny from all
5
6
7.4 隐藏上传文件路径
示例:使用blob把网站上的全部图片链接加密。
后台返回图片:
1protected void Page_Load(object sender, EventArgs e)
2 {
3 string url = Server.MapPath("~/Images/abg.jpg");
4 Bitmap b = new Bitmap(url);
5 MemoryStream ms = new MemoryStream();
6 b.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
7 Response.ClearContent();
8 Response.ContentType = "image/Jpg";
9 Response.BinaryWrite(ms.ToArray());
10 }
JavaScript代码:
1
2
回到网页查看img标签src的地址:
8.文件二次渲染
1$is_upload = false;
2$msg = null;
3if (isset($_POST['submit'])){
4 // 获得上传文件的基本信息,文件名,类型,大小,临时文件路径
5 $filename = $_FILES['upload_file']['name'];
6 $filetype = $_FILES['upload_file']['type'];
7 $tmpname = $_FILES['upload_file']['tmp_name'];
8
9 $target_path=UPLOAD_PATH.basename($filename);
10
11 // 获得上传文件的扩展名
12 $fileext= substr(strrchr($filename,"."),1);
13
14 //判断文件后缀与类型,合法才进行上传操作
15 if(($fileext == "jpg") && ($filetype=="image/jpeg")){
16 if(move_uploaded_file($tmpname,$target_path))
17 {
18 //使用上传的图片生成新的图片
19 $im = imagecreatefromjpeg($target_path);
20
21 if($im == false){
22 $msg = "该文件不是jpg格式的图片!";
23 @unlink($target_path);
24 }else{
25 //给新图片指定文件名
26 srand(time());
27 $newfilename = strval(rand()).".jpg";
28 $newimagepath = UPLOAD_PATH.$newfilename;
29 imagejpeg($im,$newimagepath);
30 //显示二次渲染后的图片(使用用户上传图片生成的新图片)
31 $img_path = UPLOAD_PATH.$newfilename;
32 @unlink($target_path);
33 $is_upload = true;
34 }
35 } else {
36 $msg = "上传出错!";
37 }
38
39 }else if(($fileext == "png") && ($filetype=="image/png")){
40 if(move_uploaded_file($tmpname,$target_path))
41 {
42 //使用上传的图片生成新的图片
43 $im = imagecreatefrompng($target_path);
44
45 if($im == false){
46 $msg = "该文件不是png格式的图片!";
47 @unlink($target_path);
48 }else{
49 //给新图片指定文件名
50 srand(time());
51 $newfilename = strval(rand()).".png";
52 $newimagepath = UPLOAD_PATH.$newfilename;
53 imagepng($im,$newimagepath);
54 //显示二次渲染后的图片(使用用户上传图片生成的新图片)
55 $img_path = UPLOAD_PATH.$newfilename;
56 @unlink($target_path);
57 $is_upload = true;
58 }
59 } else {
60 $msg = "上传出错!";
61 }
62
63 }else if(($fileext == "gif") && ($filetype=="image/gif")){
64 if(move_uploaded_file($tmpname,$target_path))
65 {
66 //使用上传的图片生成新的图片
67 $im = imagecreatefromgif($target_path);
68 if($im == false){
69 $msg = "该文件不是gif格式的图片!";
70 @unlink($target_path);
71 }else{
72 //给新图片指定文件名
73 srand(time());
74 $newfilename = strval(rand()).".gif";
75 $newimagepath = UPLOAD_PATH.$newfilename;
76 imagegif($im,$newimagepath);
77 //显示二次渲染后的图片(使用用户上传图片生成的新图片)
78 $img_path = UPLOAD_PATH.$newfilename;
79 @unlink($target_path);
80 $is_upload = true;
81 }
82 } else {
83 $msg = "上传出错!";
84 }
85 }else{
86 $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
87 }
88}
绕过方法:
对比上传前后的两个文件,找到没有变动的区域,插入php代码。
《黑客&网络安全入门&进阶学习资源包》分享 (qq.com)
参考文章:
1https://wiki.wgpsec.org/knowledge/ctf/uploadfile.html
2
3https://blog.csdn.net/cldimd/article/details/104992488
4
5https://github.com/c0ny1/upload-labs
6
7https://juejin.cn/post/6989580413333159949
8
9https://blog.csdn.net/liguangyao213/article/details/123430199
10
11https://blog.csdn.net/qq_43277152/article/details/113373721
12
13https://blog.csdn.net/qq_45570082/article/details/108910162
14
15https://xz.aliyun.com/t/3941
16
17https://blog.csdn.net/weixin_64551911/article/details/124627363?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-124627363-blog-105068212.pc_relevant_recovery_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-124627363-blog-105068212.pc_relevant_recovery_v2&utm_relevant_index=5
18
19等。