upload-labs

簡介

GitHub地址://github.com/Tj1ngwe1/upload-labs

mind-map_thumb[2]

有關php文件上傳

PHP $_FILES函數詳解: (//www.cnblogs.com/laijinquan/p/8682282.html)//www.cnblogs.com/laijinquan/p/8682282.html

1585471120600_thumb[2]

pass-1 前端js驗證

前端js過濾文件後綴名,頁面禁用js即可

 在這裡插入圖片描述

pass-2 後端MIME驗證

  • Content-Type 實體頭部用於指示資源的MIME類型

  • media type ,在響應中,Content-Type標頭告訴客戶端實際返回的內容的內容類型。

  • 常見Content-Type //www.cnblogs.com/klb561/p/10090540.html 源碼: 

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

 

  • 抓包,發現Content-Type為application/…

  • 改為圖片格式image/png即繞過伺服器端驗證

  •  在這裡插入圖片描述

pass-3 黑名單驗證

提示:不允許上傳.asp,.aspx,.php,.jsp後綴文件! 未知的風險太多,黑名單過濾的結果無法預測!

 在這裡插入圖片描述

源碼的過濾不可繞過

 在這裡插入圖片描述

  • 上傳如php2,php3、php4、php5這些後綴的文件,但可能無法解析, 需要配置文件中有 AddType application/x-httpd-php .php .phtml .phps .php5 .pht

  • 也可以上傳如cer文件

  • 黑名單未限制.htaccess,且.htaccess有效

.htaccess文件是Apache伺服器中的一個配置文件,它負責相關目錄下的網頁配置.通過htaccess文件,可以實現:網頁301重定向、自定義404頁面、改變文件擴展名、允許/阻止特定的用戶或者目錄的訪問、禁止目錄列表、配置默認文檔等功能

//blog.csdn.net/qq_45555226/article/details/104846799 – 上傳.htaccess文件,內容為 SetHandler application/x-httpd-php – 再上傳php5等文件

pass 4 黑名單驗證.htaccess

1585383895249_thumb[1]

  • 禁止上傳如上這麼多文件類型,依然是黑名單,但未限制 .htaccess

  • 上傳內容為SetHandler application/x-httpd-php的文件,任意會解析成php類型,在上傳無文件後綴的shell即可

  • 前提是配置文件有效

pass-5 黑名單驗證.user.ini.

關於.user.ini //segmentfault.com/a/1190000011552335?utm_source=tag-newest

  • 創建一個名為.user.ini的文件內容為

     `auto_prepend_file=1.gif`

     

  • 創建一句話木馬命名為1.gif

  • 題目提示已經有readme.php文件

  • 將1.gif和.user.ini文件上傳,訪問readme.php時會自動包含1.gif文件(這裡上傳的文件路徑未改變)

效果如圖:

1585400719063_thumb[2]

pass-6 黑名單-大小寫繞過

  • 查看源碼會發現未過濾大小寫

1585400792334_thumb[1]

  • 木馬改名為1.PhP即可上傳

pass-7 黑名單-文件末尾加空格繞過

  • bp抓包文件尾加倆空格

1585402731898_thumb[1]

pass-8 黑名單-文件末尾加.繞過

原理: windows會對文件中的點進行自動去除,所以可以在文件末尾加點繞過

  • bp抓包改文件名為1.php.

1585401133710_thumb[1]

  • 可直接鏈接1.php

    1585401723641_thumb[2]

pass-9 黑名單-::$DATA繞過

原理: //www.jianshu.com/p/b1a130902b4e

  • 抓包將文件後綴改為php::$DATA

  • 1585402299441_thumb[1]

  • 文件名經過處理

  • 1585402459250_thumb[1]

  • 訪upload/upload/202003282132239300.php

    1585402512016_thumb[1]

pass-10 黑名單- .空格.繞過

  • 程式碼過濾不嚴格 抓包改文件名為1.php. .可以繞過

1585471645005_thumb[2]

pass-11 黑名單-雙寫繞過

  • 源碼中採用黑名單,str_ireplace()不區分大小寫替換掉黑名單中存在的後綴

 1 $is_upload = false;
 2  $msg = null;
 3  if (isset($_POST['submit'])) {
 4      if (file_exists(UPLOAD_PATH)) {
 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","ini");
 6  7          $file_name = trim($_FILES['upload_file']['name']);
 8          $file_name = str_ireplace($deny_ext,"", $file_name);
 9          $temp_file = $_FILES['upload_file']['tmp_name'];
10          $img_path = UPLOAD_PATH.'/'.$file_name;        
11          if (move_uploaded_file($temp_file, $img_path)) {
12              $is_upload = true;
13         } else {
14              $msg = '上傳出錯!';
15         }
16     } else {
17          $msg = UPLOAD_PATH . '文件夾不存在,請手工創建!';
18     }
19  }
  • 重命名shell為 1.pphphp 即可繞過

pass-12白名單- 00截斷%00

php版本要小於5.3.4,5.3.4及以上已經修復該問題

magic_quotes_gpc需要為OFF狀態

用法: //www.fujieace.com/penetration-test/file-upload-00.html

原理剖析: //cloud.tencent.com/developer/article/1378895

  • 抓包發現上傳路徑

1585473418934_thumb

  • 改shell名為1.jpg

1585473535261_thumb[1]

  • 抓包修改save_path = ../upload/1.php%00

pass-13 白名單-00截斷

  • 抓包改上傳路徑

1585476817046_thumb[1]

pass-14 檢查文件頭

  • 檢查前兩個位元組看是否是圖片類型

 function getReailFileType($filename){
     $file = fopen($filename, "rb");
     $bin = fread($file, 2); //只讀2位元組
     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;
 }

 

  • 直接用bat生成圖片馬,直接上傳

1585482502576_thumb

1585482437155_thumb

pass-15 getimagesize() 繞過

getimagesize() : //c.biancheng.net/view/6259.html

  • 使用getimagesize()檢查圖片

1585483641665_thumb[1]

  • 繞過方法同上,製作圖片馬即可

pass-16 exif_imagetype()

exif_imagetype() : //www.php.net/manual/zh/function.exif-imagetype.php

  • 繞過方法同上

pass-17 二次渲染

  • 圖片上傳後,服務端會重新進行渲染,木馬可能會遭到破壞

1585483924172_thumb[1]

  • 繞過思路是對比原圖片與上傳後的圖片,看看哪部分沒有變

備份鏈接://files.cnblogs.com/files/l0nmar/upload-labs%E4%B9%8Bpass.rar

pass-18 條件競爭

unlink:刪除文件 //www.w3school.com.cn/php/func_filesystem_unlink.asp

PHP strrpos() 函數://www.w3school.com.cn/php/func_string_strrpos.asp

strrpos() 函數查找字元串在另一字元串中最後一次出現的位置. 對大小寫敏感.

PHP move_uploaded_file() 函數 ://www.w3school.com.cn/php/func_filesystem_move_uploaded_file.asp

 move_uploaded_file(file,newloc)
     file-必需-規定要移動的文件。
     newloc-必需-規定文件的新位置。
  • 審計源碼可以發現 , `move_uploaded_file($temp_file, $upload_file)`

$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 = '上傳出錯!';
    }
 }

 

  • 利用思路: 在刪除$upload_file之前進行訪問shell

  • 隨筆選一個參數爆破

  • 1585487585558_thumb[2]

  • 開始爆破後不停刷新頁面,手速夠快是可以刷出來phpinfo(),可以開兩個爆破,一個請求頁面,一個上傳競爭

pass-19 條件競爭

  • 源碼如下:

//index.php
 $is_upload = false;
 $msg = null;
 if (isset($_POST['submit']))
 {
     require_once("./myupload.php");
     $imgFileName =time();
     $u = new MyUpload($_FILES['upload_file']['name'], $_FILES['upload_file']['tmp_name'], $_FILES['upload_file']['size'],$imgFileName);
     $status_code = $u->upload(UPLOAD_PATH);
     switch ($status_code) {
         case 1:
             $is_upload = true;
             $img_path = $u->cls_upload_dir . $u->cls_file_rename_to;
             break;
         case 2:
             $msg = '文件已經被上傳,但沒有重命名。';
             break; 
         case -1:
             $msg = '這個文件不能上傳到伺服器的臨時文件存儲目錄。';
             break; 
         case -2:
             $msg = '上傳失敗,上傳目錄不可寫。';
             break; 
         case -3:
             $msg = '上傳失敗,無法上傳該類型文件。';
             break; 
         case -4:
             $msg = '上傳失敗,上傳的文件過大。';
             break; 
         case -5:
             $msg = '上傳失敗,伺服器已經存在相同名稱文件。';
             break; 
         case -6:
             $msg = '文件無法上傳,文件不能複製到目標目錄。';
             break;      
         default:
             $msg = '未知錯誤!';
             break;
    }
 }
 ​
 //myupload.php
 class MyUpload{
 ......
 ......
 ...... 
   var $cls_arr_ext_accepted = array(
       ".doc", ".xls", ".txt", ".pdf", ".gif", ".jpg", ".zip", ".rar", ".7z",".ppt",
       ".html", ".xml", ".tiff", ".jpeg", ".png" );
 ​
 ......
 ......
 ......  
   function upload( $dir ){
     
     $ret = $this->isUploadedFile();
     //is_uploaded_file() 函數檢查指定的文件是否是通過 HTTP POST 上傳的。如果文件是通過 HTTP POST 上傳的,該函數返回 TRUE。
     if( $ret != 1 ){
       return $this->resultUpload( $ret );
    }
 ​
     $ret = $this->setDir( $dir );
     if( $ret != 1 ){
       return $this->resultUpload( $ret );
    }
 ​
     $ret = $this->checkExtension(); //檢查擴展名
     if( $ret != 1 ){
       return $this->resultUpload( $ret );
    }
 ​
     $ret = $this->checkSize(); //檢查大小
     if( $ret != 1 ){
       return $this->resultUpload( $ret );    
    }
     
     // if flag to check if the file exists is set to 1
     
     if( $this->cls_file_exists == 1 ){
       
       $ret = $this->checkFileExists();
       if( $ret != 1 ){
         return $this->resultUpload( $ret );    
      }
    }
 ​
     // if we are here, we are ready to move the file to destination
$ret = $this->move();
     if( $ret != 1 ){
       return $this->resultUpload( $ret );    
    }
 ​
     // check if we need to rename the file
if( $this->cls_rename_file == 1 ){
       $ret = $this->renameFile();
       if( $ret != 1 ){
         return $this->resultUpload( $ret );    
      }
    }
     
     // if we are here, everything worked as planned :)
return $this->resultUpload( "SUCCESS" );
   
  }
 ......
 ......
 ...... 
 };

 

  • 對文件進行了大小,擴展名等等檢查,最後重命名

  • 條件競爭會存在不重命名的情況

  • 原理不太清楚…

pass-20 加.繞過

  • 文末加點windows下會自動忽略

  • 源碼中用phpinfo()獲取文件名

1585489076824_thumb[1]

  • 加點Windows下自動忽略會使其獲得的文件路徑為空,從而通過驗證

1585489017100_thumb[1]

pass-21 白名單-數組繞過

  • 源碼如下:

```

 $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));
        }// 如果不是數組就用explode()分割為數組,以 .分割 
$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 = "請選擇要上傳的文件!";
 }
```

 

  • 先修改MIME繞過

  • 再構造數組第一個元素為1.php,第三個為jpg

  • 拼接為1.php+空=1.php

1585490190350_thumb[2]