上傳靶機實戰之upload-labs解題

雪痕*發表於2021-06-03

前言

我們知道對靶機的滲透可以提高自己對知識的掌握能力,這篇文章就對上傳靶機upload-labs做一個全面的思路分析,一共21個關卡。讓我們開始吧,之前也寫過關於上傳的專題,分別為淺談檔案上傳漏洞(客戶端JS檢測繞過)
淺談檔案上傳漏洞(其他方式繞過總結)

靶機環境搭建

Upload-Labs 環境要求
作業系統:windows、Linux
php版本:推薦5.2.17(其它版本可能會導致部分Pass無法突破)
php元件:php_gd2,php_exif(部分Pass需要開啟這兩個擴充套件)
apache:以moudel方式連線
專案地址:https://github.com/c0ny1/upload-labs
直接使用phpstudy搭建,將下載的檔案放在對應的根目錄即可。訪問如下:

解題思路

pass-01

首先看第一關,檢視提示和原始碼,發現是前端JS驗證,而我們知道,前端驗證,有和沒有基本一樣。

繞過也非常簡單,可以瀏覽器直接禁用JS,先按F12,然後按F1,找到禁用JS,如下圖:

然後直接上傳php木馬。結果如下:

這是一種方法,當然也可以直接burp抓包,修改字尾直接上傳。

pass-02

看第二關,首先分析原始碼

分析程式碼,發現只是檢查了content-type型別,這個也是很好繞過的,直接抓取資料包,修改型別就可以了。抓的資料包如下:

將型別改為image/jpeg,直接上傳PHP木馬,結果如下

木馬上傳成功。

pass-03

看第三關,分析原始碼

發現第三關是基於黑名單防護,不允許上傳'.asp','.aspx','.php','.jsp'字尾的檔案,這個黑名單是不全的,比如可以嘗試上傳.phtml .phps .php5 .pht的字尾檔案,也是可以當做php指令碼解析的,如果Web伺服器是apache的話,也可以上傳.htaccess檔案,來繞過黑名單。首先嚐試上傳.phtml,發現上傳成功,再響應包中找到上傳路徑。這裡要注意一下,要在apache的httpd.conf中有如下配置程式碼
AddType application/x-httpd-php .php .phtml .phps .php5 .pht

pass-04

看第四關,分析原始碼

發現這裡黑名單基本過濾了字尾,但是,沒有.htaccess,可以上傳.htaccess檔案,來達到解析指令碼的目的。也可以用另外的一種方法,看程式碼6到10行,這裡是對檔案字尾的一些處理,包括刪除結尾的點,刪除空格,全都轉換成小寫等,然而這麼處理肯定有想不到的地方,比如構造字尾.php. .中間是一個空格(後面的第八關和第十關是同樣的思路),即達到了繞過黑名單,又經過檢查使得指令碼木馬可以解析。如下圖:

訪問指令碼木馬,成功解析

pass-05

第五關和第四關一樣,只是黑名單裡新增了.htaccess,所以只能使用構造字尾的方式了,四關的方法五官通用,所以這裡就不詳細贅述了。

pass-06

看第六關,分析原始碼

看第5至10行,裡面的過濾沒有限制大小寫,所以可以嘗試大小寫組合繞過。比如.pHP等。嘗試上傳,如下圖:

上傳成功,指令碼木馬成功解析:

pass-07

看第七關,分析原始碼:

通過觀察原始碼,發現沒有對空格進行處理,可以直接在末尾新增空格來繞過黑名單。如下:

上傳成功,成功解析。

pass-08

看第八關,分析原始碼:

這裡的黑名單限制了所有可以解析的字尾,所以只能構造特殊字尾來繞過防護,這裡去除了空格,並用strrchr函式查詢指定小黑點最後一次出現,所以構造的字尾為.php. (點php點加空格),成功繞過,如下圖:

上傳成功,成功解析。

pass-09

看第九關,分析原始碼:

看第5行到第10行,原始碼中未過濾::$DATA,可以利用::$DATA來繞過過濾,到這裡小夥伴可能就要問了,為什麼::$DATA可以繞過黑名單呢?這其實是利用了windows的特性,在window的時候如果檔名+"::$DATA"會把::$DATA之後的資料當成檔案流處理,不會檢測字尾名,且保持::$DATA之前的檔名,他的目的就是不檢查字尾名。例如:"test.php::$DATA"Windows會自動去掉末尾的::$DATA變成"test.php"。
現在抓取資料包驗證。上傳成功,如下圖。

上傳成功,成功解析。

pass-10

看第十關,分析原始碼

這一關和第八關類似,就比第八關多了一行,多刪除了一個點,所以還是採用構造字尾的方式,這次構造的字尾為.php. .(點php點空格點)正好繞過過濾。
構造好後,上傳成功

解析成功

pass-11

看第十一關,分析原始碼

這裡的重點在第八行,這裡使用了str_ireplace函式將匹配到的字元替換為空,所以繞過思路就很簡單了,只需要雙寫就可以了,刪除字元後,剩餘的又重新拼接為字尾,達到繞過的目的,抓取資料包測試如下,上傳成功。

訪問,解析成功。

pass-12

看十二關,分析原始碼

分析原始碼我們可以知道,這裡是基於白名單過濾,只允許上傳'jpg','png','gif',但是這裡注意第八行,上傳路徑是可以控制的,所以可以利用%00截斷,來達到上傳木馬的目的。這裡要注意一下,%00截斷想要利用成功,php版本小於5.3.4(高版本php官方修復了這個漏洞),php的magic_quotes_gpc為OFF狀態。抓取資料包,進行嘗試,如下圖:

訪問,解析成功

pass-13

看十三關,分析原始碼

同樣是白名單,也是上傳位置可控,不過是由GET傳輸變為POST,還是利用%00截斷。不過因為POST不會進行自動解碼,所以要自己在16進位制中進行修改,如下圖:


上傳成功,解析成功

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;
}

$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 = "上傳出錯!";
        }
    }
}

下面是檔案包含的程式碼

include.php
<?php
/*
本頁面存在檔案包含漏洞,用於測試圖片馬是否能正常執行!
*/
header("Content-Type:text/html;charset=utf-8");
$file = $_GET['file'];
if(isset($file)){
    include $file;
}else{
    show_source(__file__);
}
?>

分析程式碼可以知道它只讀2位元組,只需要將木馬字尾改為圖片格式,內容加個圖片頭部,然後在返回包中找到路徑,然後寫在file引數後,因為file引數include的原因都會直接執行。如下:

長傳成功,配合檔案包含漏洞解析圖片格式的木馬。

pass-15

先看原始碼:

這裡使用getimagesize()函式來驗證是否是圖片,這裡說一下getimagesize(),這個函式功能會對目標檔案的16進位制去進行一個讀取,去讀取頭幾個字串是不是符合圖片的要求的。getimagesize()返回結果中有檔案大小和檔案型別,如果用這個函式來獲取型別,從而判斷是否是圖片的話,會存在問題。是可以被繞過的,因為圖片頭可以被偽造。這裡偽造gif的圖片頭,來進行上傳,如下

圖片木馬上傳成功。

pass-16

這一關需要開啟php_exif

看原始碼

這裡使用exif_imagetype函式來檢查是否是圖片,這裡說一下exif_imagetype(),它是讀取一個影像的第一個位元組並檢查其簽名。所以也是可以通過偽造圖片頭來進行繞過的。這裡同樣偽造gif的圖片頭,來進行上傳,如下

上傳成功

pass-17

看原始碼

這一關比較綜合,判斷了字尾名、content-type,以及利用imagecreatefromgif判斷是否為gif圖片,最後再做了一次二次渲染。還是按照第16關的思路走一下,看是否成功。顯然失敗了。

那就做一個圖片木馬,上傳一個正常圖片,抓取資料包,在圖片末尾插入惡意程式碼,如下:

然後,進行上傳操作。上傳成功,如下。

因為這裡進行了二次渲染,所以還沒有結束,我們將上傳的圖片下載到本地檢視。

這裡發現在進行二次渲染的過程中,我們插入到圖片的惡意程式碼被清理掉了,所以需要對比渲染前後,哪些地方沒有變化,我們將惡意程式碼插入到那裡,來繞過二次渲染。對比發現,這裡渲染前後沒有發生變化。

所以,我將惡意程式碼插入到這裡,如下圖:

重新上傳,上傳成功,再次下載到本地,發現惡意程式碼沒有被清除,繞過了二次渲染。

pass-18

看原始碼

這裡的程式碼邏輯是先將檔案上傳到伺服器,然後判斷檔案字尾是否在白名單裡,如果在則重新命名,否則刪除。這樣就存在一個安全問題,那就是我同時上傳多個相同檔案,在它刪除之前訪問就可以了。也就是條件競爭問題。可以藉助burp的暴力破解模組。這裡復現失敗了=_="。

pass-19

這裡同樣存在條件競爭問題,不過就是需要換成圖片木馬。其他和第十八關一樣。

pass-20

看原始碼

這裡發現move_uploaded_file()函式中的img_path是由post引數save_name控制的,因此可以在save_name利用00截斷繞過,和前面關卡的00截斷類似。如下:

上傳成功。

pass-21

看原始碼

說實話,這個程式碼看的我有點懵。參考網上文章一點點分析吧,首先第五行以白名單的形式檢查MIME這個可以直接在資料包中修改,然後向下分析,到第十行,這裡的含義是如果POST接收的save_name值為空則賦值給$_FILES['upload_file']['name'],否則是本身。接著是用explode() 函式把字串打散為陣列,然後解釋一下下面涉及到的函式的含義。

end()函式將 array的內部指標移動到最後一個單元並返回其值
reset()函式將 array 的內部指標倒回到第一個單元並返回第一個陣列單元的值
count() 函式計算陣列中的單元數目或物件中的屬性個數,這裡要注意,陣列下標從0開始
然後這裡用end函式將接收的字尾與白名單比較,如果符合,繼續執行,然後陣列第一位和$file[count($file) - 1]進行拼接,產生儲存檔名file_name。
所以這裡採用陣列繞過,save_name[0]=pass21.php, save_name[2]=jpg,$ext=jpg過白名單,reset($file)=pass21.php
$file[1]=null,這樣就成功上傳pass21.php.(windows多個點不影響)
抓包測試。上傳成功。

結語

這篇文章對於upload-labs靶場進行了全通關思路講解,如有錯誤請斧正。

相關文章