本文使用環(huán)境來自于:https://github.com/c0ny1/upload-labs

客戶端
js檢查
一般都是在網(wǎng)頁上寫一段javascript腳本,校驗(yàn)上傳文件的后綴名,有白名單形式也有黑名單形式。

查看源代碼可以看到有如下代碼對(duì)上傳文件類型進(jìn)行了限制:
<script type="text/javascript"> 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;
}
} </script>
我們可以看到對(duì)上傳文件類型進(jìn)行了限制。
繞過方法
- 我們直接刪除代碼中onsubmit事件中關(guān)于文件上傳時(shí)驗(yàn)證上傳文件的相關(guān)代碼即可。

或者可以不加載所有js,還可以將html源碼copy一份到本地,然后對(duì)相應(yīng)代碼進(jìn)行修改,本地提交即可。
- burp改包,由于是js驗(yàn)證,我們可以先將文件重命名為js允許的后綴名,在用burp發(fā)送數(shù)據(jù)包時(shí)候改成我們想要的后綴。

即可上傳成功:

服務(wù)端
黑名單
特殊可解析后綴
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)換為小寫
$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)建!';
}
這里做了黑名單處理,我們可以通過特殊可解析后綴進(jìn)行繞過。
繞過方法
之前在http://www.itdecent.cn/p/1ccbab572974中總結(jié)過,這里不再贅述,可以使用php3,phtml等繞過。

上傳.htaccess
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)換為小寫
$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)黑名單限制了很多后綴名,但是沒有限制.htaccess
.htaccess文件是Apache服務(wù)器中的一個(gè)配置文件,它負(fù)責(zé)相關(guān)目錄下的網(wǎng)頁配置.通過htaccess文件,可以實(shí)現(xiàn):網(wǎng)頁301重定向、自定義404頁面、改變文件擴(kuò)展名、允許/阻止特定的用戶或者目錄的訪問、禁止目錄列表、配置默認(rèn)文檔等功能。
繞過方法
我們需要上傳一個(gè).htaccess文件,內(nèi)容為:
SetHandler application/x-httpd-php
這樣所有的文件都會(huì)解析為php,接下來上傳圖片馬即可


后綴大小寫繞過
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)建!';
}
}
我們發(fā)現(xiàn)對(duì).htaccess也進(jìn)行了檢測(cè),但是沒有對(duì)大小寫進(jìn)行統(tǒng)一。
繞過方法
后綴名改為PHP即可

空格繞過
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)換為小寫
$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)建!';
}
黑名單沒有對(duì)文件中的空格進(jìn)行處理,可在后綴名中加空格繞過。
繞過方法

點(diǎn)繞過
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)換為小寫
$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)建!';
}
windows會(huì)對(duì)文件中的點(diǎn)進(jìn)行自動(dòng)去除,所以可以在文件末尾加點(diǎn)繞過,不再贅述
::$DATA繞過
同windows特性,可在后綴名中加” ::$DATA”繞過,不再贅述
路徑拼接繞過
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)換為小寫
$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)建!';
}
}
這里對(duì)文件名進(jìn)行了處理,刪除了文件名末尾的點(diǎn),并且把處理過的文件名拼接到路徑中。
繞過方法

這里我們可以構(gòu)造文件名1.PHP. . (點(diǎn)+空格+點(diǎn)),經(jīng)過處理后,文件名變成1.PHP.,即可繞過。

雙寫繞過
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)建!';
}
}
繞過方法
這里我們可以看到將文件名替換為空,我們可以采用雙寫繞過:1.pphphp


白名單
MIME檢查
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)建!';
}
繞過方法
這里檢查Content-type,我們burp抓包修改即可繞過:

%00 截?cái)?/h3>
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類型文件!";
}
}
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類型文件!";
}
}
$img_path直接拼接,因此可以利用%00截?cái)嗬@過
繞過方法

然后直接訪問/upload/1.php即可

00截?cái)啵╬ost)
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類型文件!";
}
}
?>
save_path是通過post傳進(jìn)來的,還是利用00截?cái)啵@次需要在二進(jìn)制中進(jìn)行修改,因?yàn)閜ost不會(huì)像get對(duì)%00進(jìn)行自動(dòng)解碼。
繞過方法


接下來訪問1.php即可

文件內(nèi)容檢查
文件幻數(shù)檢測(cè)
主要是檢測(cè)文件內(nèi)容開始處的文件幻數(shù),比如圖片類型的文件幻數(shù)如下,
要繞過jpg 文件幻數(shù)檢測(cè)就要在文件開頭寫上下圖的值:

Value = FF D8 FF E0 00 10 4A 46 49 46
要繞過gif 文件幻數(shù)檢測(cè)就要在文件開頭寫上下圖的值

Value = 47 49 46 38 39 61
要繞過png 文件幻數(shù)檢測(cè)就要在文件開頭寫上下面的值

Value = 89 50 4E 47
然后在文件幻數(shù)后面加上自己的一句話木馬代碼就行了
文件相關(guān)信息檢測(cè)
圖像文件相關(guān)信息檢測(cè)常用的就是getimagesize()函數(shù)
只需要把文件頭部分偽造好就ok 了,就是在幻數(shù)的基礎(chǔ)上還加了一些文件信息
有點(diǎn)像下面的結(jié)構(gòu)
GIF89a
(...some binary data for image...)
<?php phpinfo(); ?>
(... skipping the rest of binary data ...)
本次環(huán)境中的文件頭檢測(cè),getimagesize,php_exif都可以用圖片馬繞過:
copy normal.jpg /b + shell.php /a webshell.jpg
文件加載檢測(cè)
一般是調(diào)用API 或函數(shù)去進(jìn)行文件加載測(cè)試,常見的是圖像渲染測(cè)試,甚至是進(jìn)行二次渲染(過濾效果幾乎最強(qiáng))。對(duì)渲染/加載測(cè)試的攻擊方式是代碼注入繞過,對(duì)二次渲染的攻擊方式是攻擊文件加載器自身。
對(duì)渲染/加載測(cè)試攻擊- 代碼注入繞過
可以用圖像處理軟件對(duì)一張圖片進(jìn)行代碼注入
用winhex 看數(shù)據(jù)可以分析出這類工具的原理是
在不破壞文件本身的渲染情況下找一個(gè)空白區(qū)進(jìn)行填充代碼,一般會(huì)是圖片的注釋區(qū)
對(duì)于渲染測(cè)試基本上都能繞過,畢竟本身的文件結(jié)構(gòu)是完整的

二次渲染
imagecreatefromjpeg二次渲染它相當(dāng)于是把原本屬于圖像數(shù)據(jù)的部分抓了出來,再用自己的API 或函數(shù)進(jìn)行重新渲染在這個(gè)過程中非圖像數(shù)據(jù)的部分直接就隔離開了
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";
$newimagepath = UPLOAD_PATH.$newfilename;
imagejpeg($im,$newimagepath);
//顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片)
$img_path = UPLOAD_PATH.$newfilename;
@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";
$newimagepath = UPLOAD_PATH.$newfilename;
imagepng($im,$newimagepath);
//顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片)
$img_path = UPLOAD_PATH.$newfilename;
@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";
$newimagepath = UPLOAD_PATH.$newfilename;
imagegif($im,$newimagepath);
//顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片)
$img_path = UPLOAD_PATH.$newfilename;
@unlink($target_path);
$is_upload = true;
}
} else {
$msg = "上傳出錯(cuò)!";
}
}else{
$msg = "只允許上傳后綴為.jpg|.png|.gif的圖片文件!";
}
}
本關(guān)綜合判斷了后綴名、content-type,以及利用imagecreatefromgif判斷是否為gif圖片,最后再做了一次二次渲染。
繞過方法
得去找圖片經(jīng)過GD庫(kù)轉(zhuǎn)化后沒有改變的部分,再將未改變的部分修改為相應(yīng)的php代碼。

條件競(jìng)爭(zhēng)
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ò)!';
}
}
這里先將文件上傳到服務(wù)器,然后通過rename修改名稱,再通過unlink刪除文件,因此可以通過條件競(jìng)爭(zhēng)的方式在unlink之前,訪問webshell。
繞過方法

然后不斷訪問webshell:

上傳成功。
參考鏈接: