上传漏洞学习——upload-labs 闯关(二)
文章目錄
- 前言:
- Less-11(get型 %00截斷)
- Less-12(post型 00截斷)
- Less-13(圖片馬繞過)
- Less-14(getimagesize檢測)
- Less-15(exif_imagetype圖片馬)
- Less-16(二次渲染繞過)
- Less-17(條件競爭)
- Less-18(條件競爭)
- Less-19(post型 00截斷)
前言:
接著上篇的總結 (= ̄ω ̄=) 上篇鏈接:點這
Less-11(get型 %00截斷)
這關采用的防御手法是白名單過濾,只允許上傳jpg、png和gif類型,并且將上傳的文件給重命名為了白名單中的后綴。
查看源碼:
$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類型文件!";}}處理上傳文件的方式
$img_path = $_GET['save_path']."/".rand(10, 99).date("YmdHis").".".$file_ext;看起來這樣防御并沒有什么問題,但是這一關的上傳目錄是可控的,所以可以先上傳一個后綴名為.jpg,然后修改上傳目錄為.php后綴,之后在.php后,截斷后面的拼接內容。注意這里需要關掉magic_quotes_gpc這個php擴展,否則00會被轉義。
$_GET['save_path']這里使用00截斷."/".rand(10, 99).date("YmdHis").".".$file_ext;截斷的條件:
關閉 magic_quotes_gpc 函數:在php.ini文件內找到 magic_quotes_gpc = On 將其改為 magic_quotes_gpc = Off
配置好后,上傳 shell.jpg,抓包,添加shell.php%00
上傳成功。
Less-12(post型 00截斷)
和 Less-11不同,這關的save_path是通過 post 傳進來的,我們還利用00截斷,但這題需要在十六進制中進行修改,因為post不會像get對%00進行自動解碼。
步驟:上傳 webshell.jpg 然后 send to repeater
添加文件 wenshell.php(空格)
空格的十六進制為20然后找到20 改為00
然后點擊send 發包就好了
發包成功。
Less-13(圖片馬繞過)
PS:這關需要將服務器版本改到PHP5.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 = "上傳出錯!";}} }發現主要是取上傳文件的頭兩個字節判斷文件類型,因此直接上傳圖片馬即可;
圖片馬制作方法:
copy 1.jpg /b + shell.php /a webshell.jpg解釋:參數/b指定以二進制格式復制、合并文件(圖片),參數/a指定以ASCII格式復制、合并文件(php文件)。
制作成功
然后直接上傳
上傳成功,得到文件名,如果是上傳的是一句話木馬就能連接菜刀了;但我們上傳的是圖片馬,可以利用文件包含漏洞進行測試。
先新建一個包含文件漏洞的頁面upload.php,將該文件放在根目錄下:
<?php $file = $_GET[ 'page' ]; include($file); ?>測試使用,包含成功
http://127.0.0.1/upload-labs-master/upload/include.php?page=文件名
另外有時候對文件大小也有限制,所以繞過文件幻數最合適的方式是利用16進制編輯器自己制作一個偽圖片馬,這里利用winhex創建shell.jpg偽圖片馬
Less-14(getimagesize檢測)
查看關鍵代碼:
$types = '.jpeg|.png|.gif';if(file_exists($filename)){$info = getimagesize($filename);$ext = image_type_to_extension($info[2]);1234這里用 getimagesize 獲取文件類型,還是直接就可以利用圖片馬就可進行繞過,繞過方法同Less13 ,這里就不演示了。
補充:
getimagesize() 函數將測定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 圖像文件的大小并返回圖像的尺寸以及文件類型和一個可以用于普通 HTML 文件中 IMG 標記中的 height/width 文本字符串。
Less-15(exif_imagetype圖片馬)
關鍵源碼:
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;} }利用php_exif模塊判斷文件類型,還是直接利用圖片馬就可以繞過。(查看下你的php_exif模塊是否打開,沒有的話就勾上)
然后直接上傳圖片馬,仍和 less-13一樣
上傳成功。
Less-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的圖片文件!";} }通過源碼可以看到對文件后綴名和 MIME 類型進行了檢查,而且用到了php的imagecreatefromjpeg、imagecreatefrompng、imagecreatefromgif這幾個圖片處理函數對上傳的圖片進行了二次渲染生成了新的圖片,所以如果在這里上傳的是一個普通的圖片馬,雖然圖片馬可以上傳成功,但是上傳的圖片馬在經過二次渲染后,圖片尾部的php代碼就會被刪除掉,所以在這里不能使用直接在圖片尾部添加一句話木馬的方式去合成圖片馬。
但是這一關的代碼有一個明顯的邏輯漏洞,如果這幾個二次渲染函數處理的不是一個圖片,就會使這幾個函數報錯,因為這幾個二次渲染的函數只會去處理一個圖片內部格式正確的圖片,所以在這里只需要上傳一個后綴名為jpg、png、gif的一句話木馬,這樣的話上傳的一句話木馬會繞過后綴名和 MIME 類型的檢查,通過move_uploaded_file上傳至服務器,但是遇到二次渲染時,由于上傳的不是一個真正的圖片,所以二次渲染函數在處理時會因為圖片的內部格式報錯,從而突破了對圖片的二次渲染,這時候頁面雖然會顯示圖片格式不允許,但是上傳的一句話木馬已經上傳到了服務器
上傳后綴名為jpg、png、gif的圖片馬:
可以看到上傳成功,但是我的并沒有成功解析;
wenHex打開發現并查找不到我們的木馬
無奈 翻翻大佬們的blog發現是在二次渲染的時候被替換了,至于解決辦法請看這位大佬寫的點這我就不再描述(●’?’●)
Less-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 = '上傳出錯!';} }這題我是蒙蔽的,好在看了大佬的操作才后知道了些;這里先將文件上傳到服務器,然后判斷文件后綴是否在白名單里,如果在則重命名,否則刪除,因此我們可以上傳 webshell 只需要在它刪除之前訪問即可。可以利用burp的intruder模塊不斷上傳,然后我們不斷的訪問刷新該地址。
-
unlink() 函數是用來刪除文件的
-
什么是條件競爭:
條件競爭漏洞是一種服務器端的漏洞,由于服務器端在處理不同用戶的請求時是并發進行的,因此,如果并發處理不當或相關操作邏輯順序設計的不合理時,將會導致此類問題的發生。
1、抓包:
Send to lntruder,設置參數
設置Payloads選項參數:
點擊 Start attack
訪問 http://127.0.0.1/upload-labs/upload/1.php 并不斷刷新:
訪問成功!
Less-18(條件競爭)
本關需要上傳圖片馬,查看代碼:
$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 1if( $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 fileif( $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" );} ...... ...... ...... };本關對文件后綴名做了白名單判斷,然后會一步一步檢查文件大小、文件是否存在等等,將文件上傳后,然后再
$ret = $this->renameFile();,進行了一次更改文件名;同樣存在條件競爭的漏洞。可以不斷利用burp發送上傳圖片馬的數據包,由于條件競爭,程序會出現來不及rename的問題,從而上傳成功。
Less-19(post型 00截斷)
查看源碼:
$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 . '文件夾不存在,請手工創建!';} }分析,move_uploaded_file()函數中的img_path是由post參數save_name控制的,因此可以在save_name利用00截斷繞過。
首先上傳一個圖片馬,后綴名改為php+jpg
然后再16進制中把加號的2b 改為 00 fordward發包就行了。
上傳成功!
然后我又發現,這題可以直接加空格繞過
上傳成功。
好了,到這暫時就結束了至于Less20,需要審計代碼,目前自己還做不了。
總結
以上是生活随笔為你收集整理的上传漏洞学习——upload-labs 闯关(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 上传漏洞学习——upload-labs
- 下一篇: 远程命令执行与代码执行(remote c