1. <tfoot id='vdgpsn8a'></tfoot>

      <bdo id='hv2nyopn'></bdo><ul id='63tokiov'></ul>
    1. <legend id='9c72rush'><style id='0b0n3dai'><dir id='kizpzp5k'><q id='2ngacec9'></q></dir></style></legend>

    2. <small id='i2x9ozfy'></small><noframes id='k93426ps'>

    3. <i id='g7nldskl'><tr id='vbkuyu5i'><dt id='ci06exbo'><q id='dc9692nj'><span id='imowj3nh'><b id='79kpl10l'><form id='b4yc6b2w'><ins id='sdz1wsak'></ins><ul id='pd7bc5y3'></ul><sub id='a0t53ld9'></sub></form><legend id='d7ofg0si'></legend><bdo id='or6jt9dq'><pre id='t7zajeu4'><center id='7rkkxefo'></center></pre></bdo></b><th id='em6stedp'></th></span></q></dt></tr></i><div id='r6jof4e3'><tfoot id='f5wbv2q3'></tfoot><dl id='iy852uxs'><fieldset id='v12fb1j0'></fieldset></dl></div>

      精准传达 • 价值共享

      洞悉互联网前沿资讯,探寻网站营销规律

      常见的文件上传的检测方式与绕过的方法

      作者: 庚午网络 | 2020-12-09 01:29 |点击:

          <tbody id='r80zbqdm'></tbody>
          <tfoot id='5f871fvl'></tfoot>
        1. <small id='frbk4x0q'></small><noframes id='zzar32de'>

            <legend id='dzqf6lj6'><style id='bkonov7o'><dir id='0znzh3on'><q id='uie0ubhg'></q></dir></style></legend>
              <bdo id='6jlvpypk'></bdo><ul id='ifk1dikz'></ul>
              <i id='b526mwfr'><tr id='addohgyq'><dt id='9ud6jzzn'><q id='4zactysa'><span id='onp7z2xu'><b id='q4239jaj'><form id='s0pvco6k'><ins id='qr1omacv'></ins><ul id='ryu4hz97'></ul><sub id='32rmlhd7'></sub></form><legend id='yxd6uswp'></legend><bdo id='fit9xuvu'><pre id='lblpyrku'><center id='41qwgtpn'></center></pre></bdo></b><th id='gzywew3c'></th></span></q></dt></tr></i><div id='dqxrorh1'><tfoot id='9f0j7gbk'></tfoot><dl id='xo575pcm'><fieldset id='h2joc3h0'></fieldset></dl></div>

              • 前言

                文件上传漏洞是我们平时渗透过程中经常利用的漏洞,利用文件上传我们可以直接得到webshell,是非常直接的攻击方式。写这篇文章主要是想对常见的文件上传检测和绕过进行总结,同时练习文件上传php代码的编写。

                以下上传测试使用的HTML表单的代码为:

                <html>
                    <head>
                        <title>File Upload</title>
                        <meta charset="utf-8">
                    </head>
                    <body>
                        <form action="upload.php" method="POST" enctype="multipart/form-data">
                            <input type="hidden" name="MAX_FILE_SIZE" value="1000000">
                            选择文件: <input type="file" name="myfile">
                            <input type="submit" value="Upload">
                        </form>
                    </body>
                </html>
                

                1.1 前端JavaScript检测

                前端一般都是使用js来限制我们的上传类型和文件大小,这里以upload-labs Pass-01的源码为例:

                function checkFile() {
                    var file = document.getElementsByName('upload_file')[0].value;
                    if (file == null || file == "") {
                        alert("请选择要上传的文件!");
                        return false;
                    }
                    //定义允许上传的文件类型
                    var allow_ext = ".jpg|.png|.gif";
                    //提取上传文件的类型
                    var ext_name = file.substring(file.lastIndexOf("."));
                    //判断上传文件类型是否允许上传
                    if (allow_ext.indexOf(ext_name + "|") == -1) {
                        var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
                        alert(errMsg);
                        return false;
                    }
                }
                

                对于前端的检测我们可以抓包来修改文件类型,也可以禁用掉JavaScript。总之,只有前端的限制是非常不安全的,非常容易被绕过。

                2.1 后端检测文件类型

                2.1.1 检测content-type

                后端代码大致为:

                <?php
                $allow_content_type = array("image/gif", "image/png", "image/jpeg");
                $path = "./uploads";
                $type = $_FILES["myfile"]["type"];
                
                if (!in_array($type, $allow_content_type)) {
                        die("File type error!<br>");
                } else {
                        $file = $path . '/' . $_FILES["myfile"]["name"];
                        if (move_uploaded_file($_FILES["myfile"]["tmp_name"], $file)) {
                                echo 'Success!<br>';
                        } else {
                                echo 'Error!<br>';
                        }
                }
                ?>
                

                绕过方法:

                抓包将content-type改为图片形式(即'image/png'等),即可成功上传

                2.1.2 检测文件头判断文件类型

                后端代码大致为:

                <?php
                $allow_mime = array("image/gif", "image/png", "image/jpeg");
                $imageinfo = getimagesize($_FILES["myfile"]["tmp_name"]);
                $path = "./uploads";
                
                if (!in_array($imageinfo['mime'], $allow_mime)) {
                        die("File type error!<br>");
                } else {
                        $file = $path . '/' . $_FILES["myfile"]["name"];
                        if (move_uploaded_file($_FILES["myfile"]["tmp_name"], $file)) {
                                echo 'Success!<br>';
                        } else {
                                echo 'Error!<br>';
                        }
                }
                ?>
                

                此时虽然检查的也是文件类型,但是是使用getimagesize()函数来获取文件的MIME类型,此时检测的不是数据包中的content-type,而是图片的文件头,常见的图片文件头如下:

                gif(GIF89a) : 47 49 46 38 39 61

                jpg、jpeg : FF D8 FF

                png : 89 50 4E 47 0D 0A

                绕过方法:

                当上传php文件时,可以使用winhex、010editor等十六进制处理工具,在数据最前面添加图片的文件头,从而绕过检测

                2.2 后端检测文件扩展名

                2.2.1 黑名单检测

                后端代码大致为:

                <?php
                // 实际情况中黑名单内数据会更多更全面
                $blacklist = array('php', 'asp', 'aspx', 'jsp');
                $path = "./uploads";
                $type = array_pop(explode('.', $_FILES['myfile']['name']));
                
                if (in_array(strtolower($type), $blacklist)) {
                        die("File type errer!<br>");
                } else {
                        $file = $path . '/' . $_FILES['myfile']['name'];
                        if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
                                echo 'Success!<br>';
                        } else {
                                echo 'Error!<br>';
                        }
                }
                ?>
                

                众所周知使用黑名单是非常不安全的,很多网站会使用扩展名黑名单来限制上传文件类型,有些甚至在判断时都不用strtolower()来处理,因此造成漏洞

                绕过方法:

                1. 使用一些特殊扩展名来绕过(如php可以使用php3、php4、php5等来代替)
                2. 在后端比较没有转换大小写处理时,使用大小写混淆(如将php改为pHp等)来绕过

                2.2.2 白名单检测

                大致代码如下,与黑名单检测没有太大差别:

                <?php
                $whitelist = array('png', 'jpg', 'jpeg', 'gif');
                $path = "./uploads";
                $type = array_pop(explode('.', $_FILES['myfile']['name']));
                
                if (!in_array(strtolower($type), $whitelist)) {
                        die("File type errer!<br>");
                } else {
                        $file = $path . '/' . $_FILES['myfile']['name'];
                        if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
                                echo 'Success!<br>';
                        } else {
                                echo 'Error!<br>';
                        }
                }
                

                白名单相对与黑名单就安全许多,要求只能是特定扩展名的文件才能上传,虽然我们无法从代码层面来绕过,但这样也不是绝对的安全,可以利用其他漏洞来绕过

                绕过方法:

                1. 使用%00截断文件名来上传(后面会讲)
                2. 如果目标还存在文件包含漏洞,那么就可以上传图片马再文件包含来拿shell

                2.3 后端检测文件内容

                2.3.1 文件内容替换

                这种主要是将文件中的敏感字符替换掉,大致代码类似于下面这样:

                <?php
                $path = "./uploads";
                $content = file_get_contents($_FILES['myfile']['tmp_name']);
                $content = str_replace('?', '!', $content);
                $file = $path . '/' . $_FILES['myfile']['name'];
                
                if (move_uploaded_file($_FILES['myfile']['tmp_name'], $file)) {
                        file_put_contents($file, $content);
                        echo 'Success!<br>';
                } else {
                        echo 'Error!<br>';
                }
                ?>
                

                此时如果我们要上传php的一句话<?php @eval($_POST['shell']);?>时,php的语言标记中的?会被替换为!,这样一句话就不能被执行了

                绕过方法:

                主要还是要根据实际过滤的字符来判断,如果写死的话可能是没办法的(一般不会,因为还要兼顾图片上传)

                比如过滤掉问号,我们就可以使用<script language='php'>system('ls');</script>这样的一句话。具体方法要看实际代码过滤了哪些字符。

                2.3.2 图片二次渲染

                我们以upload-labs Pass-16的源码为例:

                $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(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;
                                imagejpeg($im,$img_path);
                                @unlink($target_path);
                                $is_upload = true;
                            }
                        } else {
                            $msg = "上传出错!";
                        }
                ...
                

                大致意思是后端调用了php的GD库,提取了文件中的图片数据,然后再重新渲染,这样图片中插入的恶意代码就会被过滤掉了

                我自己在测试时发现不管是直接修改文件头来制作的图片马,还是利用copy命令制作的图片马,都无法避免其中的一句话被过滤掉。

                而看了一篇文章发现其实要把一句话插入到图片数据中,这样经过渲染后这部分数据还是会保留下来。大家可以看一下作为参考:https://secgeek.net/bookfresh-vulnerability/

                3.1 解析漏洞及其他漏洞

                3.1.1 IIS解析漏洞

                IIS6.0

                在IIS6.0中有两个很重要的asp解析漏洞:

                1. 假设当前有一个名为"xxx.asp"的目录,那么该目录下的所有文件都将被作为asp文件解析
                2. 假设上传一个名为"test.asp;xxx.jpg"时,该文件会被当做asp文件解析

                IIS7.5

                这个其实不能算IIS的洞,它其实是php的解析漏洞,这个漏洞利用条件是服务器在php.ini中将cgi.fix_pathinfo的值设置为1

                然后当我们访问服务器上任意一个文件时(如:http://test.com/a.jpg),当我们在URL后面添加`.php`(即:http://test.com/a.jpg/.php),那么文件a.jpg就将被作为php文件来解析

                3.1.2 Apache解析漏洞

                利用低版本apache扩展名解析特性

                在了解这个解析漏洞之前,我们要首先了解apache和php的三种结合方式:

                Apache和php三种结合方式:

                1.CGI

                2.Module

                3.FastCGI

                该解析漏洞只有在apache和php以Module方式结合时才存在,而且Apache还有一个特性:

                Apache在解析文件时会以文件名从右向左解析,当最后一个扩展名无法识别时,就会向左查看是否有可以识别的文件名,如果没有的话就以配置中的默认文件类型来解析

                例如:

                a.php.xxx因为xxx无法识别,而左边的php可识别,就会被解析为php文件

                因此,如果上传文件名为a.php.xxx的一句话,访问后就很可能拿到shell

                CVE-2017-15715

                还有一个apache的解析漏洞就是CVE-2017-15715,这个漏洞利用方式就是上传一个文件名最后带有换行符(只能是\x0A,如上传a.php,然后在burp中修改文件名为a.php\x0A),以此来绕过一些黑名单过滤

                具体的漏洞分析可以看p牛:https://www.leavesongs.com/PENETRATION/apache-cve-2017-15715-vulnerability.html

                3.1.3 %00截断

                这个多数被利用在截断路径,利用的条件是:

                PHP < 5.3.4

                magic_quotes_gpc 关闭

                因为0x00是字符串的结束标志符,所以php在读取到0x00时就不会再往后读取,我们可以利用这些截断字符后面不需要的内容

                以upload-labs的Pass-12为例,源码如下:

                $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;
                
                        if(move_uploaded_file($temp_file,$img_path)){
                            $is_upload = true;
                        } else {
                            $msg = '上传出错!';
                        }
                    } else{
                        $msg = "只允许上传.jpg|.png|.gif类型文件!";
                    }
                }
                

                由于是白名单限制了上传文件类型,因此我们无法在文件名处做文章。但最终move_uploaded_file()的目标目录是我们可控的,我们可以将POST传入的save_path改为../upload/shell.php%00,这样后面的内容就会被截断掉,这就导致了任意文件上传

                还要注意的是%00是url编码,在以POST传参时应该使用burpsuite对其进行url decode,或者修改hex值为00;而当GET传参时因为浏览器会做一遍url decode,所以直接传%00即可。

                3.1.4 利用.htaccess解析

                .htaccess文件(或者"分布式配置文件"),全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。

                利用.htaccess的条件:Apache中配置AllowOverride All

                .htaccess文件可以配置将特定的文件按规定的文件类型进行解析,可以用以下两种方式来配置:

                <FilesMatch "test">
                  SetHandler application/x-httpd-php
                </FilesMatch>
                

                这一种采用正则匹配,只要文件名为test的文件都将被作为php文件解析

                AddType application/x-httpd-php .jpg
                

                第二种是将.jpg文件都作为php文件解析

                这样我们如果能将.htaccess上传到服务器的话,就可以再根据我们自己设定的规则来解析上传的文件,以此来绕过上传过滤

                总结

                常见的文件上传的检测和绕过方式基本是以上几种。在实战或CTF比赛中往往是几种类型的结合,因此绕过也需要几种方式的结合。

                首先我认为最重要的是前期的信息收集,服务器的类型、版本,使用的脚本语言、版本,只要做到对这些很清楚后才能考虑之后能否利用一些如%00截断、服务器解析漏洞来进行文件上传。

                在测试时,一般我们都先要fuzz看一下检测是哪种类型,是前端还是后端?黑名单还是白名单?上传后的shell能否被成功执行?是否有文件内容的检测?

                如果是黑名单的话,就要尝试各种特殊文件名(php、Php、PHP、pht、php5、phtml),或者在扩展名后添加空格、::$DATA、.等字符,再或者是尝试上传.htaccess

                如果是白名单,就要看是否可以使用%00截断,或者利用服务器的解析漏洞。如果真的过滤很死的话,不妨再找一下目标的文件包含漏洞,尝试利用文件包含来解析图片马。

                个人认为现在文件上传在代码层除了逻辑问题外已经很少有漏洞了,大多数情况下都是利用服务器解析漏洞等来getshell,这篇文章也只是作为自己入门文件上传的总结。如果有错误,请各位师傅指正。

                二度创作,如有侵权请联系删除。如没特殊注明,文章均为庚午网络原创,转载请注明https://www.hngengwu.com/gengwuwenku/554.html
                • <bdo id='v14heiwz'></bdo><ul id='znxfacp1'></ul>

                  <small id='qtmmmcwz'></small><noframes id='kebd7wem'>

                  <tfoot id='bp54yxzt'></tfoot>

                1. <legend id='crtvuu5b'><style id='cmx25qqj'><dir id='z8zfu3tl'><q id='9qu2ame3'></q></dir></style></legend>

                    <i id='ixc4mxc7'><tr id='ar40aqbk'><dt id='0r4sy57d'><q id='6bh5vvqg'><span id='icccyn8o'><b id='9smqv9to'><form id='1cldiu02'><ins id='jlq2q791'></ins><ul id='c2r52u13'></ul><sub id='5523f4so'></sub></form><legend id='o33rkdbn'></legend><bdo id='ch335zfl'><pre id='4wapsv86'><center id='iu9e79hi'></center></pre></bdo></b><th id='iomfg729'></th></span></q></dt></tr></i><div id='nlysyouu'><tfoot id='3o1vuo2a'></tfoot><dl id='eago6mqd'><fieldset id='xfpecan0'></fieldset></dl></div>
                    多一份策划方案,总有益处。

                    请直接添加技术总监微信联系咨询

                    网站设计 品牌营销

                    多一份参考,总有益处

                    联系庚午网络,获得专属《策划方案》及报价

                    咨询相关问题或预约面谈,可以通过以下方式与我们联系

                    业务热线:18574395938 / 大客户专线:18574395938