TP漏洞之文件上傳總結

  • 2019 年 10 月 29 日
  • 筆記

js檢查

一般都是在網頁上寫一段javascript腳本,校驗上傳文件的後綴名,有白名單形式也有黑名單形式。

查看源程式碼可以看到有如下程式碼對上傳文件類型進行了限制:


我們可以看到對上傳文件類型進行了限制。

繞過方法

  1. 我們直接刪除程式碼中onsubmit事件中關於文件上傳時驗證上傳文件的相關程式碼即可。

或者可以不載入所有js,還可以將html源碼copy一份到本地,然後對相應程式碼進行修改,本地提交即可。

  1. burp改包,由於是js驗證,我們可以先將文件重命名為js允許的後綴名,在用burp發送數據包時候改成我們想要的後綴。

即可上傳成功

黑名單

特殊可解析後綴

這裡做了黑名單處理,我們可以通過特殊可解析後綴進行繞過。

繞過方法

之前在https://www.jianshu.com/p/1ccbab572974中總結過,這裡不再贅述,可以使用php3,phtml等繞過。

上傳.htaccess


我們發現黑名單限制了很多後綴名,但是沒有限制.htaccess .htaccess文件是Apache伺服器中的一個配置文件,它負責相關目錄下的網頁配置.通過htaccess文件,可以實現:網頁301重定向、自定義404頁面、改變文件擴展名、允許/阻止特定的用戶或者目錄的訪問、禁止目錄列表、配置默認文檔等功能。

繞過方法

我們需要上傳一個.htaccess文件,內容為:

這樣所有的文件都會解析為php,接下來上傳圖片馬即可

後綴大小寫繞過

我們發現對.htaccess也進行了檢測,但是沒有對大小寫進行統一。

繞過方法

後綴名改為PHP即可

空格繞過

黑名單沒有對文件中的空格進行處理,可在後綴名中加空格繞過。

繞過方法

點繞過

windows會對文件中的點進行自動去除,所以可以在文件末尾加點繞過,不再贅述

::$DATA繞過

同windows特性,可在後綴名中加」 ::$DATA」繞過,不再贅述

路徑拼接繞過

這裡對文件名進行了處理,刪除了文件名末尾的點,並且把處理過的文件名拼接到路徑中

繞過方法

這裡我們可以構造文件名1.PHP. . (點+空格+點),經過處理後,文件名變成1.PHP.,即可繞過。

雙寫繞過

繞過方法

這裡我們可以看到將文件名替換為空,我們可以採用雙寫繞過:1.pphphp

白名單

繞過方法

這裡檢查Content-type,我們burp抓包修改即可繞過:

%00 截斷

$img_path直接拼接,因此可以利用%00截斷繞過

繞過方法

然後直接訪問/upload/1.php即可

00截斷(post)

save_path是通過post傳進來的,還是利用00截斷,但這次需要在二進位中進行修改,因為post不會像get對%00進行自動解碼。

繞過方法

接下來訪問1.php即可

文件內容檢查

文件幻數檢測

主要是檢測文件內容開始處的文件幻數,比如圖片類型的文件幻數如下, 要繞過jpg 文件幻數檢測就要在文件開頭寫上下圖的值:

Value = FF D8 FF E0 00 10 4A 46 49 46

要繞過gif 文件幻數檢測就要在文件開頭寫上下圖的值

Value = 47 49 46 38 39 61 要繞過png 文件幻數檢測就要在文件開頭寫上下面的值

Value = 89 50 4E 47

然後在文件幻數後面加上自己的一句話木馬程式碼就行了

文件相關資訊檢測

影像文件相關資訊檢測常用的就是getimagesize()函數

只需要把文件頭部分偽造好就ok 了,就是在幻數的基礎上還加了一些文件資訊

有點像下面的結構

GIF89a (…some binary data for image…) <?php phpinfo(); ?> (… skipping the rest of binary data …)

本次環境中的文件頭檢測,getimagesize,php_exif都可以用圖片馬繞過:

copy normal.jpg /b + shell.php /a webshell.jpg

文件載入檢測

一般是調用API 或函數去進行文件載入測試,常見的是影像渲染測試,甚至是進行二次渲染(過濾效果幾乎最強)。對渲染/載入測試的攻擊方式是程式碼注入繞過,對二次渲染的攻擊方式是攻擊文件載入器自身。

對渲染/載入測試攻擊- 程式碼注入繞過

可以用影像處理軟體對一張圖片進行程式碼注入

用winhex 看數據可以分析出這類工具的原理是

在不破壞文件本身的渲染情況下找一個空白區進行填充程式碼,一般會是圖片的注釋區

對於渲染測試基本上都能繞過,畢竟本身的文件結構是完整的

二次渲染

imagecreatefromjpeg二次渲染它相當於是把原本屬於影像數據的部分抓了出來,再用自己的API 或函數進行重新渲染在這個過程中非影像數據的部分直接就隔離開了

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";                $newimagepath = UPLOAD_PATH.$newfilename;                imagejpeg($im,$newimagepath);                //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)                $img_path = UPLOAD_PATH.$newfilename;                @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";                $newimagepath = UPLOAD_PATH.$newfilename;                imagepng($im,$newimagepath);                //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)                $img_path = UPLOAD_PATH.$newfilename;                @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";                $newimagepath = UPLOAD_PATH.$newfilename;                imagegif($im,$newimagepath);                //顯示二次渲染後的圖片(使用用戶上傳圖片生成的新圖片)                $img_path = UPLOAD_PATH.$newfilename;                @unlink($target_path);                $is_upload = true;            }        } else {            $msg = "上傳出錯!";        }    }else{        $msg = "只允許上傳後綴為.jpg|.png|.gif的圖片文件!";    }}

本關綜合判斷了後綴名、content-type,以及利用imagecreatefromgif判斷是否為gif圖片,最後再做了一次二次渲染。

繞過方法

得去找圖片經過GD庫轉化後沒有改變的部分,再將未改變的部分修改為相應的php程式碼。

條件競爭

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。

繞過方法

然後不斷訪問webshell:

上傳成功。