不安全的文件下載
概述
文件下載功能在很多web系統上都會出現,一般我們當點擊下載鏈接,便會向后台發送一個下載請求,一般這個請求會包含一個需要下載的文件名稱,后台在收到請求后 會開始執行下載代碼,將該文件名對應的文件response給瀏覽器,從而完成下載。 如果后台在收到請求的文件名后,將其直接拼進下載文件的路徑中而不對其進行安全判斷的話,則可能會引發不安全的文件下載漏洞。
此時如果攻擊者提交的不是一個程序預期的的文件名,而是一個精心構造的路徑(比如../../../etc/passwd),則很有可能會直接將該指定的文件下載下來。 從而導致后台敏感信息(密碼文件、源代碼等)被下載。所以,在設計文件下載功能時,如果下載的目標文件是由前端傳進來的,則一定要對傳進來的文件進行安全考慮。
切記:所有與前端交互的數據都是不安全的,不能掉以輕心!
實驗
相當於把一個文件名傳到后端,后台去找這個文件,然后響應輸出到前端
測試文件下載漏洞時,我們可以用目錄遍歷的方式
http://192.168.171.133/pikachu/vul/unsafedownload/execdownload.php?filename=../../../../../../../../../../1.txt
這時候就能下載到我們想要的文件,尤其是 Linux 上很多配置文件都有固定的目錄
防范措施
- 對傳入的文件名進行嚴格的過濾和限定
- 對文件下載的目錄進行嚴格的過濾
不安全的文件上傳
概述
因為業務功能需要,很多 Web 站點都有文件上傳的接口,比如:
- 注冊時上傳頭像圖片(比如jpg,png,gif等)
- 上傳文件附件(doc,xls等)
而在后台開發時,並沒有對上傳的文件進行安全考慮,或者采用了有缺陷的措施,導致攻擊者可以通過一些手段繞過安全措施從而上傳一些惡意文件(如:一句話木馬)
從而通過對該惡意文件的訪問來控制整個 Web 后台
測試流程
- 對文件上傳的地方按照要求上傳文件,查看返回結果(路徑,提示等)
- 嘗試上傳不同類型的 “ 惡意 ” 文件,比如 xx.php 文件,分析結果
- 查看 html 源碼,看是否通過 js 在前端做了限制,可以繞過
- 嘗試使用不同方式進行繞過:黑白名單繞過 / MIME類型繞過 / 目錄0x00截斷繞過等
- 猜測或者結合其他漏洞(比如敏感信息泄露等)得到木馬路徑,連接測試
客戶端 check
我們先進行 客戶端check 這個實驗,這里只允許我們上傳圖片
我們選擇一個 php 文件時,會直接提示文件不符合要求,內容如下
<?php echo shell_exec($_GET['cmd']);?>
下面看一下這個限制是不是通過前端完成的
可以看到,當 input 標簽的狀態發生改變時,就會調用 checkFileExt(),下面是這個函數的源碼
這個函數會判斷文件的后綴是否在 jpg、png 和 gif 中,是這些后綴才運行上傳。
但是前端做的限制只是輔助作用,是可以繞過的,比如直接刪掉 onchange 中的內容
這時候就能上傳了
然后利用上傳的文件進行操作
http://192.168.171.133/pikachu/vul/unsafeupload/uploads/hack.php?cmd=ipconfig
服務端check
MIME
MIME(Multipurpose Internet Mail Extensions)多用途互聯網郵件擴展類型。是設定某種擴展名的文件用一種應用程序來打開的方式類型,當該擴展名文件被訪問時,瀏覽器會自動使用指定應用程序來打開。多用於指定一些客戶端自定義的文件名,以及一些媒體文件打開方式。
每個MIME類型由兩部分組成,前面是數據的大類別,例如聲音audio、圖象image等,后面定義具體的種類。常見的 MIME 類型,比如:
- 超文本標記語言:.html,.html text.html
- 普通文件:.txt text/plain
- RTF文件:.rtf application/rtf
- GIF圖形:.gif image/gif
- JPEG圖形:.jpeg,.jpg image/jpeg
$_FILES()函數
它從瀏覽器的HTTP頭里獲取 Content-Type ,這個 Content-Type 前端用戶是可以控制的
通過使用 PHP 的全局數組 $_FILES,你可以從客戶計算機向遠程服務器上傳文件
第一個參數是表單的 input name,第二個下標可以是 “name”,“type”,“size”,“tmp_name” 或 “error”,就像這樣:
- $_FILES['file']['name']:被上傳文件的名稱
- $_FILES['file']['type']:被上傳文件的類型
- $_FILES['file']['size']:被上傳文件的大小
- $_FILES['file']['tmp_name']:存儲在服務器的文件的臨時副本的名稱
- $_FILES['file']['error']:由文件上傳導致的錯誤代碼
實驗
當我們上傳一個 php 文件時,會報錯,下面通過 BurpSuite 修改請求頭
修改成 image/png,或者別的圖片類型都行
這時候文件就上傳成功了
getimagesize() 類型驗證
getimagesize() 返回結果中有文件大小和文件類型,如果用這個函數來獲取類型,從而判斷是否是圖片的話,會存在問題。
它讀取目標文件的 16 進制的頭幾個字符串,看符不符合圖片要求,固定的圖片文件前面幾個字符串是一樣的
但是圖片頭可以被偽造,因此還是可以被繞過
我們可以用 xxd 這個命令查看圖片的第一行
xxd image.png | head -n 1
我們可以嘗試上傳一個包含惡意代碼的圖片,制作方法如下
- 方法1:CMD命令直接偽造頭部GIF89A:copy /b test.png + muma.php cccc.png
- 方法2:使用GIMP(開源的圖片修改軟件),通過增加備注,寫入執行命令
<?php phpinfo(); ?>
然后上傳這個 ccc.png 文件
但是我們訪問這個圖片,惡意代碼是不會被執行的。我們可以結合本地文件包含漏洞進一步利用,猜測上傳圖片所在的位置
http://192.168.171.133/pikachu/vul/fileinclude/fi_local.php?filename=../../unsafeupload/uploads/2019/10/09/6470185d9d609075689635710502.png&submit=Submit+Query
防范措施
- 不要在前端使用 JS 實施上傳限制策略
- 通過服務端對上傳文件進行限制:
- 進行多條件組合檢查:比如文件的大小,路徑,擴展名,文件類型,文件完整性
- 對上傳的文件在服務器上存儲時進行重命名(制定合理的命名規則)
- 對服務器端上傳的目錄進行權限控制(比如只讀),限制執行權限帶來的危害