漏洞重溫之文件上傳(FUZZ)


文件上傳FUZZ思路通關upload-labs


Pass-16

黑盒階段

進入第十六關,首先我們能看到,該頁面的上傳點為圖片上傳。

首先,先把對方想的簡單一點,這里雖然是上傳圖片,但是可能只是前端js驗證,我們只需要先將腳本后綴改為圖片格式,然后抓包修改后綴,就有可能上傳成功。

上傳失敗,可以得知,該網站對於上傳文件的驗證存在於后端。

從報錯結果,我們可以得知,該位置采用的是白名單過濾,因為黑名單過濾一般不會告訴你該位置可以上傳的文件類型。

既然得知該位置使用白名單對后綴進行過濾,那么我們可以使用的手段就只剩下00截斷。

再由第二個圖片的請求包信息,我們可以得知請求是以POST請求發送的。

繞過失敗,該處無法通過00截斷進行繞過。

一般情況下,在測試到該位置的時候,如果我們拿不到源碼,黑盒測試就可以結束了。

白盒階段

點擊關卡查看源碼屬性,因為代碼很長,就不截圖了。代碼如下。

$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的圖片文件!";
    }
}

這里,跟大家說一些可能會有幫助的點。

對於一些漏洞初學者來說,想要吃透一種類型的漏洞,在沒有代碼或者網絡基礎的情況下是很困難的事情,或者說至少在白盒情況下,是很難深入的發現一些問題的。

例如上面的代碼,如果沒有代碼基礎,想要理解代碼的意思不是一個簡單的事情。

但是,說到底,我們看代碼只是為了知道我們的攻擊為什么無法實現,或者說看對於該功能點,網站的防御如何,針對於這些防御,我們可以采用什么方法進行繞過。

例如上面的代碼,我們雖然看不懂具體每行代碼的含義,但是我們可以根據代碼塊上面的注釋理解該位置的代碼究竟發揮了什么作用。

以此為標准,我們可以看到,在代碼開始,先是獲取了上傳文件的后綴,然后判斷后綴是否合法,合法才進行上傳。

然后,網站會使用上傳的圖片商城新的圖片,並且給圖片指定指定文件名。

從這個位置的代碼,我們可以看到,其中一個判斷流程的報錯信息我們之前看到過。

也就是說,我們第二次采用00隔斷進行上傳的時候,其實繞過了第一層防御,因為給出的報錯信息是在給圖片進行二次渲染的地方的報錯信息。

如果該網站並沒有給圖片進行二次渲染,可能我們的上傳已經成功了。

但是,從此處,我們也可以了解到,哪怕我們該位置上傳的是圖片馬,那么我們的圖片馬中插入的代碼也會被二次渲染修改,導致無法正常使用。

既然我們已經清楚該位置上傳失敗是源於圖片二次渲染,那么就有必要了解一下二次渲染是什么。

二次渲染:就是根據用戶上傳的圖片,新生成一個圖片,將原始圖片刪除,將新圖片添加到數據庫中。比如一些網站根據用戶上傳的頭像生成大中小不同尺寸的圖像。

這里,也就是說,我們上傳的東西,會被網站作為樣品再生成一個新的,並且將我們原本上傳的文件刪除。所以,想要繞過二次渲染,我們就需要知道,新生成的圖片,跟我們原本的圖片有什么不同,在相同處插入我們需要插入的代碼或許就可以繞過。

首先,我們上傳一個gif圖片,因為圖片的二次渲染,會利用我們的圖片生成一個新圖片,所以我們需要將上傳的圖片下載下來,通過16進制編輯器對比兩張圖片,可以發現,有一個地方是沒有被修改的,所以我們只需要將php代碼插入到沒有被修改過的地方,就可以完成圖片馬的上傳。

將代碼寫到藍色范圍之內,就可以獲得一張可以繞過網站二次渲染的gif圖片。

利用這個圖片再次上傳,獲取路徑。

利用文件包含訪問該文件,檢查我們的代碼是否可以正常運行。

第十六關,通關。

當然,面對圖片二次渲染,針對png和jpg兩種格式,還有兩種不同的應對方法,只是那兩種我自己並沒有成功,所以並沒有在這里總結。

Pass-17

黑盒階段

第十七關,可以看到,該處還是一個圖片上傳點,貫徹我們的思路,先把對方當成憨批,猜測他的防御只建立在前端。

跟第一關同樣的思路,通過這里的報錯信息,我們可以判斷出,該位置采用白名單過濾。並且,請求包是POST請求,對付白名單過濾,我們可以采用00截斷進行繞過。

可以看到,這里我們已經上傳成功了,訪問該文件。

第十七關,通關。

Pass-18

黑盒階段

跟第十七關類似,上傳點依然提示我們這里是一個圖片上傳點。針對上傳,我的思路就是先把對面當憨批,跟xss一樣,先輸入一個測試馬,成功了,那么對方的防御確實憨批,如果沒成功,通過返回的報錯,我們可以大致了解他們的防御情況。

可以看到,這里的報錯信息和之前不同,猜測該位置網頁采用的是黑名單過濾。

對於黑名單過濾,我們可以采用的方式就比白名單多了,簡單來說,有以下幾種:

1.上傳特殊可解析后綴

2.配合解析漏洞

3.后綴大小寫繞過

4.點繞過

5.空格繞過

6.::$DATA繞過

7.雙后綴名繞過

8.00截斷

因為這里我們並無法得知網站針對這些繞過方式做了什么防護,所以這里我們只能挨個嘗試。

1.上傳特殊可解析后綴

失敗!

2.配合解析漏洞上傳

失敗!

3.后綴大小寫繞過

失敗!

4.點繞過

失敗!

5.空格繞過

失敗!

6.::$DATA繞過

失敗!

7.雙寫后綴繞過

失敗!

8.00截斷

上傳成功!

利用文件包含漏洞,測試文件里面代碼是否可執行。

第十八關,通關。

Pass-19

黑盒階段

進入十九關,可以看到,一個很明顯的區別就是這里多了一個保存名稱的選項,猜測,可能我們無論上傳什么,都會被重命名為這個名稱進行儲存。所以我們可以嘗試接着上傳我們的測試圖片馬,然后將保存名稱的后綴修改為php,嘗試上傳。

可以發現,在我們將保存文件的后綴修改之后,系統給出了報錯,那么我們基本可以放棄繞過黑名單的幾種方法了。

因為我們就算可以繞過網頁的防御,保存的文件的名稱依然是被修改掉了,所以在這上面花費的功夫基本等於無用功。

所以我們直接使用00過濾。

可以發現,文件已經上傳成功。

訪問文件,檢查代碼是否依然可執行。

第十九關,通關!

Pass-20

可以看到,在上傳點下面也有一個保存名稱框,跟之前一樣,先測試一下是否可以通過直接修改保存名稱的后綴來直接將我們上傳的文件修改為php文件。

可以發現,在這里修改不行,同上一關的思路,我們沒必要測試黑名單繞過方式,直接測試白名單繞過方式,也就是00截斷。

可以發現,00截斷失敗了,一般在黑盒情況下,做到這里就可以結束了。

白盒階段

查看源碼,找到失敗的原因。代碼如下:

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

        $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 = "請選擇要上傳的文件!";
}

可以發現$file_name經過reset($file) . '.' . $file[count($file) - 1];處理。

如果上傳的是數組的話,會跳過$file = explode('.', strtolower($file));。並且后綴有白名單過濾

$ext = end($file);
$allow_suffix = array('jpg','png','gif');

而最終的文件名后綴取的是$file[count($file) - 1],因此我們可以讓$file為數組。$file[0]smi1e.php/,也就是reset($file),然后再令$file[2]為白名單中的jpg。此時end($file)等於jpg,$file[count($file) - 1]為空。而 $file_name = reset($file) . '.' . $file[count($file) - 1];,也就是smi1e.php/.,最終move_uploaded_file會忽略掉/.,最終上傳smi1e.php

上面是我從博客里面看到的大佬的思路,大概就是說,因為正常情況下代碼里面的有行代碼無法繞過,所以在黑盒測試階段我們的00階段失效,但如果上傳的是數組的話,就可以跳過這行代碼。

{{uploading-image-428631.png(uploading...)}}

第二十關,未通關,需要再多研究。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM