1. 程式人生 > 實用技巧 >upload - labs (下)

upload - labs (下)

Pass - 11:

1.檢視原始碼,發現進行了一次對字尾名替換成空格,因此考慮雙寫繞過,

2.上傳成功,

關鍵程式碼:

$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","ini"); $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 . '資料夾不存在,請手工建立!'; } }

Pass -12:

1.檢視原始碼,看到是白名單判斷,但是$img_path直接拼接嘗試%00截斷,但在進行move_uploaded_file前。利用$_GET['save_path']和隨機時間函式進行拼接,拼接成檔案儲存路徑。

因此構造檔案儲存路徑利用了_GET傳入:(注意%00要進行編碼)

2.上傳成功

檢視原始碼:

$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 = '上傳出錯!';
        }
    } else{
        $msg = "只允許上傳.jpg|.png|.gif型別檔案!";
    }
}

補充:

截斷條件:
1、php版本小於5.3.4
2、php.ini的magic_quotes_gpc為OFF狀態

Pass - 13:

同Pass - 12,唯一的區別就是GET換成了POST,

但這次需要在二進位制中進行修改,因為post不會像get對%00進行自動解碼。

關鍵程式碼:

$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 - 14:

1.任務要求上傳圖片馬,

2.製作圖片馬,檢視原始碼可知,通過讀檔案的前2個位元組判斷檔案型別,也可以在一句話檔案內容前面加圖片的標識例如GIF89a。

3.上傳成功,

關鍵程式碼:

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;
}

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

補充:

unpack() 函式從二進位制字串對資料進行解包。

Pass - 15:

1.檢視一下提示,

2.檢視原始碼,用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 = "上傳出錯!";
        }
    }
}

補充:

getimagesize() 函式用於獲取影象大小及相關資訊,成功返回一個數組,失敗則返回 FALSE 併產生一條 E_WARNING 級的錯誤資訊。

語法格式:
array getimagesize ( string $filename [, array &$imageinfo ] )

getimagesize() 函式將測定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 影象檔案的大小並返回影象的尺寸以及檔案型別及圖片高度與寬度。

Pass - 16:

1.檢視提示,

2.檢視原始碼,用到php_exif模組來判斷檔案型別,還是直接就可以利用圖片馬就可進行繞過

關鍵程式碼:

function isImage($filename){
    //需要開啟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 = "上傳出錯!";
        }
    }
}

補充:

exif_imagetype — 判斷一個影象的型別

exif_imagetype ( string $filename ) : int
exif_imagetype() 讀取一個影象的第一個位元組並檢查其簽名。

本函式可用來避免呼叫其它 exif 函式用到了不支援的檔案型別上或和 $_SERVER['HTTP_ACCEPT'] 結合使用來檢查瀏覽器是否可以顯示某個指定的影象。    

Pass - 17:

(重點!!!)

1.檢視原始碼,

判斷檔案型別Content-Type:

$filetype = $_FILES['upload_file']['type'];

獲取檔案字尾副檔名:

$fileext= substr(strrchr($filename,"."),1);

然後根據不同的檔案字尾副檔名進行二次渲染:

jpg:
$im = imagecreatefromjpeg($target_path);	#使用上傳的圖片生成新的圖片(二次渲染)
png:
$im = imagecreatefrompng($target_path);
gif:
$im = imagecreatefromgif($target_path);

2.上傳方法與前幾關類似。

關鍵程式碼:

$is_upload = false;
$msg = null;
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";
                //顯示二次渲染後的圖片(使用使用者上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagejpeg($im,$img_path);
                @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";
                //顯示二次渲染後的圖片(使用使用者上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagepng($im,$img_path);

                @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";
                //顯示二次渲染後的圖片(使用使用者上傳圖片生成的新圖片)
                $img_path = UPLOAD_PATH.'/'.$newfilename;
                imagegif($im,$img_path);

                @unlink($target_path);
                $is_upload = true;
            }
        } else {
            $msg = "上傳出錯!";
        }
    }else{
        $msg = "只允許上傳字尾為.jpg|.png|.gif的圖片檔案!";
    }
}

補充:

imagecreatefromgif — 由檔案或 URL 建立一個新圖象。
說明 
imagecreatefromgif ( string $filename ) : resource

imagecreatefromgif() 返回一影象識別符號,代表了從給定的檔名取得的影象。 

參考:

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

Pass - 18:

思路:

檢視程式碼,需要程式碼審計,檢視原始碼,先move_uploaded_file函式將上傳檔案臨時儲存,再進行判斷,如果不在白名單裡則unlink刪除,在的話就rename重新命名,所以這裡存在條件競爭。

因此可以上傳aaa.php只需要在它刪除之前訪問即可,可以利用burp的intruder模組不斷上傳,然後不斷地訪問重新整理該地址即可。

步驟:

1.用burp開啟兩個intruder模組,一個用於重複上傳,另一個用於重複訪問。先設定上傳請求,記住此處的檔名,等下要用來拼接訪問請求的url。

因為此處沒有什麼引數需要爆破,只是需要重複發起請求,所以payload設定為Null payloads,設定訪問次數10000次,執行緒50個

3.設定訪問請求:

①瀏覽器構造請求url:http://127.0.0.1/upload-labs/upload/aaa.php,進行訪問,然後用burp抓包
②burp抓包後傳送至intruder模組,然後設定payload,這一步和上傳請求設定差不多,都是Null payloads、10000次、50個執行緒

4.設定好兩個模組後同時啟動,觀察結果,因為我們傳入的php程式碼是phpinfo();,所以如果訪問成功的話,會返回php的配置資訊。

5.大部分訪問結果是狀態碼是404。
因為條件競爭繞過存在一定概率,實踐中如果一次不成功,可以多試幾次。

關鍵程式碼:

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

補充:

strrpos() 函式查詢字串在另一字串中最後一次出現的位置(區分大小寫)。

  註釋:strrpos() 函式是區分大小寫的。

相關函式:

  • strpos() - 查詢字串在另一字串中第一次出現的位置(區分大小寫)
  • stripos() - 查詢字串在另一字串中第一次出現的位置(不區分大小寫)
  • strripos() - 查詢字串在另一字串中最後一次出現的位置(不區分大小寫)
move_uploaded_file() 函式把上傳的檔案移動到新位置。

如果成功該函式返回 TRUE,如果失敗則返回 FALSE。
語法
move_uploaded_file(file,newloc) 

 註釋:該函式僅用於通過 HTTP POST 上傳的檔案。

  註釋:如果目標檔案已經存在,將會被覆蓋。

Pass - 19:

思路:

檢視原始碼,先將上傳的檔案儲存(move函式),再rename重新命名一下。所以也存在條件競爭,繞過方法和上面Pass-18差不多

關鍵程式碼:

//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" );

......
......
......  
  /** upload()
   **
   ** Method to upload the file.
   ** This is the only method to call outside the class.
   ** @para String name of directory we upload to
   ** @returns void
  **/
  function upload( $dir ){
    
    $ret = $this->isUploadedFile();
    
    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" );
  
  }
......
......
...... 
};
View Code

Pass - 20:

(重要!!!)

1.檢視原始碼,要繞過.jpg,

2.move_uploaded_file()函式會忽視檔名末尾的 /.

因此可以構造aaa.php/.進行繞過,

post: save_name = aaa.php%00.jpg
post: save_name = aaa.php/.

3.上傳成功,

關鍵程式碼:

$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 = '上傳出錯!';
            }
        }else{
            $msg = '禁止儲存為該型別檔案!';
        }

    } else {
        $msg = UPLOAD_PATH . '資料夾不存在,請手工建立!';
    }
}

補充:

pathinfo() 函式
定義和用法
pathinfo() 函式以陣列的形式返回關於檔案路徑的資訊。

返回的陣列元素如下:
    [dirname]: 目錄路徑
    [basename]: 檔名
    [extension]: 檔案字尾名
    [filename]: 不包含字尾的檔名

語法
pathinfo(path,options)
path 必需。規定要檢查的路徑。
options 可選。規定要返回的陣列元素。預設是 all。

可能的值:

  • PATHINFO_DIRNAME - 只返回 dirname
  • PATHINFO_BASENAME - 只返回 basename
  • PATHINFO_EXTENSION - 只返回 extension
  • PATHINFO_FILENAME - 只返回 filename


 如果不是請求所有的元素,則 pathinfo() 函式返回字串

Pass - 21:

1.看檢視原始碼,第5-6行先進行了一個Content-Type判斷

 $allow_type = array('image/jpeg','image/png','image/gif');
    if(!in_array($_FILES['upload_file']['type'],$allow_type)){

2.10-13行,如果save_name是字串的話就通過explode函式,將post進去的save_name轉成小寫後按’.'打散成陣列。

$file = empty($_POST['save_name']) ? $_FILES['upload_file']['name'] : $_POST['save_name'];
        if (!is_array($file)) {
            $file = explode('.', strtolower($file));

3.第20行,由於後面filename構成的過程中由於file[count(file[count(file[count(file) - 1]的作用,導致$file[1] = NULL,所以構造檔名後相當於直接就是xx.php/.,

$file_name = reset($file) . '.' . $file[count($file) - 1]; 

關鍵程式碼:

$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 = "請選擇要上傳的檔案!";
}

參考:

https://blog.csdn.net/weixin_41182861/article/details/105546654