背景:
一些網站的業務需求,可能提供文件查看或下載功能,如果對用戶查看或下載的文件不做限制,那麼用戶就能夠查看和下載任意2文件,可以使源代碼文件、敏感文件等。
路徑遍歷代碼:
<?php
$dir_path=$_REQUEST['path'];
$filename=scandir($dir_path);
foreach($filesnames as $name){
echo $name."<br/>";
}
?>
路徑遍歷漏洞成因:
如果應用程序使用用戶可控制的數據,以危險的方式訪問位於引用程序服務器或其後端文件系統中的文件和目錄,就會出現路徑遍歷漏洞。
文件讀取代碼:
<?php
$filename=$_GET['m'];
echo file_get_contest($filename);
?>
<?php
$filename=$_GET['m'];
$fp=fopen($filename,"r") or die ("unable open!");
echo fread($fp,filesize($filename));
fclose($fp);
?>
<?php
$filename=$_GET['m'];
readfile($filename);
?>
文件讀取漏洞成因
通過提交專門設計的輸入,攻擊者就可以在被訪問的文件系統中讀取或寫入任意內容,往往能夠使攻擊者從服務器上獲取敏感信息文件
$dir_path和$filename 沒有經過校驗或者不嚴格,用戶可以控制這個變量讀取任意文件(/etc/password..../index.php)
漏洞之所以會發生是因爲攻擊者可以將路徑遍歷序列放入文件名內,從當前位置向上回溯,從而瀏覽整個瀏覽器的的任何文件
給出一個典型攻擊
http://127.0.0.1/path_traversal.php?path=..\
如果應用程序把file參數的值附加到目錄名稱之後,就得到以下
路徑:D:\Program Files\phpstudy\WWW\..\
這個遍歷序列立即從當前目錄回溯到Web目錄上一級目錄,因此前
面的路徑等同於以下路徑:
D:\Program Files\phpstudy
漏洞過濾缺陷繞過:
提交大量的遍序列:幾乎每一種文件系統都接收試圖向上回溯到文件系統根目錄的多餘遍歷序列:有助於避免誤報警
分隔符:widows接收\和/作爲目錄的分割符,而UNIX接收/作爲分隔符。但是一些WEB應用程序過濾兩者之一。
漏洞挖掘:
使用編碼,對遍歷序列進行簡單的URL編碼(對輸入的每一個斜線和點編碼)
點 %2e
斜線%2f
反斜線%5c
雙倍URL編碼:有的網站waf會對想url進行一次解析進行過濾。這樣雙倍編碼就變成了單次編碼,在送給webserver再進行解析。完成目錄賓律。
點 %u002
斜線%u2215
反斜線%u2216
16位Unicode編碼
點 %u002
斜線 %u2215
反斜線 %u2216
嘗試使用下面的超長UTF-8 Unicode編碼:
點 %c0%2e、 %e0%40%ae、 %c0ae等
斜線 %c0%af、 %e0%80%af、 %c0%2f等
反斜線 %c0%5c、 %c0%80%5c等
這些表示法違反了Unicode表示法規則,卻爲許多Unicode解碼器接受,特別是Windows平臺的解碼器。
如果程序嘗試通過刪除遍歷序列來淨化用戶輸入,但沒有以遞歸的方式應用這種過濾,那麼可以用一個序列替換另一個序列來避開過濾。.
例如:
....//
....\/
..../\
....\\
<?php
function checkstr($str,$find){
$find_str=$find;
$tmparray=explode($find_str,$str);
if(count($tmparray)>1){
return true;
}else{
return false;}
}
$hostdir=$_REQUEST['path'];
if(!checkstr($hostdir,"..")&&!checkstr($jostdir,"../")){
echo $hostdir;
}else{
echo "請勿提交非法字符";
}
?>
修復方案:
過濾.(點)等可能的惡意字符:這個試用於能夠修改線上代碼,最爲推薦的方法
正則判斷用戶輸入的參數的格式,看輸入的格式是否合法:這個方法的匹配最爲準確和細緻,但是有很大難度,需要大量時間配置規則。
php.ini 配置 open_basedir:這個參數值得的是用戶只能訪問的目錄,作爲不能修改線上代碼時的備用方案。
文件讀取修補方案:
<?php
$filename = $_REQUEST['file'];
switch($filename){
case "config":
echo file_get_contents("config.php");
break;
default:
echo '請求錯誤';
}
?>