一、文件上傳漏洞介紹
Web應用程序通常帶有文件上傳的功能,比如在博客園發表文章需要上傳圖片等行為,這其中就可能存在文件上傳漏洞。
如果Web應用程序存在上傳漏洞,攻擊者可以直接上傳WebShell(以asp、php或者jsp等網頁文件形式存在的一種命令執行環境,也可以將其稱做為一種網頁后門)到服務器上。
二、解析漏洞
攻擊者在利用上傳漏洞時,通常會與Web容器的解析漏洞配合在一起。
常見的Web容器有IIS、Nginx、Apache、Tomcat。
1. IIS解析漏洞(基於IIS6.0
環境)
(1)當建立*.asa
、*.asp
格式的文件夾時,其目錄下的任意文件都將被IIS當做asp文件來解析。
測試案例:建立文件夾parsing.asp
,在文件夾內新建內容為<%=NOW()%>
的文本文件test.txt
,然后在瀏覽器里訪問。
測試結論:
NOW()
是ASP獲取當前時間的函數。正常而言,IIS是不會去解析文本文檔格式而是直接顯示內容。而在parsing.asp
文件夾內,卻被當做ASP腳本來解析。
(2)當文件為*.asp;1.jpg
時,IIS同樣會以ASP腳本執行。
測試案例:創建文件名為test.asp;1.jpg
,其內容為<%=NOW()%>
。
(3)WebDav漏洞
WebDav是一種基於HTTP1.1協議的通信協議。在GET、POST、HEAD等HTTP標准方法之外擴展了新方法。
攻擊者可以通過PUT方法向服務器上傳危險腳本。
2. Apache解析漏洞(基於Apache 1.x
和Apache 2.x
環境)
(1)Apache漏洞介紹:
我們在Apache環境中設置文件內容為<?php phpinfo(); ?>
的1.php.aa
文件,在正常情況下,應該會提示下載該文件,但是在此情況下卻顯示了phpinfo()的內容。
(2)Apache在解析文件名的原理:
當遇到不認識的擴展名,將會從后向前解析,直到碰到認識的擴展名。例如文件名為1.php.aa
,首先解析aa
擴展名,發現不認識繼續向前面遍歷。
(3)Apache可識別擴展名(在/conf/mime.types
文件中有詳細列表)
(4)對於Apache解析漏洞的防范:
在開發設計上傳文件程序時,應設置判斷是否為PHP、ASP、ASPX
以及在(3)中提到的擴展名的函數,如果函數返回Fasle則禁止上傳。
3. PHP CGI(Nginx)解析漏洞
(1)漏洞介紹:
我們在Nginx環境下布置一個1.jpg
文件,並用文本編輯器寫入<?php echo "hello world"; ?>
。通常情況而言,我們打開URL:http://127.0.0.1:80/1.jpg 顯示為一張無法識別的圖片,但是利用Nginx解析漏洞,我們打開URL:http://127.0.0.1:80/1.jpg/1.php (1.php是虛構、不存在的文件)時,卻將文件1.jpg識別為一個php文件。
(2)漏洞解析:
在PHP的配置文件中有一個選項:cgi.fix_pathinfo=True
,在訪問URL時,當Nginx服務器遇到1.php是不存在的文件時,便會向前遍歷解析。
如下圖在php7.3.4版本中,cgi.fix_pathinfo默認是開啟的。
三、繞過上傳漏洞
使用Web應用中,很多場景都要使用文件上傳。文件上傳的流程為客戶端使用JavaScript驗證與服務器端采用隨機數命名文件。因此在客戶端利用JavaScript在文件未上傳的時候就對文件進行驗證,服務器端檢測上傳文件的MIME類型、檢測文件擴展名是否合法、是否嵌入惡意代碼。
任何客戶端驗證都是不安全的。客戶端驗證是防止用戶錯誤輸入,減少服務器開銷而已。
1. 客戶端檢測
下面通過對Upload.html
中JavaScript源代碼分析來突破客戶端驗證。
<html>
<head>
<title>Pic Upload</title>
<script type="text.javascript">
funtion checkFile(){
var flag=false;
var str=document.getElementById("file").value;
str=str.substring(str.lastIndexOf('.')+1);
var arr=new Array('png','bmp','gif','jpg');
for(var i=0;i<arr.length;i++){
if(str=arr[i]){
flag=true;
}
}
if(!flag)
alert('file invalid');
}
return flag;
}
</script>
</head>
<body>
<form action="upload.php" method="post" onsubmit=“ checkFile ”
enctype="multpart/form-data">
<input type="file" name="file" id="file" /><br/>
<input type="submit" value="Submit" name="submit" />
</form>
</body>
</html>
由源代碼得知客戶端JavaScript僅針對png,bmp,gif,jpg四種進行文件上傳,那么攻擊者就可以將文件名偽裝成這些類型上傳。
(1)使用Firebug
Firebug介紹:
是網頁瀏覽器 Mozilla Firefox 下的一款開發類擴展,它集HTML查看和編輯、Javascript控制台、網絡狀況監視器於一體,是開發JavaScript、CSS、HTML和Ajax的得力助手。
Firebug從各個不同的角度剖析Web頁面內部的細節層面,給Web開發者帶來很大的便利。
Firebug也是一個除錯工具。用戶可以利用它除錯、編輯、甚至刪改任何網站的 CSS、HTML、DOM 以及JavaScript 代碼。
在Upload.html中單擊Submit按鈕,Form表單將會觸發onsubmit時間從而調用checkFile()函數,通過檢驗擴展名是否合法從而允許文件是否可以上傳至服務器。Firebug將onsubmit事件刪除,因此所有類型的文件擴展名都可以繞過JavaScript函數checkfile()驗證。
(2)中間人攻擊
機制與(1)中的Firebug完全不同,中間人攻擊在傳輸中的HTTP層做手腳。可以簡單地理解為上傳
1.jpg
文件通過JavaScript函數的驗證,再使用抓包工具(Burp Suite)將文件名修改后綴為php。
注意:HTTP請求頭部Content-Length參數(實體正文長度),需要根據文件名長度的改動進行相應的修改。
2. 服務器端檢測
服務器端驗證主要包含白名單與黑名單擴展名過濾、文件類型檢測、文件重命名等操作。如果將上傳漏洞配合解析漏洞就可以繞過大多數上傳驗證。
(1)白名單與黑名單驗證
黑名單過濾:定義一系列不安全的擴展名,在服務器端收到文件后匹對擴展名。
<?php
$Blacklist = array('asp','php','jsp','php5','asa','aspx');#危險函數黑名單
if(isset($_POST["submit"])){
$name = $_FILES['file']['name'];
$extension = substr(strrchr($name, "."), 1);
$boo = false;
foreach($Blacklist as $key => $value) {
if ($value==$extension){
$boo = true;
break;
}
}
if($boo){
echo "file invalid";
}
}
?>
黑名單過濾的缺點:
- 攻擊者可以從黑名單中找到Web開發者忽略的擴展名
- 沒有進行大小寫轉換,諸如
.PHP
擴展名不在黑名單里,依舊會被服務器接收 - windows系統下,如果文件名以"."或空格結尾會自動取出。
asp.
轉化為asp
白名單過濾:
與黑名單過濾相反,白名單只允許已定義過的擴展名,比黑名單有更好的防御機制。
<?php
$Whitelist = array('jpg','jpge','bmp','gif','png');#白名單允許函數
if(isset($_POST["submit"])){
$name = $_FILES['file']['name'];
$extension = substr(strrchr($name, "."), 1);
$boo = true;
foreach($Blacklist as $key => $value) {
if ($value==$extension){
$boo = false;
break;
}
}
if(!$boo){
echo "file invalid";
}
}
?>
白名單過濾的缺點:
白名單並不能完全防御上傳漏洞。在IIS解析漏洞章節中,我們介紹過當文件名為*.asp;1.jpg
時,白名單過濾機制識別文件擴展名為.jpg
,即驗證通過可以上傳。但是在IIS解析漏洞中,此文件會被當做asp腳本程序來執行。
(2)MIME驗證
MIMIE類型用來設定某種擴展名文件的打開方式。
if($_FILES['file']['type']==" image/jpeg"){
$imageTempName=$_FILES['file']['tmp_name'];
$imageName=$_FILES['file']['name'];
$last=substr($imageName, strrpos($imageName,"."));
if(!is_dir("uploadFile")){
mkdir("uploadFile");
}
$imageName=md5($imageName).$last;
move_uploaded_file($imageName, "./uploadFile/".$imageName;
echo("Success");
}else{
echo("Fail");
exit();
}
上傳php文件時,我們使用抓包工具(Burp Suite)查看其MIME類型,可以發現php文件的MIME類型為application/php,無法通過驗證。因此可以將Content-Type修改成image/jpeg類型,即可通過驗證。
(3)目錄驗證
簡介:在文件上傳時,允許用戶將文件放到指定的目錄中,如果不存在指定目錄,就會先創建目錄再將文件放入。
攻擊手段:HTML代碼中有一個隱藏標簽<input type="hidden" name="Extension" value="up"/>
,這是文件上傳默認的文件夾,我們可以將參數value的值就可以達到目的。結合IIS解析漏洞(當建立*.asa
、*.asp
格式的文件夾時,其目錄下的任意文件都將被IIS當做asp文件來解析),就可以將惡意代碼寫入。
(4)截斷上傳攻擊
此方法通常適用於ASP程序。
//ASP代碼
<%
username = request("username")
Response.write username
%>
//將請求輸入的username輸出
截斷上傳攻擊指的是%00將后面的字符都截斷,當我們上傳文件名為1.asp x.jpg
時,然后將空格的十六進制數20改成00,因此文件名為1.asp%00x.jpg
,即符合截斷上傳攻擊原型,最終將上傳1.asp
文件。
四、文件編輯器上傳漏洞
(1)敏感信息暴露
部分文本編輯器的文件目錄存在一些敏感文件,將敏感信息直接暴露在攻擊者前。
(2)黑名單策略錯誤
部分文本編輯器采用的是黑名單機制,基於上述黑名單策略的缺點,攻擊者仍可以找到另外的危險腳本。
(3)任意文件上傳漏洞
五、修復上傳漏洞的策略
文件上傳漏洞產生的原因主要是:
- 目錄過濾不嚴,攻擊者可能建立畸形目錄
- 文件未重命名,攻擊者可能利用Web容器解析漏洞
經過學習,設計如下代碼可預防上述攻擊。
<?php
if(!isset($_POST['submit'])){
exit();
}
$arr = Array('jpg','gif','jpeg','png','rar','zip','doc'); //設置白名單
$imageTempName=$_FILES['file']['temp_name'] //將文件放在臨時路徑,防止解析漏洞發生
$imageName=$_FILES['file']['name'];
$last=strtolower(substr($imageName, strrpos($imageName,'.')+1)); //獲取文件擴展名並全部轉換成小寫
if(!in_array($last,$arr)){
exit('extension name invalid .$last ...'); //當擴展名不在白名單內,立即退出程序。
}
$Extension=$_POST['Extension']; //確認擴展名安全方可獲取文件上傳目錄
$imageName = md5($imageName).".".$last; //對文件重命名,防止利用解析漏洞
move_uploaded_file($imageTempName, "./$Extension/".$imageName);
echo("Success!");
}
- 接收文件將其存放在文件臨時路徑,即便存在解析漏洞也不能獲取有效信息。
- 將擴展名與白名單對照,不符合的情況下直接退出程序。
- 對文件重命名方式諸如
test.asp;1.jpg
文件名繞過白名單卻利用解析漏洞實施攻擊。