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

文件上传漏洞

  • 常见的漏洞分类
     服务器配置不当导致文件上传
     开源编辑器存在上传漏洞
     本地文件上传限制可以上传被绕过
     服务器端过滤不严可以被绕过
     解析漏洞导致文件执行
     文件路径截断

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

补充:
对于文件上传漏洞的防护来说,主要分为以下两类:
白名单限制和黑名单限制
对于黑名单的限制,我们只需要寻找一些较为偏僻的可执行后缀、大小写混写以及相关操作系统的特性(如windows文件名后缀的最后会自动过滤空格以及.等)来进行绕过;
对于白名单的限制来说,一般是结合解析漏洞、代码函数漏洞(icov(80-EF截断),造成00截断的相关函数以及相关操作系统特性(如windows10文件名长度总共为223包括后缀,win2012的为237,linux ubuntu0.16.04.1文件名长度252等)来进行绕过!

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

例子一:

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


文件上传(upload-labs详细全解)_第1张图片
1.png

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

文件上传(upload-labs详细全解)_第2张图片
2.png

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


文件上传(upload-labs详细全解)_第3张图片
3.png

 3、到上传路径和文件名


文件上传(upload-labs详细全解)_第4张图片
4.png

 4、访问上传的木马文件,用菜刀链接
文件上传(upload-labs详细全解)_第5张图片
5.png

文件上传(upload-labs详细全解)_第6张图片
6.png

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





Upload










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

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

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

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

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


文件上传(upload-labs详细全解)_第7张图片
1.png

访问返回木马的路径


文件上传(upload-labs详细全解)_第8张图片
2.png

菜刀连
文件上传(upload-labs详细全解)_第9张图片
3.png

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


文件上传(upload-labs详细全解)_第10张图片
1.png

burpsuit进行修改后缀


文件上传(upload-labs详细全解)_第11张图片
2.png

查看返回地址
文件上传(upload-labs详细全解)_第12张图片
3.png

菜刀连接

文件上传(upload-labs详细全解)_第13张图片
4.png

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


文件上传(upload-labs详细全解)_第14张图片
image.png

菜刀链接,找打key


文件上传(upload-labs详细全解)_第15张图片
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进行截断攻击

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

文件上传(upload-labs详细全解)_第16张图片
image.png

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


文件上传(upload-labs详细全解)_第17张图片
image.png

4、成功上传,菜刀链接


文件上传(upload-labs详细全解)_第18张图片
image.png

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

文件上传(upload-labs详细全解)_第19张图片
1.png

先扫描一波目录看看

文件上传(upload-labs详细全解)_第20张图片
3.png

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


文件上传(upload-labs详细全解)_第21张图片
image.png

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


文件上传(upload-labs详细全解)_第22张图片
2.png

不过中间好像有个上传的页面一闪而过,我们用burp抓包,来一页一页看页面
文件上传(upload-labs详细全解)_第23张图片
8.png

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

Cookie: uploadmd5=verify%2F2b10f3817a8604ef.txt

我们查看源代码:


文件上传(upload-labs详细全解)_第24张图片
7.png

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


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

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

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

我们直接构造 shell.php 内容为 进行上传


文件上传(upload-labs详细全解)_第25张图片
9.png

文件上传(upload-labs详细全解)_第26张图片
10.png

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


文件上传(upload-labs详细全解)_第27张图片
11.png

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

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

文件上传(upload-labs详细全解)_第28张图片
12.png

分析源代码

 

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

$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


文件上传(upload-labs详细全解)_第29张图片
13.png

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


文件上传(upload-labs详细全解)_第30张图片
12.png

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

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

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

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


文件上传(upload-labs详细全解)_第31张图片
1.png
  • pass-01
    上传文件,显示只能上传什么类型的


    文件上传(upload-labs详细全解)_第32张图片
    2.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代码


文件上传(upload-labs详细全解)_第33张图片
3.png

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


文件上传(upload-labs详细全解)_第34张图片
4.png

上传之后查看源码,得到上传文件的路径
文件上传(upload-labs详细全解)_第35张图片
1.png

访问连接,菜刀连接


文件上传(upload-labs详细全解)_第36张图片
5.png
  • pass-02
    第二关先进行黑盒测试,发现可以上传正常图片、修改后缀名的(shell.php改为shell.jpg)进行上传、抓包修改后缀名(上传shell.jpg抓包改为shell.php)、修改文件类型(上传shell.php,修改Content-Type: image/gif)成功上传木马。
文件上传(upload-labs详细全解)_第37张图片
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


文件上传(upload-labs详细全解)_第38张图片
4.png

文件上传(upload-labs详细全解)_第39张图片
2.png
  • pass-03
     禁止上传.asp|.aspx|.php|.jsp后缀文件
    用上面方法发现上传都不行,发现对.asp|.aspx|.php|.jsp后缀名进行了严格的限制。
    用[.htaccess]从新解析.htaccess的内容是,意思是让jpg格式的文件也当成php文件运行
AddType application/x-httpd-php .jpg
文件上传(upload-labs详细全解)_第40张图片
TIM图片20181204100742.png

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


文件上传(upload-labs详细全解)_第41张图片
TIM图片20181204100742.png
文件上传(upload-labs详细全解)_第42张图片
TIM图片20181204100742.png
注.htaccess基础知识重点内容

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


文件上传(upload-labs详细全解)_第43张图片
3.png
  • pass-04
    查看源代码
$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
文件上传(upload-labs详细全解)_第44张图片
TIM截图20181204105318.png

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


文件上传(upload-labs详细全解)_第45张图片
TIM截图20181204112219.png

访问


文件上传(upload-labs详细全解)_第46张图片
TIM截图20181204112616.png
  • pass-05
    查看源代码
$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); //转换为小写

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


文件上传(upload-labs详细全解)_第47张图片
4.png

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


文件上传(upload-labs详细全解)_第48张图片
1.png

发现成功上传,可以访问一下,发现成功执行:
文件上传(upload-labs详细全解)_第49张图片
2.png
  • pass-06
    查看源代码
$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文件,抓包将文件名后缀加上空格,如下图


文件上传(upload-labs详细全解)_第50张图片
1.png

访问:


文件上传(upload-labs详细全解)_第51张图片
2.png
  • pass-07
    查看源代码:
$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特性,会自动去掉后缀名中最后的”.”,可在后缀名中加”.”绕过:


文件上传(upload-labs详细全解)_第52张图片
1.png

访问


文件上传(upload-labs详细全解)_第53张图片
2.png
  • pass-08
    查看源代码
$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"之前的文件名。

文件上传(upload-labs详细全解)_第54张图片
1.png
文件上传(upload-labs详细全解)_第55张图片
2.png

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

  • pass-09
    这关算是一个逻辑漏洞
    查看源码
$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;
文件上传(upload-labs详细全解)_第56张图片
1.png

访问


文件上传(upload-labs详细全解)_第57张图片
2.png
  • pass-10
    查看源码
$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);
文件上传(upload-labs详细全解)_第58张图片
1.png

返回


文件上传(upload-labs详细全解)_第59张图片
2.png
  • pass-11 采用00截断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);
    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 参数所在的位置返回的长度负数 - 从字符串末端返回的长度

理解测试代码:


返回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


文件上传(upload-labs详细全解)_第60张图片
1.png

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


文件上传(upload-labs详细全解)_第61张图片
1.png

访问,成功上传
文件上传(upload-labs详细全解)_第62张图片
2.png
  • pass-12 采用00截断POST方式
    查看并分析源码
$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进行编码之后进行上传文件,同样可以解析成功


文件上传(upload-labs详细全解)_第63张图片
2.png

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

文件上传(upload-labs详细全解)_第64张图片
1.png

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


文件上传(upload-labs详细全解)_第65张图片
2.png

点击go进行上传


文件上传(upload-labs详细全解)_第66张图片
3.png

访问
文件上传(upload-labs详细全解)_第67张图片
4.png

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


文件上传(upload-labs详细全解)_第68张图片
5.png
文件上传(upload-labs详细全解)_第69张图片
7.png
文件上传(upload-labs详细全解)_第70张图片
8.png
  • pass-13 图片马上传
    查看源码
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 

上传图片马:

你可能感兴趣的:(文件上传(upload-labs详细全解))