Upload-labs 测试条记

Upload-labs 测试条记

By:Mirror王宇阳

2019年11月~

文件上传剖析学习

环境要求

若要自己亲自搭建环境,请凭据以下设置环境,方可正常运行每个Pass。

设置 项 设置 形貌
操作系统 Window or Linux 推荐使用Windows,除了Pass-19必须在linux下,其余Pass都可以在Windows上运行
PHP版本 推荐5.2.17 其他版本可能会导致部门Pass无法突破
PHP组件 php_gd2,php_exif 部门Pass依赖这两个组件
中间件 设置Apache以moudel方式毗邻

Upload-labs 测试条记

手艺摘录

  • 判断文件长传点

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("."));
    //判断上传文件类型是否允许上传
    if (allow_ext.indexOf(ext_name + "|") == -1) {
        var errMsg = "该文件不允许上传,请上传" + allow_ext + "类型的文件,当前文件类型为:" + ext_name;
        alert(errMsg);
        return false;
    }
}

[剖析]

Pass-01是在客户端使用js对文件举行校验,完全可以绕过。

[思绪]

使用障眼法,将PHP文件修改图像花样后直接上传;使用burp阻挡该数据包,修改文件花样(后缀名)

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

[剖析]

服务端的源码对接受的文件MIME举行检测,判断是否相符图像花样;但MIME校验的缺陷是严重的,用户完全可以随意修改MIME的参数值,但完全不影响文件花样的正常剖析。

[思绪]

正常上传一个PHP文件,Burp阻挡数据包,修改数据包中的MIME花样类型为图像花样的MIME。

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

[剖析]

源码检测举行文件名后缀检测,由此确定文件类型;无法使用burp阻挡改包的方式;由于接纳的黑名单方式,只隔离了asp、aspx、php、jsp等文件的后缀;由于php的特征,可以上传php5等文件后缀也是可以凭据PHP文件被剖析的

[思绪]

上传“11.php5”文件,直接绕过黑名单。

[ps:获取上传目录和文件名]

由于文件上传后的文件位置是位置的,且文件名是接纳随机数举行的二次重命名;故此我们可以凭据返回的图像打开图像位置获取文件的详细路径。乐成上传一个php(php5)文件后就会返回一个图像,打开图像的URL地址就是PHP文件的地址,例:../upload-labs-master/upload/202003141844327950.php5这个取决于Apache的设置问题(需要修改Apache的设置,让Apache支持剖析例如php3之类的文件为PHP文件)

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

[剖析]

一看数组deny_ext那么多的黑名单;之前的特殊剖析方式(混淆剖析)也可存在可能,要害照样取决于apache的设置平安

[.htaccess知识]

.htaccess文件(分布式设置文件)提供了针对目录改变设置的方式;特定的文档目录中放置一个包罗一个或多个指令的文件,以作用于此目录及其所有子目录;(是Apache环境下的一种设置行为)

设置.htaccess将当前目录的所有文件以php文件剖析$#$

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

[剖析]

这里把.htaccess也拉入了黑名单,细细的看代码发现少了之前源代码中的一行”巨细写转写”;代码缺陷瞬间露出,将文件名举行巨细写混淆即可。

[思绪]

上传muma.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 . '文件夹不存在,请手工确立!';
    }
}

[剖析]

从源码看来,对黑名单的建设是相当的完善了,同时也添加了小写转变检测的代码段,之前的巨细写混淆、特殊剖析混淆、.htaccess等方式在这里都被封杀了;然则凭据老例,既然是黑名单,我们的绕过思绪就依旧是围绕在黑名单的缺陷上,同时围绕代码缺陷找到破绽.

[思绪]

通过对源码的剖析,发现没有对截取的文件后缀举行去空处置;这里提醒:在操作系统中文件后缀是自动屏障删除后缀名的,然则在代码处置中空符号存在且可被处置.

在上传WebShell中直接提交”.php”文件即可,使用Burp阻挡数据包,修改数据包中的文件后缀(添加一个空符号)

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

[剖析]

文件后缀被所有拉入黑名单,统一转小写检测,字符串去空;然则回归突破的宗旨,查缺陷!围绕黑名单发现没有被拉入且可以绕过检测的文件后缀方式举行枚举

[思绪]

这里的思绪是行使Win文件存储的特征,自动屏障后缀名的尾部.符号;正常上传php文件,burp阻挡数据包就该文件后缀为.php.,乐成绕过php的检测,在win、linux系统上自动消除尾部符号正常保存为。.php文件;(不选择其他特殊符号末端的缘故原由:在文件后缀修改上,其他特殊符号都市被正常存储,只有符号点会被消除)

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绕过举行平安检测

[思绪] -> ::$DATA绕过

NTFS文件系统的存储数据流的一个属性DATA时,当我接见a.php::DATA时,就是请求a.php自己的数据。

1. 两数之和

提交.php文件,Burp阻挡数据包修改为.php::$DATA放包;正常以./././xxxx.php接见该文件即可

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

[剖析]

这里否决了之前的所有绕过方案,不外依旧凭据黑名单的绕过原则,通过名单缺陷和代码逻辑缺陷发现:删除逻辑(删除尾部的点、删除收尾的空字符、删除::$DATA) 这里的删除逻辑可以行使“双写”的方式来做突破

[思绪]

通过Burp将文件名字符串修改为.php. .,代码逻辑会删除尾部的点和空字符,最后会将.php.提交举行黑名单校验

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

[剖析]

依旧是黑名单机制,这里发现一个要害的代码逻辑,相符黑名单的字符所有替换为空字符;故此无法在使用之前那些什么后缀名混淆的方式没有用了,由于只要有相符黑名单中的字符所有替换为空

[思绪]

burp阻挡将文件名修改为双写.phphpp,交给代码举行校验,校验代码举行一次校验并替换敏感词为空字符,再上传。

Pass-11

[源码]

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

[剖析]

这里不再是黑名单机制,反之接纳了“白名单”机制

[思绪]

使用%00字节截断方式绕过–>.php%00

Pass-12

[源码]

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

[剖析]

[思绪]

00字节截断,php5.3+版本不再支持

Pass-13

[源码]

**************客户端校验****************
function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只读2字节
    fclose($file);
    $strInfo = @unpack("C2chars", $bin); 
        // unpack() 函数从二进制字符串对数据举行解包。   
    $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_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传失足!";
        }
    }
}

[剖析]

这里只允许上传图片文件,图片马走起;js剧本通过读文件的前2个字节判断文件类型

[思绪]

这里需要行使文件包罗来举行图片马的剖析

Pass-14

[源码]

function isImage($filename){
    $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
        //file_exists() 检测文件是否存在
        $info = getimagesize($filename);
        // getimagesize() 获取图像巨细及相关信息,乐成返回一个数组

        // [宽度,高度,type(返回数值),…………]
        $ext = image_type_to_extension($info[2]);
        if(stripos($types,$ext)>=0){
            return $ext;
        }else{
            return false;
        }
    }else{
        return false;
    }
}

****************************************************

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传失足!";
        }
    }
}

[剖析]

这里在客户端行使getimagesize()函数获取图像的信息(返回的数组第三个元素)举行校验类型;

[思绪]

图片马

Pass-15

[源码]

function isImage($filename){
    //需要开启php_exif模块
    $image_type = exif_imagetype($filename);
    switch ($image_type) {
        case IMAGETYPE_GIF:
            return "gif";
            break;
        case IMAGETYPE_JPEG:
            return "jpg";
            break;
        case IMAGETYPE_PNG:
            return "png";
            break;    
        default:
            return false;
            break;
    }
}

*************************************************

$is_upload = false;
$msg = null;
if(isset($_POST['submit'])){
    $temp_file = $_FILES['upload_file']['tmp_name'];
    $res = isImage($temp_file);
    if(!$res){
        $msg = "文件未知,上传失败!";
    }else{
        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$res;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上传失足!";
        }
    }
}

[剖析]

这里行使PHP_exif模块举行判断文件类型; exif_imagetype()获取图片类型

[思绪]

图片马

Pass-16

[源码]

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 获得上传文件的基本信息,文件名,类型,巨细,临时文件路径
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

    $target_path=UPLOAD_PATH.'/'.basename($filename);

    // 获得上传文件的扩展名
    $fileext= substr(strrchr($filename,"."),1);

    //判断文件后缀与类型,正当才举行上传操作
    if(($fileext == "jpg") && ($filetype=="image/jpeg")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片天生新的图片
            $im = imagecreatefromjpeg($target_path);

            if($im == false){
                $msg = "该文件不是jpg花样的图片!";
                @unlink($target_path);
            }else{
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".jpg";
                //显示二次渲染后的图片(使用用户上传图片天生的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上传失足!";
        }

    }else if(($fileext == "png") && ($filetype=="image/png")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片天生新的图片
            $im = imagecreatefrompng($target_path);

            if($im == false){
                $msg = "该文件不是png花样的图片!";
                @unlink($target_path);
            }else{
                 //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".png";
                //显示二次渲染后的图片(使用用户上传图片天生的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @unlink($target_path);
                $is_upload = true;               
            }
        } else {
            $msg = "上传失足!";
        }

    }else if(($fileext == "gif") && ($filetype=="image/gif")){
        if(move_uploaded_file($tmpname,$target_path)){
            //使用上传的图片天生新的图片
            $im = imagecreatefromgif($target_path);
            if($im == false){
                $msg = "该文件不是gif花样的图片!";
                @unlink($target_path);
            }else{
                //给新图片指定文件名
                srand(time());
                $newfilename = strval(rand()).".gif";
                //显示二次渲染后的图片(使用用户上传图片天生的新图片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上传失足!";
        }
    }else{
        $msg = "只允许上传后缀为.jpg|.png|.gif的图片文件!";
    }
}

[剖析]

这是一道大题,综合判断后缀名、content-type、行使imagecreatefromgif等多种方式来验证是否为图片;更要害的是在判断是图片后还会举行第二次图片渲染,图片的十六进制内容会发生许多转变。送上一个很好的剖析文章(思绪)

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 = '上传失足!';
    }
}

[剖析]

条件竞争绕过(参考文章)

Pass-19

CVE-2015-2348 move_uploaded_file() 00截断

Pass-20

Pass-20参考文章

笔者注

Upload-labs是在去年接触并做了部门Pass,近期整理资料发现了这份没有完成的稿子,于是闲暇之余所有Pass整理汇总(部门Pass由于环境的约束和时间不适没有测试,转载了先辈的文章)

Upload-labs考察了绝大多数现在主流的文件上传方式和剖析,在测试学习的过程中更可以学会避开文件上传的风险。

防御文件上传的方式离不开:

  • 前端限制:行使Js代码限制上传的文件类型,但这是不可靠且不可不用的方式,前端的一切防御都可以经由数据抓包举行绕过

  • 检查扩展名:后端检查MIME的意义并不大,但可以对文件的扩展名举行检测(绕过方式也是多种),这里建议首先将PHP升级到5.4以上的版本规避00字节绕过、凭据平安的设置要求设置Apache(同时也是建议Nginx);对扩展名举行完整的截取检查比对黑名单(或接纳白名单机制也可以,详细需求详细设计,固然了,白名单是加倍平安);记着是严酷的后缀名检查!!!

  • 检查剖析破绽:检查是否存在剖析破绽,若是存在剖析破绽绕过白/黑名单是易如反掌的;笔者从各处收集了一些剖析破绽的文章,供参考:
  • 剖析文件头内容来检查文件类型:这类方式不是检查文件后缀那般的简朴,而是对文件内容举行检查;行使各种文件特定类型都市有不一样的标志位和开头;可行使php的exif_imagetype()函数(也可以自己编写)

  • 其他防御计谋异常的多,笔者暂未深入研究平安防御的计谋确立

原创文章,作者:28x29新闻网,如若转载,请注明出处:https://www.28x29.com/archives/1329.html