接着上篇的總結 (= ̄ω ̄=) 上篇鏈接:點這
Less-11
這關採用的防禦手法是白名單過濾,只允許上傳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;
注意這裏的00字符因爲在url的GET參數中,所以需用進行url編碼
-
截斷的條件:
1)php版本必須小於5.3.4
2)打開php的配置文件php-ini,將magic_quotes_gpc設置爲Off -
關閉magic_quotes_gpc函數:
在php.ini文件內找到
magic_quotes_gpc = On
將其改爲
magic_quotes_gpc = Off
配置好後,上傳webshell.jpg,抓包,添加webshell.php%00
上傳成功
Less-12
和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
(圖片一句話木馬爲:<?php phpinfo(); ?>
)
解釋:參數/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
查看關鍵代碼:
$types = '.jpeg|.png|.gif';
if(file_exists($filename)){
$info = getimagesize($filename);
$ext = image_type_to_extension($info[2]);1234
這裏用getimagesize獲取文件類型,還是直接就可以利用圖片馬就可進行繞過,繞過方法同Less13 ,這裏就不演示了
知識補充:
array getimagesize ( string $filename [, array &$imageinfo ] )
getimagesize() 函數將測定任何 GIF,JPG,PNG,SWF,SWC,PSD,TIFF,BMP,IFF,JP2,JPX,JB2,JPC,XBM 或 WBMP 圖像文件的大小並返回圖像的尺寸以及文件類型和一個可以用於普通 HTML 文件中 IMG 標記中的 height/width 文本字符串。
如果不能訪問 filename 指定的圖像或者其不是有效的圖像,getimagesize() 將返回 FALSE 併產生一條 E_WARNING 級的錯誤。
Less-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;
}
}
利用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 = '上傳出錯!';
}
}
這題我是矇蔽的,好在看了大佬的操作才後知道了些;這裏先將文件上傳到服務器,然後通過rename修改名稱,再通過unlink刪除文件,因此可以通過條件競爭的方式在unlink之前,訪問webshell。
-
unlink()
函數是用來刪除文件的 -
什麼是條件競爭:
條件競爭漏洞是一種服務器端的漏洞,由於服務器端在處理不同用戶的請求時是併發進行的,因此,如果併發處理不當或相關操作邏輯順序設計的不合理時,將會導致此類問題的發生。
- 首先在burp中不斷髮送上傳webshell的數據包:
- 然後不斷在瀏覽器中訪問,發現通過競爭可以訪問到:
具體的操作方法我也沒掌握,等學習到了就補上
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 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" );
}
......
......
......
};
本關對文件後綴名做了白名單判斷,然後會一步一步檢查文件大小、文件是否存在等等,將文件上傳後,然後再 $ret = $this->renameFile();
,進行了一次更改文件名;同樣存在條件競爭的漏洞。可以不斷利用burp發送上傳圖片馬的數據包,由於條件競爭,程序會出現來不及rename的問題,從而上傳成功。
Less-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 . '文件夾不存在,請手工創建!';
}
}
分析,move_uploaded_file()
函數中的img_path
是由post參數save_name
控制的,
因此可以在save_name
利用00截斷繞過:
首先上傳一個圖片馬,後綴名改爲php+jpg
然後再16進制中把加號的2b 改爲 00 fordward發包就行了。然而我的burp不知道爲啥發不了,唉
然後我又發現,這題可以直接加空格繞過
測試成功。
好了,到這暫時就結束了至於Less20,需要審計代碼,目前自己還做不了。