【文件上传绕过】——后端检测_文件的扩展名检测漏洞

本文详细讲述了如何通过各种方法绕过Web应用的文件扩展名检测,包括黑名单和白名单策略,解析漏洞利用,文件包含技巧,大小写绕过,以及利用Windows命名机制进行文件上传。通过upload-labs闯关游戏实例,展示了实战中的具体步骤和策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、漏洞说明:

  通常是针对文件的扩展名后缀进行检测,主要是通过黑白名单进行过滤检测,如果不符全过滤规则则不允许上传。

二、工具:

BurpSuite
火狐/谷歌浏览器
AntSword(蚁剑)

三、实验环境:

靶 机: windows10虚拟机:192.168.15.133
      upload-labs-master闯关游戏

攻击机: 物理机

四、实验目的:

1、通过实验,学习掌握文件的扩展名检测的原理;
2、通过实验,学习扩展名检测的绕过的方法技巧。

五、检测方法:

1. 黑名单:

  黑名单检测:一般有个专门的 blacklist 文件,里面会包含常见的危险脚本文件。
  例如: fckeditor 2.4.3 或之前版本的黑名单:

2. 白名单:

  白名单检测:一般有个专门的 whitelist 文件,里面会包含的正常文件。
  Jpg png GIF

六、绕过方式:

1. 白名单绕过:

1.1 解析漏洞:
1.2 截断上传:
原理:

  虽然web应用做了校验,但是由于文件上传后的路径用户可以控制,攻击者可以利用手动添加字符串标识符0X00的方式来将后面的拼接的内容进行截断,导致后面的内容无效,而且后面的内容又可以帮助我们绕过黑白名单的检测。
   点击进入: 【文件上传绕过】——后端检测_文件名检测00截断绕过

绕过思路:

  在C语言中,空字符有一个特殊含义,代表字符串的拼接结束。
  这里我们使用的是php语言,属于高级语言,底层靠C语言来实现的,也就是说空字符的字符串拼接结束功能在PHP中也能实现。但是我们在URL中不能直接使用,这样会造成无法识别;我们通过查看ASCII对照表,发现ASCII对照表第一个就空字符,它对应的16进制是00,这里我们就可以用16进制的00来代替空字符,让它截断后面的内容。

使用burpsuite进行抓包,因为这里是通过URL进行传递的文件上传后存储路径,所以需要对16进制00进行URL编码,编码的结果就是%00,通过这种方式,就可以%00截断后面的内容,让拼接的文件名不再进行生效:

1.3 文件包含:

点击进入:【汇总】文件包含漏洞合集详解

2. 黑名单绕过:

2.1 解析漏洞:
2.2 截断上传:
原理:

  虽然web应用做了校验,但是由于文件上传后的路径用户可以控制,攻击者可以利用手动添加字符串标识符0X00的方式来将后面的拼接的内容进行截断,导致后面的内容无效,而且后面的内容又可以帮助我们绕过黑白名单的检测。
   点击进入: 【文件上传绕过】——后端检测_文件名检测00截断绕过

绕过思路:

  在C语言中,空字符有一个特殊含义,代表字符串的拼接结束。
  这里我们使用的是php语言,属于高级语言,底层靠C语言来实现的,也就是说空字符的字符串拼接结束功能在PHP中也能实现。但是我们在URL中不能直接使用,这样会造成无法识别;我们通过查看ASCII对照表,发现ASCII对照表第一个就空字符,它对应的16进制是00,这里我们就可以用16进制的00来代替空字符,让它截断后面的内容。

2.3 可能存在大小写绕过漏洞:

比如:aSppHp之类;

2.3.1 upload-labs闯关游戏(Pass-05):

页面源码:

$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");
        $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 . '文件夹不存在,请手工创建!';
    }
}

通过上面的源码可以看出,没有对文件的大小写进行验证,可以通过大小写进行绕过,下面通过把文件修改为大写:
在这里插入图片描述修改为大小写,发现绕过了黑名单,可以进行解析为脚本文件:
在这里插入图片描述

2.4 找黑名单扩展名的漏网之鱼:

比如:
asacer之类
asp: asa cer aspx
jsp: jspx jspf
php: php php3 php4 php5 phtml pht
exe: exee

2.4.1 upload-labs闯关游戏(Pass-03):

访问:

192.168.15.133/upload-labs-master/Pass-03/index.php?action=show_code

1、上传一个1.php的文件:
在这里插入图片描述2、提示不允许上传:
在这里插入图片描述3、文件名改为1.php2:
在这里插入图片描述
4、发现能够上传,但无法解析为脚本文件:
在这里插入图片描述
5、删除后面的2,发现没有这个文件,因为服务器里面没有这个文件:
在这里插入图片描述
6、我们偿试上传一个1.php5的文件:
在这里插入图片描述
7、无法进行解析:
在这里插入图片描述
8、通过偿试,发现上传php3 php4 php5 pht几个文件都可以进行上传,但是无法进行解析为脚本文件。
偿试上传phtml文件,首先我们进行重命名,发现这里可以解析为脚本文件:
在这里插入图片描述
9、偿试进行上传:
在这里插入图片描述
10、访问,可以正常进行解析:
在这里插入图片描述

2.5 利用Windows的命名机制:

shell.php. shell.php空格 shell.php:1.jpg shell. php::$DATA shell.php:1.jpg

1、在windows中,后缀名后面的点和空格都会被删除掉。
2.php文件重命名为2.php. .,如下图所示:

2、我们发现,空格和点都被删除了,如下图所示:

2.5.1 upload-labs闯关游戏(Pass-06):

页面源码:

$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");
        $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;
            if (move_uploaded_file($temp_file,$img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

通过上面源码我们发现,里面有$file_ext = strtolower($file_ext); //转换为小写代码,我们使用大小写进行绕过肯定不行。
但是我们发现,这个代码相比于前面一关来说,没有进行首尾去空的代码,可以使用命名机制进行绕过:
1、通过上传,发现只能上传以下几种文件后缀:
在这里插入图片描述2、这里我们发现无法直接通过windows本地进行后缀加空格的修改,我们可以通过burpsuite抓包进行修改后缀名:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
3、发现已经上传成功,并且可以正常解析:
在这里插入图片描述

注:我们可以把文件名称改为*.php空格,它会把我们上传的文件和黑名单里面的后缀进行比对,发现黑名单没有*.php空格这个文件的后缀名,后台就会进行放行,这样就可以进行成功进行上传。到达windows服务器后,windows发现文件后缀有空格,windows就会删除后面的空格,文件就变成*.php格式了。

2.5.2 upload-labs闯关游戏(Pass-07):

页面源码:

$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");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $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.'/'.$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '此文件类型不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

1、通过上面源码我们发现,这里的代码里面没有写删除文件后缀末尾的点的这行代码,这里我们可以通过在文件后面加上点进行绕过,通过burpsuite进行抓包:
在这里插入图片描述
2、发现正常,可以进行解析为脚本文件:
在这里插入图片描述

2.5.3 upload-labs闯关游戏(Pass-09):

页面源码:

$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");
        $file_name = trim($_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
        $file_ext = trim($file_ext); //首尾去空
        
        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 . '文件夹不存在,请手工创建!';
    }
}

检测过滤过程:删除文件名末尾的点-->截取后缀名-->转换为小写-->去除字符串::$DATA-->首尾去空-->把过滤的结果和黑名单进行比对

通过上面的源码我们发现,它的验证过程是先删除删除文件名末尾的点,最后首尾去空,这样我们就可以构造为1.php. .,这样在第一步的时候,先删除最后面的点,接着删除中间的空格,最后还剩下1.php.,黑名单中也没有这个后缀名,可以进行绕过。
1、通过burpsuite进行抓包修改文件后缀名,如下图所示:
在这里插入图片描述2、可以解析为脚本文件:
在这里插入图片描述

2.5.3 upload-labs闯关游戏(Pass-08):

页面源码:

$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");
        $file_name = trim($_FILES['upload_file']['name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //转换为小写
        $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 . '文件夹不存在,请手工创建!';
    }
}

检测过滤过程:删除文件名末尾的点-->截取后缀名-->转换为小写-->首尾去空-->把过滤的结果和黑名单进行比对
通过上面源码我们发现,这里的代码里面没有写去除字符串::$DATA的这行代码,这里我们可以通过在文件后面加上点进行绕过。

注:这关我们需要的了解的知识:$DATA是什么?
  windows磁盘一般使用文件系统为NTFS文件系统,NTFS使用Master File Table (MFT) 来管理文件。windows系统中的每个文件都对应一个MFT记录。而每一个MFT记录由若干个属性(attribute)组成,用来描述该文件的具体信息。比如:
$FILE_NAME 属性描述了该文件的文件名和创建修改访问时间;
$DATA属性包含了该文件的具体内容,我们一般在创建文件,写入的内容都会默认存储在这个属性里面。这个默认的属性我们称为主数据流(primary data stream )。
  举个例子,我现在有一个文本文件,名称为1.txt,文本内容为”Hello, world!”:

我们可以通过实验进行了解:
创建一个1.txt的文件:


通过上面操作,我们发现,通过两种方法写入的数据效果都是一样,其实都是存储在第一个$DATA里面,我们正常创建的一个文件,默认写入的就是第一个$DATA里面。通过在后面加上::$DATA这样就可以绕过黑名单的检测,而且在绕过黑名单后,Windows会自动去掉末尾的::$DATA变成*.php

可参考文章1

可参考文章2

1、通过burpsuite进行抓包,修改文件后缀名:


2、我们复制图片链接地址,并进行访问,发现没有权限进行访问:


3、删除::$DATA后进行访问,发现可以进行访问:


4、我们去文件上传路径看看文件的变化,发现文件名后面的::$DATA没有了:

注:出现上面情况的原因是因为,根据windows的命名机制,文件名是不允许有:(冒号)等一些字符存在的,当这个文件被转存到web服务器后,它会根据windows命名机制删除:(冒号)后面的字符。

2.6 双写绕过

有时候在检测时,后台会把敏感字符替换成空格,这个时候,我们可以使用双写进行绕过。比如:pphphp

2.6.1 upload-labs闯关游戏(Pass-10):

页面源码:

$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($_FILES['upload_file']['name']);
        $file_name = str_ireplace($deny_ext,"", $file_name);//把上传的文件和黑名单进行对比,如果黑名单里面存在,就把后缀名替换为空格。
        $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 = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

这关的验证方式和前面几关有所不同,主要看str_ireplace($deny_ext,"", $file_name);这个代码,主要作用是把上传的文件和黑名单进行对比,如果黑名单里面存在,就把后缀名替换为空格。
通过这种方式进行过滤验证的,我们通常可以使用双写的方式进行绕过。
1、下面我们对文件进行重命名,命名为1.pphphp:


2、上传并进行访问,发现上传成功可以进行解析:

### 回答1: CentOS 7启动httpd服务失败可能有多种原因,以下是一些常见的解决方法: 1. 检查httpd配置文件是否正确:可以使用命令`httpd -t`检查httpd配置文件是否正确,如果有错误,需要修改配置文件。 2. 检查端口是否被占用:可以使用命令`netstat -tlnp`查看端口是否被占用,如果被占用需要释放端口或修改httpd配置文件中的端口号。 3. 检查httpd服务是否安装:可以使用命令`rpm -qa | grep httpd`查看httpd服务是否安装,如果没有安装需要先安装httpd服务。 4. 检查httpd服务是否启动:可以使用命令`systemctl status httpd`查看httpd服务是否启动,如果没有启动需要使用命令`systemctl start httpd`启动httpd服务。 5. 检查SELinux是否开启:如果SELinux开启,可能会导致httpd服务启动失败,需要使用命令`setenforce 0`关闭SELinux,或者修改SELinux策略。 以上是一些常见的解决方法,如果以上方法都无法解决问题,可以查看httpd服务日志文件,找到具体的错误信息,然后根据错误信息进行解决。 ### 回答2: CentOS 7上的httpd服务启动失败可能有多种原因。以下列出了一些常见问题和解决方法: 1. 端口被占用 当httpd试图占用已被其他程序占用的端口时会启动失败。此时可以通过使用`netstat -tunlp`命令检查端口占用情况,然后杀死占用该端口的进程及时释放端口。或者修改httpd的配置文件,将端口修改为未被占用的端口。 2. 配置文件错误 有时httpd服务的配置文件中可能出现错误,例如语法错误或路径错误等等。在启动httpd服务之前,可以使用`apachectl configtest`命令进行检查,如果输出“Syntax OK”,则表示配置文件没有错误。如果出现错误,则需要根据错误提示进行相应修改。 3. 依赖关系问题 如果httpd依赖的其他程序或库缺失,也会导致启动失败。可以通过使用`systemctl status httpd.service`命令来查看httpd服务状态,如果输出“Failed to start”或“Loaded: failed”,则需要检查依赖关系是否完整。 4. SELinux问题 当SELinux启用时,有时会导致httpd服务启动失败。在这种情况下,可以在SELinux上禁用httpd服务,或者修改httpd配置文件解决SELinux相关的问题。 5. 用户权限问题 httpd服务启动可能需要特定的用户权限。如果使用的用户权限不够,则无法启动。可以尝试使用root用户启动httpd服务,或者根据需要修改相应的用户权限。 ### 回答3: CentOS 7中的Apache HTTP服务器(httpd)是一个常见的Web服务器,如果遇到httpd服务启动失败的情况,可能会影响服务器正常的工作和对外服务的稳定性。本文将提供一些可能会导致httpd服务启动失败的原因,并给出相应的解决方法。 1. 端口被占用 如果端口被其他进程占用,httpd服务就无法启动。可以通过 netstat -tulpn 命令查看端口占用情况,并杀死占用该端口的进程。如果端口被 httpd 服务自身占用,可以通过 systemctl restart httpd 命令重启 httpd 服务;如果是其他进程占用了端口,可以通过 kill 命令杀死该进程或更改 httpd.conf 文件配置,将 httpd 服务的端口改为其他空闲端口,重新启动。 2. 配置文件错误 httpd 服务的配置文件通常是 /etc/httpd/conf/httpd.conf,如果其中存在语法错误、权限问题或者其它配置错误,可能会导致 httpd 服务启动出错。可以通过将 httpd.conf 文件备份后删掉,重新执行 yum install httpd 命令安装 httpd 服务,然后手动修改 httpd.conf 文件,逐个检查每个配置项是否正确,确认无误后重启 httpd 服务。 3. SELinux 问题 SELinux 是 CentOS 7中提供的一种安全模块,它可以对系统文件和应用程序进行安全管控。如果 SELinux 配置不正确,可能会阻止 httpd 服务正常启动。可以通过修改 /etc/selinux/config 文件中 SELINUX=disabled 来暂时关闭 SELinux,然后重新启动 httpd 服务;或者一个更优的方式是,根据日志确定问题原因,使用命令 semanage 或者 setsebool 等工具将相关目录或者配置加入到 SELinux 许可列表中,重新启动 httpd 服务,以恢复服务正常工作。 4. 防火墙问题 如果你的 CentOs 7 服务器启用了防火墙,有可能会导致 httpd 服务启动失败。可以通过检查防火墙相关配置来确定问题原因,解决方案是修改防火墙规则,将端口 80 或者 443 等 httpd 服务需要的端口放行,重新启动 httpd 服务。 总之,当遇到 httpd 服务启动失败时,不要慌张,可以先通过日志或者执行命令查看错误信息,找到错误原因,然后根据错误原因一步一步解决问题。在解决问题过程中注意备份原始配置文件,以免造成不必要的损失。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值