序
文件上传靶场,搭建了很长时间了,一直没做,刚好最近闲来无事。学习一下
靶场环境
因为环境的不同导致上传的绕过方法也会不同,在这里说明我搭建的环境信息:操作系统为windows,使用的phpstudy的集成环境,php版本为5.2.17,因为1有些题目涉及到00截断上传。apache配置文件没有修改过,是默认的配置文件
闯关笔记
Pass-01
- 直接观察源代码,发现不允许上传.php类型文件
//定义允许上传的文件类型
var allow_ext = ".jpg|.png|.gif";
-
可以直接抓包就可以绕过上传
-
查看
Pass-02
- 查看源码
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 = '上传出错!';
-
Content-Type绕过,直接把Content-Type改为图片类型即可
上传成功,截图不在赘述
Pass-03
- 这一关是另类的文件名的绕过,可以尝试phtml,php3,php4, php5, pht后缀名都可以绕过,但是前提是要在配置文件里面有这样的一句话
AddType application/x-httpd-php .php .phtml .phps .php5 .pht
- 源码黑名单
$deny_ext = array('.asp','.aspx','.php','.jsp');
Pass-04
1.看一下他过滤的名单,上面的方法已经不行了
$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");
- 但是
.htaccess
还是没有过滤,可以重写文件解析规则绕过,上传一个.htaccess
,文件内容如下,就是在upload目录下匹配gg.jpg的文件并以php文件执行
SetHandler application/x-httpd-php
-
然后再上传一个名字为gg.jpg的脚本
访问,成功上传
Pass-05
- 这一题里面多过滤了
.htaccess
,如何绕过呢? - 对比代码发现去掉了转换为小写,部分代码
$file_ext = strtolower($file_ext); //转换为小写
-
文件后缀大小写混合过滤
Pass-06
- 这一关比第五关少了这样的一句代码
$file_ext = trim($file_ext); //首尾去空
-
后缀名+空格的形式去绕过
Pass-07
- 对比第6题的代码可以发现少了下面一句代码
$file_name = deldot($file_name);//删除文件名末尾的点
1
-
既然没有对文件最后的点做过滤,可以尝试以后缀名加上点的形式去绕过
- 这一题的代码比上一次少了下面这一段代码
$file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
-
文件后缀 + ::$DATA 绕过
Pass-09
- 这一关像是前几关的组合拳
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); //首尾去空
- 可以遵循着他的步骤去实现自己的payload,可以这样设置
09.phP. .
Pass-10
- 关键过滤的代码就这两句
$file_name = trim($_FILES['upload_file']['name']);
$file_name = str_ireplace($deny_ext,"", $file_name);
-
双写绕过
Pass-11
- 关键的代码在于这里的’save_path’是一个可控的变量,但是后面还拼接上一个后缀名,也需要绕过
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
- 这个时候可以使用%00截断,但这东西有点过气了,因为需要两个条件
php版本小于5.3.4
php的magic_quotes_gpc为OFF状态
如果要完成这一个题目就必须要实现上面的两个条件,但是现在都PHP7了,这东西也就很少见了,满足上面的条件的时候php就是把它当成结束符,后面的数据直接忽略,这也导致了很多的问题,文件包含也可以利用这一点
所以如果要绕过,我们可以这样去实现,另
save_path
等于../upload/11.php%00
Pass-12
- 这里的源代码就改了一点点,就是把get改为post类型,一样的方式绕过,只不过这里需要在二进制里面修改%00,因为post不会像get对%00进行自动解码。
$img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
Pass-13
- 这里可以发现源代码只是用了unpack这一个函数去实现对于php前两个字节的检测,也就是只是对文件头做检测。。。
$bin = fread($file, 2); //只读2字节
fclose($file);
$strInfo = @unpack("C2chars", $bin);
-
直接上传 在bp中构造 shell
把该图片上传上去,尝试文件包含,成功回显
http://192.168.3.8/bachang/shangchuan/include.php?file=./upload/9920190725190903.gif
Pass-14
- 用了
getimagesize
函数来对文件类型做判断
Pass-15
- 同理
Pass-16
具体针对二次渲染的上传绕过可以看这篇文章upload-labs之pass 16详细分析,我试了下gif文件的绕过
-
先上传一个gif文件,修改没有二次渲染后没有变动的地方。插入shell
-
利用文件包含成功执行php语句
Pass-17和18
- 条件竞争上传
Less-19
- 这一关正常做法应该是CVE-2015-2348
move_uploaded_file()
00截断,上传webshell,同时自定义保存名称,上传的文件名用0x00绕过。改成xx.php【二进制00】jpg
-
move_uploaded_file()
函数中的_img_path_
是由post参数save_name
控制的,因此可以在save_name
利用00截断绕过
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 = "请选择要上传的文件!";
}
首先end函数取所post参数数组中的最后一个值,_$file_name = reset($file) . '.' . $file[count($file) - 1]_
我们可以post一个参数名为一个[0]一个[2],然后file) - 1]就为空,file)即$file[0],就可以绕过判断