upload-labs
- 2020 年 4 月 29 日
- 筆記
- MySQL, notebook系列, Web安全
簡介
GitHub地址://github.com/Tj1ngwe1/upload-labs
有關php文件上傳
PHP $_FILES函數詳解: (//www.cnblogs.com/laijinquan/p/8682282.html)//www.cnblogs.com/laijinquan/p/8682282.html
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
-
禁止上傳如上這麼多文件類型,依然是黑名單,但未限制 .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文件(這裡上傳的文件路徑未改變)
效果如圖:
pass-6 黑名單-大小寫繞過
-
查看源碼會發現未過濾大小寫
-
木馬改名為1.PhP即可上傳
pass-7 黑名單-文件末尾加空格繞過
-
bp抓包文件尾加倆空格
pass-8 黑名單-文件末尾加.繞過
原理: windows會對文件中的點進行自動去除,所以可以在文件末尾加點繞過
-
bp抓包改文件名為1.php.
pass-9 黑名單-::$DATA繞過
pass-10 黑名單- .空格.繞過
-
程式碼過濾不嚴格 抓包改文件名為1.php. .可以繞過
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狀態
-
抓包發現上傳路徑
-
改shell名為1.jpg
-
抓包修改save_path = ../upload/1.php%00
pass-13 白名單-00截斷
-
抓包改上傳路徑
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生成圖片馬,直接上傳
pass-15 getimagesize() 繞過
getimagesize() : //c.biancheng.net/view/6259.html
-
使用getimagesize()檢查圖片
-
繞過方法同上,製作圖片馬即可
pass-16 exif_imagetype()
exif_imagetype() : //www.php.net/manual/zh/function.exif-imagetype.php
-
繞過方法同上
pass-17 二次渲染
-
圖片上傳後,服務端會重新進行渲染,木馬可能會遭到破壞
-
繞過思路是對比原圖片與上傳後的圖片,看看哪部分沒有變
-
詳情參考: //xz.aliyun.com/t/2657
備份鏈接://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
-
開始爆破後不停刷新頁面,手速夠快是可以刷出來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()獲取文件名
-
加點Windows下自動忽略會使其獲得的文件路徑為空,從而通過驗證
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