0


文件上传漏洞(思路,绕过,修复)

文件上传漏洞:

1.思维导图

在这里插入图片描述
在这里插入图片描述

2.上传思路

在这里插入图片描述

3.概念

在这里插入图片描述

4.绕过

文件上传常见验证:
后缀名,类型、文件头等。

  • 后缀名:黑名单、白名单(phtml/php4,双写,空字节,双扩展等等)
  • 文件类型:MIME信息(抓包修改)
  • 文件头:内容头信息(修改文件头)

方法:查看源码、抓包修改包信息

%00截断:可以把这个放在文件名内,绕过检测。可见upload-labs-Less11、12关,修改的是文件路径上(url)的,而非文件名上截断。
get传输:会自动解码。
post传输:不会自动解码。
所以想以post提交数据%00需要把它进行url编码变成%25%30%30,或直接在burp中改十六进制为00,%00对应的十六进制为20改为00。

在这里插入图片描述
5.
在这里插入图片描述
6.

靶场

老版靶场:

upload-labs通关指南

新版靶场:

upload-labs练习文件上传靶场

内容/逻辑/数组绕过

在这里插入图片描述

1)cmd制作图片马,这样不会损坏文件:

copy 1.png /b + shell.php /a webshell.jpg

2)
Pass-15-getimagesize()函数-图片马,该函数会验证返回图片信息,若不是图片则会返回为空,之后代码也就不会执行,所以必须上传图片。

Pass-16-exif_imagetype()函数-图片马

两者都是判断文件类型的函数,可以图片马绕过,攻击方式同pass-14.

3)二次渲染/条件竞争:

1.逻辑安全=二次渲染:指的是网站接受目标后会再进行操作,也就是说会对文件进行二次操作(比如缩略图和头像框都被渲染过),其中的php代码可能会被渲染掉,主要是imagecreatefromjpeg()函数 ! upload-labs-Less-17
2.逻辑安全-条件竞争:有的网站会对上传的文件进行上传后再验证(上传过程不进行验证),这样文件会暂时保存到服务器上,可以趁程序未对此文件进行操作(例如改名,移位等),访问文件进行占用,产生条件竞争。 upload-labs-Less-18

4)Less-17源码:

$is_upload=false;$msg=null;if(isset($_POST['submit'])){// 获得上传文件的基本信息,文件名,类型,大小,临时文件路径$filename=$_FILES['upload_file']['name'];$filetype=$_FILES['upload_file']['type'];$tmpname=$_FILES['upload_file']['tmp_name'];$target_path=UPLOAD_PATH.'/'.basename($filename);// 获得上传文件的扩展名$fileext=substr(strrchr($filename,"."),1);//判断文件后缀与类型,合法才进行上传操作if(($fileext=="jpg")&&($filetype=="image/jpeg")){//if与else if语句分别判断是否为三种图片类型if(move_uploaded_file($tmpname,$target_path)){//将客户端生成的临时文件移动到服务器指定文件目录下$im=imagecreatefromjpeg($target_path);//使用上传的图片生成新的图片,新的图层,这是二次渲染的关键。if($im==false){$msg="该文件不是jpg格式的图片!";
                @unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename=strval(rand()).".jpg";$img_path=UPLOAD_PATH.'/'.$newfilename;//显示二次渲染后的图片并在html中打印(使用用户上传图片生成的新图片)imagejpeg($im,$img_path);//php输出jpg图片文件函数
                @unlink($target_path);//删除文件$is_upload=true;}}else{$msg="上传出错!";}}elseif(($fileext=="png")&&($filetype=="image/png")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im=imagecreatefrompng($target_path);if($im==false){$msg="该文件不是png格式的图片!";
                @unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename=strval(rand()).".png";//显示二次渲染后的图片(使用用户上传图片生成的新图片)$img_path=UPLOAD_PATH.'/'.$newfilename;imagepng($im,$img_path);

                @unlink($target_path);$is_upload=true;}}else{$msg="上传出错!";}}elseif(($fileext=="gif")&&($filetype=="image/gif")){if(move_uploaded_file($tmpname,$target_path)){//使用上传的图片生成新的图片$im=imagecreatefromgif($target_path);if($im==false){$msg="该文件不是gif格式的图片!";
                @unlink($target_path);}else{//给新图片指定文件名srand(time());$newfilename=strval(rand()).".gif";$img_path=UPLOAD_PATH.'/'.$newfilename;imagegif($im,$img_path);

                @unlink($target_path);$is_upload=true;}}else{$msg="上传出错!";}}else{$msg="只允许上传后缀为.jpg|.png|.gif的图片文件!";}}

二次渲染的利用参考这篇博客

5)Less-18源码:

$is_upload=false;$msg=null;if(isset($_POST['submit'])){$ext_arr=array('jpg','png','gif');$file_name=$_FILES['upload_file']['name'];$temp_file=$_FILES['upload_file']['tmp_name'];//上传图片时在客户端生成的临时文件,在php.ini中可以设定关于上传文件的配置。$file_ext=substr($file_name,strrpos($file_name,".")+1);//截取到文件后缀$upload_file=UPLOAD_PATH.'/'.$file_name;if(move_uploaded_file($temp_file,$upload_file)){//将客户端生成的临时文件移动到服务器指定文件目录下if(in_array($file_ext,$ext_arr)){//再次截取文件名后缀并与数组对比验证是否为图片$img_path=UPLOAD_PATH.'/'.rand(10,99).date("YmdHis").".".$file_ext;rename($upload_file,$img_path);$is_upload=true;}else{$msg="只允许上传.jpg|.png|.gif类型文件!";unlink($upload_file);//删除图片}}else{$msg='上传出错!';}}

我们知道若系统占用某文件时是无法删除或重命名的,此处为判断文件后缀是否在白名单里,如果在则重命名,否则删除。因此我们可以不断上传不断访问(burp的intruder模块),总会出现刚好上传且被刚好被访问的情况,此时php函数是无法对我们上传的文件进行重命名或删除的。由于是先上传成功后才会对文件进行检验,可以上传php文件!因此此处存在逻辑漏洞,这就是条件竞争的原理存在的漏洞可能不是二次渲染的漏洞,而是逻辑上可以将文件上传到服务器并条件竞争来读取,存在逻辑漏洞

在这里插入图片描述
在这里插入图片描述
6)Less-19源码:

//index.php$is_upload=false;$msg=null;if(isset($_POST['submit'])){require_once("./myupload.php");$imgFileName=time();$u=newMyUpload($_FILES['upload_file']['name'],$_FILES['upload_file']['tmp_name'],$_FILES['upload_file']['size'],$imgFileName);$status_code=$u->upload(UPLOAD_PATH);switch($status_code){case1:$is_upload=true;$img_path=$u->cls_upload_dir.$u->cls_file_rename_to;break;case2:$msg='文件已经被上传,但没有重命名。';break;case-1:$msg='这个文件不能上传到服务器的临时文件存储目录。';break;case-2:$msg='上传失败,上传目录不可写。';break;case-3:$msg='上传失败,无法上传该类型文件。';break;case-4:$msg='上传失败,上传的文件过大。';break;case-5:$msg='上传失败,服务器已经存在相同名称文件。';break;case-6:$msg='文件无法上传,文件不能复制到目标目录。';break;default:$msg='未知错误!';break;}}//myupload.phpclassMyUpload{..................var$cls_arr_ext_accepted=array(".doc",".xls",".txt",".pdf",".gif",".jpg",".zip",".rar",".7z",".ppt",".html",".xml",".tiff",".jpeg",".png");................../** upload()
   **
   ** Method to upload the file.
   ** This is the only method to call outside the class.
   ** @para String name of directory we upload to
   ** @returns void
  **/functionupload($dir){$ret=$this->isUploadedFile();if($ret!=1){return$this->resultUpload($ret);}$ret=$this->setDir($dir);if($ret!=1){return$this->resultUpload($ret);}$ret=$this->checkExtension();if($ret!=1){return$this->resultUpload($ret);}$ret=$this->checkSize();if($ret!=1){return$this->resultUpload($ret);}// if flag to check if the file exists is set to 1if($this->cls_file_exists==1){$ret=$this->checkFileExists();if($ret!=1){return$this->resultUpload($ret);}}// if we are here, we are ready to move the file to destination$ret=$this->move();if($ret!=1){return$this->resultUpload($ret);}// check if we need to rename the fileif($this->cls_rename_file==1){$ret=$this->renameFile();if($ret!=1){return$this->resultUpload($ret);}}// if we are here, everything worked as planned :)return$this->resultUpload("SUCCESS");}..................};

分析源码后可以在myupload.php看到先是上传文件其次才是检验文件内容,存在逻辑漏洞:

在这里插入图片描述

Less-20源码(可能是%00截断绕过,但我没复现成功):

$is_upload=false;$msg=null;if(isset($_POST['submit'])){if(file_exists(UPLOAD_PATH)){$deny_ext=array("php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");/*
        $file_name = trim($_POST['save_name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        */$file_name=$_POST['save_name'];$file_ext=pathinfo($file_name,PATHINFO_EXTENSION);if(!in_array($file_ext,$deny_ext)){$temp_file=$_FILES['upload_file']['tmp_name'];$img_path=UPLOAD_PATH.'/'.$file_name;if(move_uploaded_file($temp_file,$img_path)){$is_upload=true;}else{$msg='上传出错!';}}else{$msg='禁止保存为该类型文件!';}}else{$msg=UPLOAD_PATH.'文件夹不存在,请手工创建!';}}

虽然可以直接上传php文件,但却会被修改后缀重命名,并且重命名函数处有很强的黑名单数组,显然无法直接重命名为php文件:

在这里插入图片描述

但可以依靠00截断等上边介绍的一些绕过黑名单方法:
在这里插入图片描述
电脑此处不知道啥原因就是上传不上去,显示上传错误不论是%00还是空字节00或者直接加个“.”,都无法上传,很无语…可能是新靶场升级了,此处考的不再是00截断复现不了无法贴自己的图,其实原理跟上边的00截断一样,就是注意post传输url编码问题,参考:
在这里插入图片描述
在这里插入图片描述

其实还有另一种方法:

在这里插入图片描述
当我们倘若上传的文件名不是普通的upload-19.jpg,而是类似一个文件夹类型的:upload-19.php/.

在这里插入图片描述
此时会被当成php文件,上传成功:
在这里插入图片描述

数组绕过,常在ctf比赛中见到,基本是百盒代码审计形式:

$is_upload=false;$msg=null;if(!empty($_FILES['upload_file'])){//检查MIME$allow_type=array('image/jpeg','image/png','image/gif');if(!in_array($_FILES['upload_file']['type'],$allow_type)){$msg="禁止上传该类型文件!";}else{//检查文件名$file=empty($_POST['save_name'])?$_FILES['upload_file']['name']:$_POST['save_name'];if(!is_array($file)){$file=explode('.',strtolower($file));//对file进行分割将file变为一个数组,之后利用end函数将file数组的最后一个单位赋值给$ext}$ext=end($file);$allow_suffix=array('jpg','png','gif');if(!in_array($ext,$allow_suffix)){$msg="禁止上传该后缀文件!";}else{$file_name=reset($file).'.'.$file[count($file)-1];//数组绕过的关键$temp_file=$_FILES['upload_file']['tmp_name'];$img_path=UPLOAD_PATH.'/'.$file_name;if(move_uploaded_file($temp_file,$img_path)){$msg="文件上传成功!";$is_upload=true;}else{$msg="文件上传失败!";}}}}else{$msg="请选择要上传的文件!";}

这个题无法再次用上边那个伪造文件夹上传php操作,因为有了该结构过滤:

$ext=end($file);//会截取我们的php/.并查看是否是数组里的白名单的这三个$allow_suffix=array('jpg','png','gif');if(!in_array($ext,$allow_suffix)){$msg="禁止上传该后缀文件!";}

此处是白名单,众所周知,白名单比黑名单更安全但也更难绕过。但正是因为截取末尾的后缀,那我们可不可以再在末尾再拼接个jpg后缀呢?
在这里插入图片描述
最重要的就是这三个:

$file=explode('.',strtolower($file));$ext=end($file);$file_name=reset($file).'.'.$file[count($file)-1];

在这里插入图片描述

正常情况下我们抓的数据包:
在这里插入图片描述
我们可以将save_name数据包复制多份并构造成数组:
在这里插入图片描述

修改POST参数为数组类型,索引[0]为upload-21.php,索引[2]为jpg|png|gif,只要第二个索引不为1,

      f 
     
    
      i 
     
    
      l 
     
    
      e 
     
    
      [ 
     
    
      c 
     
    
      o 
     
    
      u 
     
    
      n 
     
    
      t 
     
    
      ( 
     
    
   
     file[count( 
    
   
 file[count(file) - 1]就等价于$file[2-1],值为空。

最需要注意的就是一定要把数据包间隔的空行去掉!!!否则上传不上去!我在这卡了20分钟(心酸呀,查了好几篇文章最后才解决,真就是不断试错不断测试踩坑…)

在这里插入图片描述

构造数组的意思就是前边已经用数据的方式把/upload.php/.jpg拆开,因为count截取的是【2】嘛,我们就用白名单去绕过,还有MIME值也要修改,即可上传成功

在这里插入图片描述

所以说有代码审计能力还是很重要的,这21关也就会在ctf中有源码审计才会遇见,黑盒时很难找到,若还是不懂就去看看迪哥的视频,讲的通俗易懂。至此upload-labs靶场通关,当然,这只是基础。

服务器解析漏洞

文件上传漏洞不仅仅局限在代码层面,还可能出在中间件上,参考《Web中间件常见漏洞总结》比如:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

中间件漏洞也不容小觑,最熟知的apach解析漏洞。还有最近贼火的apach log4j2漏洞,一打倒一片,奈何本人技术菜还没技术复现这个。

编辑器漏洞

web编辑器:一些网站在后台添加/修改一些文章或音频等等时可能用到第三方编辑器。

常见的有:fckeditor编辑器,uedictor编辑器。

编辑器界面,看到这个要想到编辑器漏动,一般可以直接百度到漏洞和exp:
在这里插入图片描述
可以利用的php的exp:

所以可能出现的漏洞太多样了:源码,中间件,框架,第三方应用,cms,操作系统等等。

常见cms文件上传漏洞:

比如:通达OA系统,wordpress等等,百度一搜一堆,主要就是靠自己收集识别整理到网站的cms版本,然后查找有无漏洞,没有就换思路,找中间件漏洞等等,渗透思路很多。

参考:
在这里插入图片描述

WAF 绕过

可以在本地也可以在阿里云上搭建,配置下安全狗啥的,打个upload-labs靶场练习文件上传,此时是从绕过安全狗waf角度来上传后门,自己修改安全狗防护规则啥的不断测试来绕过。或者宝塔,云盾等等。

在这里插入图片描述

在这里插入图片描述
payload:

1.大量垃圾数据缓冲溢出(Ccontent-Disposition,filename等)。
2.单引号、双引号、分号:
filename=x.php
filename="x.php
filename='x.php
filename=“a.jpg;.php”;
3.%00、换行、转义符等等:
1)filename=“a.php%00.jpg”
2)filename=“Content-Disposition : form-data;name=“upload_file” ; x.php”
3)filename=“x.jpg” ; filename=“x.jpg” ; . . . …filename=“x.php”;
4)filename=
"
x
.
p
h
p
"
;

#上传参数名解析:
明确哪些东西能修改?
Content-Disposition:一般可更改
name:表单参数值,不能更改
filename:文件名,可以更改
Content-Type:文件MIME,视情况更改

在这里插入图片描述
在这里插入图片描述

1)垃圾数据溢出:
在这里插入图片描述

由于Content-Disposition数据头可以更改,因此数据溢出插入点也可以在name之后,filename之前:

在这里插入图片描述
注意此处数据溢出插入的不是文件内容,就是利用数据头绕过waf来上传php文件,文件内容仍在下边。

2)换行会被安全狗识别为/n,p/nhp不会被拦截,但数据包认识,所以可以上传成功。

3)单双引号只有前边一半时可能不会被拦截。

4);截断:
在这里插入图片描述

5)重复参数(不是垃圾数据溢出,这就是构造很多filename):在这里插入图片描述
6)白名单机制(很奇葩很不可思议):

借助白名单,在filename内写入前面的一些数据(讲数据头复制进去!),最后再写入x.php,程序判定filename时发现有前面的数据就放行,遇到x.php后发现没有变量接收,然后放弃检测,但最后x.php上传给了filename。这个payload令人大开眼界
在这里插入图片描述

7)/ 截断:

在这里插入图片描述

8)上传完全可以fuzz跑,不过注意现本地搭建,否则可能会因为大量请求封ip,修改文件名导入fuzz字典来爆破上传,字典一定要强大。

9)实战中网站最先需要绕过的就是waf,其次才是可能存在的漏洞,而且你未必知道上传的到底是被waf拦截还是代码拦截了,需要自己识别,这都提高了渗透的难度。

安全修复(未知攻,焉知防)

#文件上传安全修复方案 :
后端验证:采用服务端验证模式后缀检测。
基于黑名单,白名单过滤M工ME检测:。
基于上传自带类型检测。
内容检测:文件头,完整性检测。

自带函数过滤:参考uploadlabs函数。
自定义函数过滤:function check_file(){ }。
WAF防护产品:宝塔,云盾,安全公司产品等。

标签: 安全 web安全

本文转载自: https://blog.csdn.net/qi_SJQ_/article/details/121397762
版权归原作者 暮w光 所有, 如有侵权,请联系我们删除。

“文件上传漏洞(思路,绕过,修复)”的评论:

还没有评论