文末下載上傳環境源碼
客戶端
js檢查
一般都是在網頁上寫一段javascript腳本,校驗上傳文件的后綴名,有白名單形式也有黑名單形式。
查看源代碼可以看到有如下代碼對上傳文件類型進行了限制:
我們可以看到對上傳文件類型進行了限制。
繞過方法
1.我們直接刪除代碼中onsubmit事件中關于文件上傳時驗證上傳文件的相關代碼即可。
或者可以不加載所有js,還可以將html源碼copy一份到本地,然后對相應代碼進行修改,本地提交即可。
2.burp改包,由于是js驗證,我們可以先將文件重命名為js允許的后綴名,在用burp發送數據包時候改成我們想要的后綴。
即可上傳成功:
服務端
黑名單
特殊可解析后綴
? ?
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 . '文件夾不存在,請手工創建!'; }
這里做了黑名單處理,我們可以通過特殊可解析后綴進行繞過。
繞過方法
之前在4中總結過,這里不再贅述,可以使用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);//刪除文件名末尾的點 $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 . '文件夾不存在,請手工創建!'; }}?>
我們發現黑名單限制了很多后綴名,但是沒有限制.htaccess
.htaccess文件是Apache服務器中的一個配置文件,它負責相關目錄下的網頁配置.通過htaccess文件,可以實現:網頁301重定向、自定義404頁面、改變文件擴展名、允許/阻止特定的用戶或者目錄的訪問、禁止目錄列表、配置默認文檔等功能。
繞過方法
我們需要上傳一個.htaccess文件,內容為:
SetHandler application/x-httpd-php
這樣所有的文件都會解析為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);//刪除文件名末尾的點 $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也進行了檢測,但是沒有對大小寫進行統一。
繞過方法
后綴名改為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);//刪除文件名末尾的點 $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 . '文件夾不存在,請手工創建!'; }
黑名單沒有對文件中的空格進行處理,可在后綴名中加空格繞過。
繞過方法
點繞過
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 . '文件夾不存在,請手工創建!'; }
windows會對文件中的點進行自動去除,所以可以在文件末尾加點繞過,不再贅述
::$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);//刪除文件名末尾的點 $file_ext = strrchr($file_name, '.'); $file_ext = strtolower($file_ext); //轉換為小寫 $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA $file_ext = trim($file_ext); //首尾去空 if (!in_array($file_ext, $deny_ext)) { $temp_file = $_FILES['upload_file']['tmp_name']; $img_path = UPLOAD_PATH.'/'.$file_name; if (move_uploaded_file($temp_file, $img_path)) { $is_upload = true; } else { $msg = '上傳出錯!'; } } else { $msg = '此文件類型不允許上傳!'; } } else { $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!'; }}
這里對文件名進行了處理,刪除了文件名末尾的點,并且把處理過的文件名拼接到路徑中。
繞過方法
這里我們可以構造文件名1.PHP. . (點+空格+點),經過處理后,文件名變成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 = '上傳出錯!';
}
} else {
$msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
}
}
繞過方法
這里我們可以看到將文件名替換為空,我們可以采用雙寫繞過: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 = '上傳出錯!'; } } else { $msg = '文件類型不正確,請重新上傳!'; } } else { $msg = UPLOAD_PATH.'文件夾不存在,請手工創建!'; }
繞過方法
這里檢查Content-type,我們burp抓包修改即可繞過:
%00 截斷
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類型文件!"; }}
$img_path直接拼接,因此可以利用%00截斷繞過
繞過方法
然后直接訪問/upload/1.php即可
00截斷(post)
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傳進來的,還是利用00截斷,但這次需要在二進制中進行修改,因為post不會像get對%00進行自動解碼。
繞過方法
接下來訪問1.php即可
文件內容檢查
文件幻數檢測
主要是檢測文件內容開始處的文件幻數,比如圖片類型的文件幻數如下,
要繞過jpg 文件幻數檢測就要在文件開頭寫上下圖的值:
Value = FF D8 FF E0 00 10 4A 46 49 46
要繞過gif 文件幻數檢測就要在文件開頭寫上下圖的值
Value = 47 49 46 38 39 61
要繞過png 文件幻數檢測就要在文件開頭寫上下面的值
Value = 89 50 4E 47
然后在文件幻數后面加上自己的一句話木馬代碼就行了
文件相關信息檢測
圖像文件相關信息檢測常用的就是getimagesize()函數
只需要把文件頭部分偽造好就ok 了,就是在幻數的基礎上還加了一些文件信息
有點像下面的結構
GIF89a
(...some binary data for image...)<?php phpinfo(); ?>
(... skipping the rest of binary data ...)
本次環境中的文件頭檢測,getimagesize,php_exif都可以用圖片馬繞過:
copy normal.jpg /b + shell.php /a webshell.jpg
文件加載檢測
一般是調用API 或函數去進行文件加載測試,常見的是圖像渲染測試,甚至是進行二次渲染(過濾效果幾乎最強)。對渲染/加載測試的攻擊方式是代碼注入繞過,對二次渲染的攻擊方式是攻擊文件加載器自身。
對渲染/加載測試攻擊- 代碼注入繞過
可以用圖像處理軟件對一張圖片進行代碼注入
用winhex 看數據可以分析出這類工具的原理是在不破壞文件本身的渲染情況下找一個空白區進行填充代碼,一般會是圖片的注釋區
對于渲染測試基本上都能繞過,畢竟本身的文件結構是完整的
二次渲染
imagecreatefromjpeg二次渲染它相當于是把原本屬于圖像數據的部分抓了出來,再用自己的API 或函數進行重新渲染在這個過程中非圖像數據的部分直接就隔離開了
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"; $newimagepath = UPLOAD_PATH.$newfilename; imagejpeg($im,$newimagepath); //顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片) $img_path = UPLOAD_PATH.$newfilename; @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"; $newimagepath = UPLOAD_PATH.$newfilename; imagepng($im,$newimagepath); //顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片) $img_path = UPLOAD_PATH.$newfilename; @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"; $newimagepath = UPLOAD_PATH.$newfilename; imagegif($im,$newimagepath); //顯示二次渲染后的圖片(使用用戶上傳圖片生成的新圖片) $img_path = UPLOAD_PATH.$newfilename; @unlink($target_path); $is_upload = true; } } else { $msg = "上傳出錯!"; } }else{ $msg = "只允許上傳后綴為.jpg|.png|.gif的圖片文件!"; }}
本關綜合判斷了后綴名、content-type,以及利用imagecreatefromgif判斷是否為gif圖片,最后再做了一次二次渲染。
繞過方法
得去找圖片經過GD庫轉化后沒有改變的部分,再將未改變的部分修改為相應的php代碼。
條件競爭
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 = '上傳出錯!'; }}
這里先將文件上傳到服務器,然后通過rename修改名稱,再通過unlink刪除文件,因此可以通過條件競爭的方式在unlink之前,訪問webshell。
繞過方法
然后不斷訪問webshell:
上傳成功。
參考鏈接:
https://blog.csdn.net/Kevinhanser/article/details/81613003
https://secgeek.net/bookfresh-vulnerability/
https://xz.aliyun.com/t/2435
上傳環境源碼:https://github.com/c0ny1/upload-labs
更多推薦
內網橫向滲透的常用姿勢
滲透測試之提權方式總結
滲透測試之linux系統提權總結
國內SRC漏洞挖掘經驗和自用技巧
任意文件上傳漏洞 getshell 教程