檔案上傳漏洞:upload-labs(二)
阿新 • • 發佈:2020-09-22
Pass-11
原始碼
$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型別檔案!"; } }
繞過方式
%00截斷繞過
Pass-12
原始碼
$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型別檔案!"; } }
繞過方式
0x00繞過,我們現在路徑後面加個一個空格和一個a,字母a可加可不加,這裡主要是為了對空格進行定位。方便修改
然後修改二進位制為00進行截斷,原理同Pass-11一致。
訪問
Pass-13
原始碼
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 = "上傳出錯!"; } } }
繞過方式
圖片頭欺騙:GIF89a
Pass-14
原始碼
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獲取檔案型別,直接就可以利用圖片馬就可進行繞過
Pass-15
原始碼
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 = "上傳出錯!"; } } }
繞過方式
需要開啟php_exif模組
1.在php.ini檔案中找到;extension=php_exif.dll,去掉前面的分號 2.在php.ini檔案中找到;extension=php_mbstring.dll,去掉前面的分號,並將此行移動到extension=php_exif.dll之前,使之首先載入*。 3.找到[exif]段,把下面語句的分號去掉。 ;exif.encode_unicode = ISO-8859-15 ;exif.decode_unicode_motorola = UCS-2BE ;exif.decode_unicode_intel = UCS-2LE ;exif.encode_jis = ;exif.decode_jis_motorola = JIS ;exif.decode_jis_intel = JIS
Pass-16
原始碼
$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的圖片檔案!"; } }
繞過方式
二次渲染繞過,找到不被渲染的二進位制,更改二進位制。先上傳一個正常圖片,伺服器渲染之後,再把圖片下載下來,和沒有被渲染的圖片做對比,看看有什麼變化,找到沒有變化的地方(也就是渲染不到的地方),寫入惡意程式碼,再上傳,就會執行。
Pass-17
原始碼
$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 = '上傳出錯!'; } }
繞過方式
條件競爭繞過,再圖片上傳到伺服器後,伺服器檢測檔案是否安全,如果不安全,伺服器就把檔案處理掉。條件競爭漏洞就出在這裡,檔案上傳到伺服器上之後,再到檢查檔案、刪除檔案之間有一定的時間差,我們可以利用這個時間差去繞過檢查機制,比如說,在上傳的檔案中寫入一個建立惡意檔案的指令碼,然後我們在刪除之前不斷地訪問這個檔案,只要有一次訪問成功,那麼就會寫入惡意指令碼,這個方法就是條件競爭,存在一定的運氣,多試幾次成功概率會比較大。
首先,上傳檔案,主要目的是在伺服器上建立shell.php檔案,並寫入一句話木馬。然後扔到Intruder模組中
調整配置
然後我們寫一個指令碼不斷地去訪問這個檔案。
可以看到已經訪問成功了,連入菜刀
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" ); } ...... ...... ...... };
繞過方式
閱讀原始碼,檔案上傳之後對檔案進行重新命名,同樣可以使用條件競爭方式進行繞過檢測機制,讓伺服器來不及進行rename。
Pass-19
原始碼
$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 . '資料夾不存在,請手工建立!'; } }
繞過方式
./繞過
Pass-20
原始碼
$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 = "請選擇要上傳的檔案!"; }
繞過方式
閱讀原始碼,通過構造save_name繞過
總結一下