文件上传

文件上传 原理 类型 预防

0x00 文件上传原理

文件上传漏洞是指用户上传了一个可执行脚本文件,并通过此文件获得了执行服务器端命令的能力。在大多数情况下,文件上传漏洞一般是指上传 WEB 脚本能够被服务器解析的问题,也就是所谓的 webshell 问题。完成这一攻击需要这样几个条件,一是上传的文件能够被 WEB 容器执行,其次用户能从 WEB 上访问这个文件,最后,如果上传的文件被安全检查、格式化、图片压缩等功能改变了内容,则可能导致攻击失败。

img

Webshell简介:
  • WebShell就是以asp、php、jsp或者cgi等网页文件形式存在的一种命令执行环境,也可以将其称之为一种网页后门。攻击者在入侵了一个网站后,通常会将这些asp或php后门文件与网站服务器web目录下正常的网页文件混在一起,然后使用浏览器来访问这些后门,得到一个命令执行环境,以达到控制网站服务器的目的(可以上传下载或者修改文件,操作数据库,执行任意命令等)。

  • WebShell后门隐蔽较性高,可以轻松穿越防火墙,访问WebShell时不会留下系统日志,只会在网站的web日志中留下一些数据提交记录,没有经验的管理员不容易发现入侵痕迹。攻击者可以将WebShell隐藏在正常文件中并修改文件时间增强隐蔽性,也可以采用一些函数对WebShell进行编码或者拼接以规避检测。除此之外,通过一句话木马的小马来提交功能更强大的大马可以更容易通过

S出现场景:用户上传头像,编写文章上传图片等
PHP $_FILES函数
然后upload.php中可以直接用 
$_FILES 
$_POST 
$_GET 
等函数获取表单内容。 
当客户端提交后,我们获得了一个$_FILES 数组 
$_FILES数组内容如下: 
$_FILES['myFile']['name'] 客户端文件的原名称。 
$_FILES['myFile']['type'] 文件的 MIME 类型,需要浏览器提供该信息的支持,例如"image/gif"。 
$_FILES['myFile']['size'] 已上传文件的大小,单位为字节。 
$_FILES['myFile']['tmp_name'] 文件被上传后在服务端储存的临时文件名,一般是系统默认。可以在php.ini的upload_tmp_dir 指定,但 用 putenv() 函数设置是不起作用的。 
$_FILES['myFile']['error'] 和该文件上传相关的错误代码。['error'] 是在 PHP 4.2.0 版本中增加的。下面是它的说明:(它们在PHP3.0以后成了常量) 

附加:本地upload环境搭建

0x01 为什么文件上传存在漏洞

  • 上传文件的时候,如果服务器脚本语言,未对上传的文件进行严格的验证和过滤,就容易造成上传任意文件,包括上传脚本文件。
  • 如果是正常的PHP文件,对服务器则没有任何危害。
  • php可以像其他的编程语言一样,可以查看目录下的文件,查看文件中的吗内容,可以执行系统命令等。
  • 上传文件的时候,如果服务器端脚本语言,未对上传的文件进行严格的验证和过滤,就有可能上传恶意的PHP文件,从而控制整个网站,甚至是服务器。这个恶意的PHP文件,又被称为WebShell。

0x02 客户端检测绕过(JS检测)

客户端检测绕过(javascript 检测)
  1. 简介

    这类检测通常在上传页面里含有专门检测文件上传的 javascript 代码

    最常见的就是检测扩展名是否合法

    通常这种检测机制通常伴随页面 asp 弹框,检测流程是在本地的,不会上传流量到服务器

    检测内容:

    在这里插入图片描述

2.操作:前端对文件后缀进行检查,该种通过抓包修改数据包即可解决

绕过方法
  1. 我们直接删除代码中onsubmit事件中关于文件上传时验证上传文件的相关代码即可。

img

或者可以不加载所有js,还可以将html源码copy一份到本地,然后对相应代码进行修改,本地提交即可。

2.burp改包,由于是js验证,我们可以先将文件重命名为js允许的后缀名,在用burp发送数据包时候改成我们想要的后缀。

img

eg: CTF HUB web 前端验证

0x03服务端检测绕过 MIME 绕过

  • 定义:MIME((Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式每个MIME类型由两部分组成,前面是数据的大类别,例如声音 audio、图象 Image等,后面定义具体的种类。

  • MIME类型就是服务端会检测Content-Type的值

  • Content-Type检测

    HTTP协议规定了上传资源的时候在Header中加上一项文件的MIMETYPE,来识别文件类型,这个动作是由浏览器完成的,服务端可以检查此类型。不过这仍然是不安全的,因为HTTP header可以被发出者或者中间人任意的修改,不过加上一层防护也是可以有一定效果的。

  • 常见的MME类型,例如:

    • 超文本标记语言文本 .html,html text/htm

    • 普通文本 .txt text/plain

    • RTF文本. rtf application/rtf

    • GIF图形 .gif image/gif

    • JPEG图形 . jpg image/jpeg

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nrIkCfWo-1611500711946)(C:\Users\77771\AppData\Roaming\Typora\typora-user-images\image-20210121231806868.png)]

  • 检测原理

当用户上传文件到服务器端的时候,服务器端的程序会获取上传文件的MIME类型,然后用这个获取到的类型来和期望的MIME类型进行匹配,如果匹配不上则说明上传的文件不合法。服务端检测MIME类型的代码如下:

if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')){

 ...//判断过后对文件处理的进一步操作
}
  • 绕过方法

因为服务端检测的是文件的MIME类型,而对这个MIME类型的的值的获取是通过HTTP请求字段里的Content-Type字段 ,所以绕过的方法就是通过修改Content-Type的值,比如修改为image/jpeg;image/png;image/gif等等允许上传类型对应的MIME值

eg: CTF HUB web MIME绕过

0x04 服务端检测绕过(文件扩展名检测)

大致可以分为两类

  • 黑名单后缀绕过

名单里有的后缀不可上传,上传没有的就行了

  • 白名单后缀绕过

名单里有的后缀才可上传,如果是在前段验证可以加验证的后缀

0x01 00截断

  • 定义:00截断是绕过上传限制的一种常见方法。在C语言中,“\0”是字符串的结束符,如果用户能够传入“\0”,就能够实现截断。

  • 00截断通过上传限制适用的场景为,后端先获取用户上传的文件名,如x.php\00.jpg,再根据文件名获得文件的实际后缀jpg;通过后缀的白名单校验后,最后在保存文件时发生截断,实现上传的文件为x.php

  • 0x00是十六进制表示方法,表示ASCII码为0的字符,在一些函数处理时,会把这个字符当作结束符。

    0x00可以用在对文件名的绕过上,具体原理:系统在对文件名进行读取时,如果遇到0x00,就会认为读取已经结束。但要注意是文件的十六进制内容里的00,而不是文件名中的00。也就是说系统是按二进制或十六进制读取文件,遇到ASCII码为0的位置就停止,而这个ASCII码为0的位置在十六进制中是00。

    总之就是利用ASCII码为0这个特殊字符,让系统认为字符串已经结束

  • 注:php版本要 PHP<5.3.29,且GPC关闭

  • eg:upload labpass12

    这题和上一题基本一样,只是save_path不在URL中了,而在POST数据里面,由于POST里面的数据不会被url自动解码,所以要稍微改变一下,首先,先改好路径,然后再路径后面加上一个字符,什么字符都可以,这里我为了方便用+号。
    在这里插入图片描述
    然后再点击Hex,找到对应+的十六进制数据2b
    在这里插入图片描述
    直接双击2b改为00,再切回到RAW,查看报文。
    在这里插入图片描述
    直接GO,查看返回结果。
    在这里插入图片描述
    访问,解析成功。
    在这里插入图片描述
    因为是十六进制所以这种截断叫做是0x00截断,其实是%00截断最终被url解码还是会变成0x00的。在url%00表示ascll码中的0,而ascii0作为特殊字符保留,表示字符串结束,所以当url中出现%00时就会认为读取已结束。这是一样的道理,所以这里还有另外一种做法。
    在这里插入图片描述
    直接在后面加上%00然后选中,右键如下图进行url解码即可,或者直接按ctrl+shfit+u
    在这里插入图片描述
    效果会是一样的。
    在这里插入图片描述
    源码不用分析什么,就是将GET换成了POST而已。

    $is_upload = false;
    $msg = null;
    if(isset($_POST['submit'])){
         
        $ext_arr = array('jpg','png','gif');
        $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
        if(in_array($file_ext,$ext_arr)){
         
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;	//换成了POST
    
            if(move_uploaded_file($temp_file,$img_path)){
         
                $is_upload = true;
            } else {
         
                $msg = "上传失败";
            }
        } else {
         
            $msg = "只允许上传.jpg|.png|.gif类型文件!";
        }
    }
    

%00截断

  • 原理:url发送到服务器后被服务器解码,这时还没有传到验证函数,也就是说验证函数里接收到的不是%00字符,而是%00解码后的内容,即解码成了0x00。总之就是%00被服务器解码为0x00发挥了截断作用。
  • 例题 CTF hub web %00截断
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OuAPI4IJ-1611500711947)(C:\Users\77771\AppData\Roaming\Typora\typora-user-images\image-20210122234230481.png)]

0x0a截断

0x0a是十六进制表示方法,表示ASCII码为/n的换行字符,具体为换行至下一行行首起始位置。

分享一篇很好的00截断博客

http://www.admintony.com/%E5%85%B3%E4%BA%8E%E4%B8%8A%E4%BC%A0%E4%B8%AD%E7%9A%8400%E6%88%AA%E6%96%AD%E5%88%86%E6%9E%90.html

0x02 双写后缀绕过

  • 原理:黑名单会给出一些不可使用的后缀名。
    将写入一句话木马的php文件上传,抓包,将后缀改为.pphphp即可,双写即可绕过。
    思路不唯一,各种后缀也是各种双写。
  • 解析后,pphphp后缀名会变为php后缀名

eg: CTF HUB web 双写后缀名

0x03 后缀大小写绕过

eg: upload-labs Pass 6

if (isset($_POST['submit'])) {
   
    if (file_exists(UPLOAD_PATH)) {
   
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空

        if (!in_array($file_ext, $deny_ext)) {
   
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
            if (move_uploaded_file($temp_file, $img_path)) {
   
                $is_upload = true;
            } else {
   
                $msg = '上传出错!';
            }
        } else {
   
            $msg = '此文件类型不允许上传!';
        }
    } else {
   
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

我们发现对.htaccess也进行了检测,但是没有对大小写进行统一。

绕过原理:通过对检测不包含的后缀名(黑名单)漏洞利用来实现绕过
绕过方法

后缀名改为PHP即可//在实际操作中将后缀改为phP,pHp,Php等格式同样成立

img

0x04 空格绕过

eg: upload-labs Pass 7

源码分析
$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",".pHp",".pHp5",".pHp4",".pHp3",".pHp2",".Html",".Htm",".pHtml",".jsp",".jspa",".jspx",".jsw",".jsv",".jspf",".jtml",".jSp",".jSpx",".jSpa",".jSw",".jSv",".jSpf",".jHtml",".asp",".aspx",".asa",".asax",".ascx",".ashx",".asmx",".cer",".aSp",".aSpx",".aSa",".aSax",".aScx",".aShx",".aSmx",".cEr",".sWf",".swf",".htaccess",".ini");
        $file_name = $_FILES['upload_file']['name'];
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        
        if (!in_array($file_ext, $deny_ext)) {
   
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
            
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值