文件上传漏洞——upload-labs(11-20)
前言:上次文件上傳漏洞學(xué)習(xí)到第十關(guān),這次繼續(xù)學(xué)習(xí)
第十一關(guān)
分析源碼
前面幾行代碼都是對后綴名進行限制,最重要的就是這一句代碼
發(fā)現(xiàn)save_path用戶是可控的,那么就利用%00截斷來繞過
在此之前,先來了解一下截斷上傳的原理
在url中%00表示ascll碼中的0 ,而ascii中0作為特殊字符保留,表示字符串結(jié)束,所以當(dāng)url中出現(xiàn)%00時就會認為讀取已結(jié)束,而忽略后面上傳的文件或圖片,只上傳截斷前的文件或圖片
可以通過一個例子詳解的了解一下
<% path="upload/web/" file="1.jpg" upfilename=path & file '最后的上傳地址 %>將路徑改為path="upload/web/1.php%00",那么拼接之后,文件上傳時就變成了
"upload/web/1.php%001.jpg",這時上傳便將1.php上傳進去,而1.jpg則被截斷,我理解的就是相對于省略符號,將后面的內(nèi)容給省略了,相當(dāng)于MySQL注入語句中的#、--+等
下面就來做題,幾乎是一模一樣
上傳成功
不過在上傳時我才明白,原來截斷了1 .jpg,但是1.jpg的內(nèi)容是被1.php給繼承過去了,我還一直認為是必須自己創(chuàng)建1.php, 里面包含內(nèi)容那。。。,這次真的學(xué)習(xí)到了
方法:%00截斷
附上大師傅們的博客
截斷上傳原理剖析
00截斷原理分析
差點忘記了最重要的一條,要進行配置才能進行%00繞過
截斷條件:
找到并修改即可
第十二關(guān)
分析源碼
和十一關(guān)的代碼基本相同,但是有一個點是不同的$_POST['save_path'],save_path是通過post傳進來的,只是傳進來的方式不同,繞過的方法應(yīng)該還是%00截斷
但是這次不能直接抓包在后面加上%00,因為post不會像get一樣對%00進行自動解碼,所以得換另一種方法進行%00繞過,查看大師傅的做法才知道要在二進制中進行修改
將70 68 70后面的2b改為00即可繞過
上傳成功
方法:%00截斷
第十三關(guān)
那就先來做圖片木馬
輸入命令
copy 1.jpg /b + 1.php /a shell.jpg一句話木馬確實已經(jīng)插入
接下來就結(jié)合文件包含漏洞將圖片中的php文件進行解析
upload-labs自帶有文件包含漏洞
解析成功
分析一下源碼
function getReailFileType($filename){$file = fopen($filename, "rb");//fopen() 函數(shù)打開文件或者 URL,"r" 只讀方式打開,將文件指針指向文件頭$bin = fread($file, 2); //只讀2字節(jié)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 = "上傳出錯!";}} }可以看出做出限制的是這一段代碼
$bin = fread($file, 2); //只讀2字節(jié)通過讀文件的前2個字節(jié)判斷文件類型,沒有其他防護,所以可以上傳圖片馬解析即可
第十四關(guān)
用十三關(guān)的圖片馬一樣可以解析
分析一下源碼
進行限制的是這兩段代碼
$info = getimagesize($filename);$ext = image_type_to_extension($info[2]);通過使用getimagesize()檢查是否為圖片文件,所以還是可以用第十三關(guān)的圖片馬繞過
第十五關(guān)
查看一下源碼
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 = "上傳出錯!";}} }做出限制的代碼為:
$image_type = exif_imagetype($filename);exif_imagetype函數(shù)獲取圖片類型,使用exif_imagetype()檢查是否為圖片文件
,所以還是可以用第十關(guān)的方法,這幾關(guān)可以了解一些獲取圖片類型的函數(shù)
第十六關(guān)
如果還使用第十三關(guān)的圖片馬,發(fā)現(xiàn)其中的PHP代碼沒有解析出來,分析一下源碼,看下源碼都做出了那些限制
$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); //imagecreatefromjpeg():創(chuàng)建一塊畫布,并從 JPEG 文件或 URL 地址載入一副圖像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的圖片文件!";} }先來了解一下代碼中出現(xiàn)的一些函數(shù)
imagecreatefromgif():創(chuàng)建一塊畫布,并從 GIF 文件或 URL 地址載入一副圖像 imagecreatefromjpeg():創(chuàng)建一塊畫布,并從 JPEG 文件或 URL 地址載入一副圖像 imagecreatefrompng():創(chuàng)建一塊畫布,并從 PNG 文件或 URL 地址載入一副圖像 imagecreatefromwbmp():創(chuàng)建一塊畫布,并從 WBMP 文件或 URL 地址載入一副圖像 imagecreatefromstring():創(chuàng)建一塊畫布,并從字符串中的圖像流新建一副圖像 move_uploaded_file() 函數(shù)將上傳的文件移動到新位置。上面的代碼判斷了文件后綴和content-type,而且后面的代碼又考察了二次渲染
看了很多大師傅們的博客,都說這道題考查的是圖像的二次渲染,但同時這段代碼是存在邏輯漏洞的
用move_uploaded_file()作if條件做判斷時,如果返回true,上傳的文件不管是否符號要求,到可以上傳到服務(wù)器,不過這里主要考察的是二次渲染,接下來就用最簡便的GIF圖片來繞過二次渲染
上傳GIF圖片馬
上傳發(fā)現(xiàn)沒有解析成功,將上傳的圖片下載下來,用winhex打開觀察一下
經(jīng)過二次渲染,發(fā)現(xiàn)文件名已經(jīng)改變而且末尾的PHP代碼已經(jīng)被去除,既然后面插入不了那就對比一些上傳前和上傳后的圖片,看看那些部分是沒有改變的,將一句話插入其中
經(jīng)過對比,這一段都是相同的,可以將代碼插入其中,發(fā)現(xiàn)上傳后的圖片依然有PHP代碼,上傳成功
還有JPEG和PNG圖片上傳,但是都需要腳本,這里就暫時先不用這兩種方法了,不過可以參考大師傅的博客,upload-labs之pass 16詳細分析
方法: 圖片對比,在winhex將代碼插入到相同的部位進行繞過
第十七關(guān)
提示:需要代碼審計!
那就來分析代碼
$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; //in_array() 函數(shù)搜索數(shù)組中是否存在指定的值。 //rename() 函數(shù)重命名文件或目錄。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 = '上傳出錯!';} } 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;這一段代碼先將文件上傳到服務(wù)器,再判斷后綴名,如果合法則保留下來,如果不合法,后面這段代碼則起刪除作用,刪除在服務(wù)器的文件
$msg = "只允許上傳.jpg|.png|.gif類型文件!";unlink($upload_file);unlink() 函數(shù)刪除文件
所以根據(jù)這個流程,可以通過條件競爭的方式在unlink()函數(shù)刪除之前,訪問上傳文件,在此之前先來了解一下條件競爭
條件競爭漏洞是一種服務(wù)器端的漏洞,由于服務(wù)器端在處理不同用戶的請求時是并發(fā)進行的,因此,如果并發(fā)處理不當(dāng)或相關(guān)操作邏輯順序設(shè)計的不合理時,將會導(dǎo)致此類問題的發(fā)生。
接下來就利用條件競爭刪除文件的時間差繞過
在burp中不斷發(fā)送上傳webshell的數(shù)據(jù)包,然后不斷在瀏覽器中訪問,發(fā)現(xiàn)通過競爭可以訪問到,設(shè)置多線程控制攻擊請求的并發(fā)數(shù),但是我的burp有問題,無法設(shè)置多線程,所以沒有辦法復(fù)現(xiàn)出來
方法:條件競爭
第十八關(guān)
隨便上傳圖片馬,發(fā)現(xiàn)
審計一下代碼
先是 $ret = $this->move();,進行了一次文件保存,然后再 $ret = $this->renameFile();,進行了一次更改文件名,所以可以用條件競爭來進行繞過
方法:條件競爭
第十九關(guān)
發(fā)現(xiàn)和之前有些不一樣
查看一下源碼
查看大師傅的博客,
發(fā)現(xiàn)move_uploaded_file會忽略掉文件末尾的/.
而且文件名是從$_FILES['upload_file']['tmp_name']中獲取的,所以用戶是可以進行控制的,所以通過/. 來進行繞過
上傳成功
除此之外那也可以用用move_uploaded_file函數(shù)的00截斷漏洞繞過
第二十關(guān)
來源一道CTF題,需要審計代碼,目前自己還審計不了,就參考大師傅們的,暫時先留到這,等水平提高了,再回頭看這道題
總結(jié):通過upload-labs又學(xué)習(xí)到了很多很好玩的知識,接下來學(xué)習(xí)又關(guān)密碼學(xué)的知識,少年,繼續(xù)加油!
參考博客:
Upload-labs 20關(guān)通關(guān)筆記
Upload-labs通關(guān)手冊
總結(jié)
以上是生活随笔為你收集整理的文件上传漏洞——upload-labs(11-20)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 实验吧——SQL注入 Write up(
- 下一篇: 文件包含漏洞——DVWA练习