如何预防文件上传漏洞:文件上传漏洞学习小结
如何预防文件上传漏洞:文件上传漏洞学习小结上传文件是flash的策略文件crossdomiain.xml,黑客用以控制flash在该域下的行为;2、域控制相册、头像上传视频、照片分享附件上传(论坛发帖、邮箱)文件管理器1、代码执行上传文件是web脚本语言,服务器的web容器解释并执行了用户上传的脚本,导致代码执行,甚至导致网站甚至整个服务器被控制
文件上传漏洞总结 一、不安全的文件上传漏洞概述在文件上传的功能处,若服务端脚本语言未对上传的文件进行严格验证和过滤,导致恶意用户上传恶意的脚本文件时,就有可能获取执行服务端命令的能力,这就是文件上传漏洞。文件上传漏洞对Web应用来说是一种非常严重的漏洞。
一般情况下,Web应用都会允许用户上传一些文件,如头像、附件等信息,如果Web应该没有对用户上传的文件进行有效的检查过滤,那么恶意用户就会上传一句话木马等webshell,从而达到控制web网站的目的。
二、漏洞原理由于程序员在对用户文件上传部分的控制不足或者处理缺陷,而导致用户可以越过其本身权限向服务器上传可执行的动态脚本文件,并通过此脚本文件获得了执行服务端命令的能力。
高危出发点:
相册、头像上传视频、照片分享附件上传(论坛发帖、邮箱)文件管理器
三、漏洞危害1、代码执行
上传文件是web脚本语言,服务器的web容器解释并执行了用户上传的脚本,导致代码执行,甚至导致网站甚至整个服务器被控制
2、域控制
上传文件是flash的策略文件crossdomiain.xml,黑客用以控制flash在该域下的行为;
3、网站挂马
上传文件是病毒、木马,黑客用以诱骗用户或者管理员下载执行;
4、钓鱼
上传文件是钓鱼图片或为包含了脚本的图片,在某些版本的浏览器中会被作为脚本执行,被用于钓鱼和欺诈。
三、上传漏洞满足条件首先,上传的文件能够被web容器解释执行。所以文件上传后所在的目录要是web容器所覆盖到的路径。
其次,用户能够从web访问这个文件。如果文件上传了,但用户无法通过web访问,或者无法得到web容器解释这个脚本,那么也不能称之为漏洞。 最后,用户上传的文件若被安全检查、格式化、图片压缩等功能改变了内容,则也可能导致攻击不成功。
四、防御将上传文件与web服务隔离 白名单过滤、限制上传文件类型 文件上传路径设置为不可执行权限 检查文件上传路径 自带函数检测 自定义函数检测 图片渲染 对上传文件重命名 对文件内容压缩,重新生成文件内容 检查文件内容
五、上传漏洞绕过详情看图片,后面有一些场景的题目配合学习
upload-labs通关笔记 Pass-1 使用js对不合法图片进行检查需要上传个webshell上去 但是限制了上传的文件类型
F12查看javascrip内容
代码审计
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); //输出errMsg
return false;
}
}
方法一 :本地删除js代码上传
F12点击查看器,将其中的js过滤代码(上面那段)删除掉,ctrl s保存在本地桌面上,在桌面上右键文本方式打开,寻找action(目标),ctrl f,没有找到,说明没有上传目标,手动添加,重新刷新网页正常上传正常图片,查看网络,可以看到一个post数据包,200ok,里面有一个地址
action="http://127.0.0.1/upload/Pass-01/index.php"
将这个代码添加在<from>标签
<div id="upload_panel">
<ol>
<li>
<h3>任务</h3>
<p>上传一个<code>webshell</code>到服务器。</p>
</li>
<li>
<h3>上传区</h3>
<form action="http://127.0.0.1/upload/Pass-01/index.php" enctype="multipart/form-data" method="post" onsubmit="return checkFile()">
<p>请选择要上传的图片:</p><p>
<input class="input_file" type="file" name="upload_file">
<input class="button" type="submit" name="submit" value="上传">
</p></form>
<div id="msg">
</div>
<div id="img">
</div>
</li>
</ol>
</div>
重新上传一个a.php文件,(<?php phpinfo(); ?>)
在网站根目录result可以查看到a.php文件,说明上传成功。
或者访问:http://127.0.0.1/upload/upload/a.php
方法二:bp抓改浏览器172.21.172.56访问靶场,修改php文件后缀改为png文件,上传,bp抓包,修改数据包后缀,又改回php,发送数据包,再次访问http://172.21.172.56/upload/upload/b.php出现phpinfo信息说明成功
方法三:火狐禁用js过滤接着再地址栏输入about:config,点击回车键。
接着看到如下画面。去掉下次任显示此警告前面的方框里的钩,再点击我 保证会小心按钮
点击后看到如下画面,在搜索地址栏中输入javascript.enabled
改为flase
直接上传c.php就可以了
访问:http://172.21.172.56/upload/upload/c.php
出现信息,成功
方法四:修改js:前端过滤不安全js代码很明显是白名单,只允许三种通过,那么我们可以手动添加一个规则
直接上传php文件
Pass-2 在服务端对数据包的MIME进行检查右键网页源码,没有发现js过滤
网站根目录查看index.php源码
<?php
include '../config.php';
include '../head.php';
include '../menu.php';
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) { //isset — 检测变量是否已设置并且非 null
if (file_exists(UPLOAD_PATH)) { // file_exists 检查文件或目录是否存在 UPLOAD_PATH如果存在
if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) { //如果文件类型是image/jpeg image/png 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 = '文件类型不正确,请重新上传!'; //非image/jpeg image/png image/gif,重新上传
}
} else {
$msg = UPLOAD_PATH.'文件夹不存在 请手工创建!';
}
}
?>
不是在js中,而是在服务器端进行了限制
MIME (Multipurpose Internet Mail Extensions) 是描述消息内容类型的因特网标准 MIME 消息能包含文本、图像、音频、视频以及其他应用程序专用的数据 在HTTP 协议中,使用Content-Type 字段表示文件的MIME 类型。
所以抓包修改Content-Type
200ok
仅仅判断content-type类型,因此上传a.php抓包修改content-type为图片类型:image/jpeg、image/png、image/gif 就可了
Pass-3 特殊后缀绕过黑名单源码分析$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) { //检查文件或目录是否存在
$deny_ext = array('.asp' '.aspx' '.php' '.jsp'); //数组deny_exit相当于黑名单
$file_name = trim($_FILES['upload_file']['name']); //trim()去除字符串首尾处的空白字符(或者其他字符)
$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; //date()重置时间,时间戳 //rand产生一个随机整数
if (move_uploaded_file($temp_file $img_path)) { //将上传的文件移动到新位置
$is_upload = true;
} else {
$msg = '上传出错!';
}
} else {
$msg = '不允许上传.asp .aspx .php .jsp后缀文件!';
}
} else {
$msg = UPLOAD_PATH . '文件夹不存在 请手工创建!';
}
}
/*
move_uploaded_file(string `$filename` string `$destination`)
filename
上传的文件的文件名。
destination
移动文件到这个位置。
*/
是个黑名单,不允许上传.asp .aspx .php .jsp后缀的文件
那最简单的绕过办法,用特殊后缀名
.phtml
.phps
.php5
.pht
类似的 前提是apache的配置文件httpd.conf中有如下配置
AddType application/x-httpd-php .php .pHtml .phps .php5 .pht
实质就是添加可以执行php的文件类型
回复告诉我们路径以及文件名了。图片上传后右键也能得到图片地址
Pass-4 .htaccess绕过黑名单源码分析$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" ".ini");
$file_name = trim($_FILES['upload_file']['name']);//trim()去除字符串首尾处的空白字符(或者其他字符)
$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 . '文件夹不存在 请手工创建!';
}
}
黑名单拒绝了几乎所有有问题的后缀名,除了.htaccess 前提条件(1.mod_rewrite模块开启。2.AllowOverride All)
因此先上传一个.htaccess文件,内容如下:SetHandler application/x-httpd-php
这样所有文件都会当成php来解析
在上传一个 1.jpg,(内容写成 <?php phpinfo();?>)之后访问就会以php来执行
Pass-5 .user.ini绕过黑名单源码分析$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 . '文件夹不存在 请手工创建!';
}
}
更完善的黑名单.htaccess文件也被禁了
但是.ini没禁 所以可以上传.user.ini文件 内容是 auto_prepend_file=1.jpg
让所有php文件都“自动”包含1.jpg文件
试了半天根本不行,介绍另一个方法
点 空格 点绕过 Pass-6-大小写绕过$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" ".ini");
$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 . '文件夹不存在 请手工创建!';
}
}
更完善的黑名单
但是大小写的函数去掉了
所以可以后缀名大写绕过
$file_ext = strtolower($file_ext); //转换为小写
这里没得
抓包看看,文件改成啥名字了
Pass-7 空格绕过黑名单源码分析$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" ".ini");
$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 = trim($file_ext); //收尾去空 $file_name = trim($_FILES['upload_file']['name']); //trim()去除字符串首尾处的空白字符(或者其他字符)
这里没有
Pass-8 点绕过黑名单源码分析$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" ".ini"); $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 . '文件夹不存在 请手工创建!'; }}
对比前面 没有对后缀名末尾的点进行处理
$file_name = deldot($file_name);//删除文件名末尾的点
没有这个
Pass-9::$DATA绕过黑名单源码分析$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" ".ini"); $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’进行过滤 在php windows的情况下文件名 "::$DATA"会把::$DATA之后的数据当成文件流处理,不会检测后缀名 且保持"::$DATA"之前的文件名
少了 $file_ext = str_ireplace('::$DATA' '' $file_ext);//去除字符串::$DATA
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" ".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" ".ini"); $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 . '文件夹不存在 请手工创建!'; }}
区别是路径里不是file_ext,而是file_name即保存文件的时候没有重命名而使用的原始的文件名 可以利用1.php. .(点 空格 点)来绕过
Pass-11 双写绕过源码分析$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" "ini"); $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把黑名单里的后缀全替换为空 但是这个函数只进行一次替换 所以可以双写绕过
Pass-12 Get 截断源码分析$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); /*返回字符串的子串substr(string $string int $start int $length = ?): string返回字符串 string 由 start 和 length 参数指定的子字符串。strrpos(string find start)函数查找字符串中最后一次出现的位置*/ 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类型文件!"; }}
定义一个白名单,只允许三种文件类型
substr()函数返回字符的一部分,strrpos(string find start)函数查找字符串中最后一次出现的位置,这里是将后缀名提取出来赋值给file_ext img_path是直接拼接
我们可以抓包修改get的参数,然后通过file_ext无效,这样就可以上传PHP文件