网络安全之文件上传漏洞(上篇)(技术进阶)

时间:2024-04-30 07:08:05

目录

一,什么是文件上传漏洞?文件上传漏洞会造成什么危害?

二,文件上传靶场upload-labs闯关

Pass-01

Pass-02

 Pass-03

 Pass-04

 Pass-05

Pass-06

 Pass-07

​Pass-08

Pass-09

 Pass-10

 总结


一,什么是文件上传漏洞?文件上传漏洞会造成什么危害?

文件上传漏洞就是服务器端脚本没有对上传的文件进行严格的过滤和验证,导致黑客利用这个漏洞上传恶意脚本从而达到控制整个网站甚至是服务器。

二,文件上传靶场upload-labs闯关

Pass-01

源码:

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("."));  //找到文件最后一个.并把后面的内容切给ext_name
    //判断上传文件类型是否允许上传
    if (allow_ext.indexOf(ext_name + "|") == -1) {  //和白名单进行匹配没有匹配到就是-1
        var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
        alert(errMsg);  //输出错误警告
        return false;
    }
}

看完注释和代码后可以知道这是一个js前端验证,这个非常简单只需要将上传的木马病毒修改后缀为白名单里面的内容,然后再通过bp抓包修改文件后缀就可以轻松绕过了。

看效果:

1,新建一个一句话木马

<?php
phpinfo();
?>

2,修改后缀为.jpg,然后上传文件

 3,开启bp抓包

 4,抓到数据包,修改test.jpg为test.php

 5,放开修改后的数据包

 

 

 总结解题思路:

看代码知道是前端验证,那么我咋知道是前端验证的呢?前端验证一般是写在JavaScript,css,html中的在浏览器里面F12就可以看到这些代码,而且前端验证不需要把数据给后台验证,它会对我们输入的数据直接进行验证,且快速返回判断结果给用户。

前端验证讲了再讲一件什么是后端验证吧,后端验证就是把数据传输到服务器端,由服务器端进行

数据的正确性验证,这样可以防止用户修改信息和绕过保证了数据的完整性和安全性。

Pass-02

查看源代码:

$is_upload = false;
$msg = null;
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'];  //将临时文件路径给$temp_file
            $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.'文件夹不存在,请手工创建!';
    }
}

  

代码和解析看完后也可以知道这是一个前端验证,更改数据类型为白名单里面的类型

1,先开启bp抓包然后上传一个test.php

2,更改文件类型为image/gif 

 3,放开数据包,发现上传成功

4,访问一句话木马

 Pass-03

源代码:

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

看完代码和注释,我们可以看出这是一个黑名单验证,但是它没有禁用 phtml和php3这两个后缀,apache中会把这两个后缀的文件当成php文件来执行,所有我们只需要将php后缀改为php3就好了。

看效果:

 

phtml效果也是一样这里不演示了。

 Pass-04

源代码:

$is_upload = false;
$msg = null;
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");
        $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 = '此文件不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

 可以看到它做的挺绝的,但是它忽略了一个.htaccess文件,这个文件可以轻松禁用和启用任何功能。

.htaccess代码:

<FilesMatch  "loudong.jpg">

SetHandler application/x-httpd-php

</FilesMatch>

它的作用是将上传的loudong.jpg文件当作一个php文件来执行

1,先把.htaccess上传上去,然后上传loudong.jpg

2,去访问看看

 Pass-05

源代码:

$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 = 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 = '此文件类型不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}
 

通过分析源代码发现它没有做小写转换,那么就简单了直接把后缀改成大写上传,要知道的是windows操作系统对文件名不区分大小写,所以改成大写它也可以运行

直接看效果

 

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

通过分析源代码可以知道它没有首位去空格,那么就简单了,在文件后缀末尾加个空格就可以轻松绕过。

 1,通过bp抓包并在php后加个空格

2,上传成功后去访问文件

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

通过分析源代码可以知道它没有删除多余的.号,所以这就简单了,直接在后缀多放几个.号就可以了。

1,通过bp抓包修改后缀

2,上传成功后去访问

 Pass-08

源代码:

$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 = 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 = '此文件类型不允许上传!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}
 

通过分析源代码可以得知它少了个删除::$DATA的语句,所以我们直接在后缀php后面加上::$DATA就行了。

1,抓包修改后缀

2,访问看效果

 

这里浅谈一下::DATA的作用吧,它是用于NTFS文件系统中用来隐藏数据流的一种标识符,但是它的出现并不影响文件的主要内容。

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

存在漏洞的deldot函数

<?php
function deldot($s){
    for($i = strlen($s)-1;$i>0;$i--){
        $c = substr($s,$i,1);
        if($i == strlen($s)-1 and $c != '.'){  //从这里可以看出它对末尾.号进行了判断,但是它一遇到其他字符就跳出了
            return $s;
        }

        if($c != '.'){
            return substr($s,0,$i+1);
        }
    }
}
?>

 可以看到它删了但是又没有完全删(只删了最后一个),所以我们只需要在后缀上加上点空格点就可以绕过了

看效果

1,老样子抓包改后缀

 2,去访问

 Pass-10

源代码:

$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","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);//判断是不是黑名单里面的如果是就用空串把它替换掉
        $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 = UPLOAD_PATH . '文件夹不存在,请手工创建!';
    }
}

 trim函数的作用是首位去空

str_ireplace(黑名单,"要替换为的字符串",上传的文件名);它的作用是那我们上传的文件名去黑名单里面找相同的字符,如果找到了就用空串替换(也就是删除了),所以我们只需要将后缀改为

test.pphphp,它会从前往后把第一个php给删了(看代码它只删了一次),但是没想到又合成了个php吧。

看效果:

1,抓包改后缀

2,访问

 总结

文件上传绕过方法不是一成不变的,我这里一关列举了一种方法,在熟练运用后会发现原来同一关可以有多个绕过方法,所以灵活运用晓其原理才能更好的玩转文件上传漏洞

中篇下个星期一更

谢谢观看!!!