摘要
PHP是一種非常流行的Web開發語言,互聯網上的許多Web應用都是利用PHP開發的。而在利用PHP開發的Web應用中,PHP文件包含漏洞是一種常見的漏洞。利用PHP文件包含漏洞入侵網站也是主流的一種攻擊手段。本文對PHP文件包含漏洞的形成、利用技巧及防范進行了詳細的分析,並通過一個真實案例演示了如何利用PHP文件包含漏洞對目標網站進行滲透測試,最終成功獲取到網站的WebShell。
1. PHP文件包含漏洞介紹
首先,我們來介紹下何為文件包含漏洞。嚴格來說,文件包含漏洞是“代碼注入”的一種。其原理就是注入一段用戶能控制的腳本或代碼,並讓服務端執行。“代碼注入”的典型代表就是文件包含。文件包含漏洞可能出現在JSP、PHP、ASP等語言中,原理都是一樣的,本文只介紹PHP文件包含漏洞。
要想成功利用文件包含漏洞進行攻擊,需要滿足以下兩個條件:
1.1 Web應用采用include()等文件包含函數通過動態變量的方式引入需要包含的文件;
1.2 用戶能夠控制該動態變量。
在PHP中,有四個用於包含文件的函數,當使用這些函數包含文件時,文件中包含的PHP代碼會被執行。下面對它們之間的區別進行解釋:
include():當使用該函數包含文件時,只有代碼執行到include()函數時才將文件包含進來,發生錯誤時只給出一個警告,繼續向下執行。
include_once():功能和include()相同,區別在於當重復調用同一文件時,程序只調用一次。
require():1.require()與include()的區別在於require()執行如果發生錯誤,函數會輸出錯誤信息,並終止腳本的運行。2.使用require()函數包含文件時,只要程序一執行,立即調用文件,而include()只有程序執行到該函數時才調用。
require_once():它的功能與require()相同,區別在於當重復調用同一文件時,程序只調用一次。
現在來看一段簡單的文件包含代碼,如下圖所示:
圖1
通過上面的代碼可以看到,在得到變量$filename的值后沒有經過任何處理,直接帶入include()函數中。此處就存在一個文件包含漏洞,利用該漏洞我們可以查看系統中的任意文件。
下面我們來實際測試一下,首先將該PHP頁面上傳到Web服務器,先讓其包含一個正常的txt文件,運行結果如下圖所示:
圖2
接着我們在該txt文本中插入php代碼,看結果如何?這里給其插入如下代碼:
圖3
再次訪問,結果如下圖所示:
圖4
通過上圖我們可以看到文本中的PHP代碼被成功執行了。
利用該漏洞我們可以查看系統中的任意文件,比如經常用到的“/etc/passwd”文件。
圖5
PHP文件包含漏洞分為本地文件包含漏洞(LFI)和遠程文件包含漏洞(RFI),能夠打開並包含本地文件的漏洞,被稱為本地文件包含漏洞。利用本地文件包含漏洞可以查看系統任意文件內容,如果具備一些條件,也可以執行命令。在下面的漏洞利用技巧部分對這個有詳細的介紹。
如果php.ini的配置選項allow_url_fopen和allow_url_include為ON的話,則文件包含函數是可以加載遠程文件的,這種漏洞被稱為遠程文件包含漏洞。利用遠程文件包含漏洞可以直接執行任意命令。在實際滲透攻擊過程中,攻擊者可以在自己的Web服務器上放一個可執行的惡意文件,通過目標網站存在的遠程文件包含漏洞來加載文件,從而實現執行任意命令的目的。
2. 文件包含漏洞利用技巧
遠程文件包含漏洞之所以能夠執行命令,就是因為攻擊者可以自定義被包含的文件內容。因此,本地文件包含漏洞要想執行命令,也需要找一個攻擊者能夠控制內容的本地文件。
目前主要有幾下幾種常見的技巧:
2.1 包含用戶上傳的文件。這個很好理解,也是最簡單的一種辦法。如果用戶上傳的文件內容中包含PHP代碼,那么這些代碼被文件包含函數加載后將會被執行。但能否攻擊成功,取決於上傳功能的設計,比如需要知道上傳文件存放的物理路徑,還需要上傳的文件有執行權限。
2.2 包含data://或php://input等偽協議。這需要目標服務器支持,同時要求allow_url_fopen為設置為ON。在PHP5.2.0之后的版本中支持data: 偽協議,可以很方便的執行代碼。
2.3 包含Session文件。這部分需要攻擊者能夠控制部分Session文件的內容。PHP默認生成的Session文件一般存放在/tmp目錄下。
2.4 包含日志文件。比如Web服務器的訪問日志文件,這是一種通用的技巧。因為幾乎所有網站都會將用戶的訪問記錄到訪問日志中。因此,攻擊者可以向Web日志中插入PHP代碼,通過文件包含漏洞來執行包含在Web日志中的PHP代碼。下面的安例中就是利用該技巧成功獲取到目標網站的WebShell的。但需要注意的是,如果網站訪問量大的話,日志文件可能會非常大,這時如果包含一個這么大的文件時,PHP進程可能會卡死。一般網站通常會每天生成一個新的日志文件,因此在凌晨時進行攻擊相對來說容易成功。
2.5 包含/proc/self/environ文件。這個也是一種通用的技巧。因為它根本不需要猜測被包含文件的路徑,同時用戶也能控制它的內容。常見的做法是向User-Agent中注入PHP代碼來完成攻擊。
3. 利用PHP文件包含漏洞滲透某網站案例
上面我們詳細的介紹了PHP文件包含漏洞的形成和測試,下面我們通過一個真實案例來講解下如何利用PHP文件包含漏洞對目標網站進行滲透攻擊。
目標網站:中國電信某業務系統
目的:獲取到目標網站的WebShell
詳細滲透過程:
3.1 發現漏洞
我們先來打開目標網站的一個URL看下,如下所示:
URL:http://XXX.vnet.mobi/index.php?path=jcb/zt/gfsdtjqg/index.html
注意path=后面的內容,通過這個URL可以發現index.php調用文件包含函數來包含網站目錄下的文件,並展示給用戶。但這時我們並不能確定此URL存在文件包含漏洞。下面我們來手工測試下是否存在文件包含漏洞。因為該網站存在一個phpinfo.php的測試頁面,我們可以通過該頁面得到目標網站的很多有用信息,不必進行模糊測試就可以獲取到Web目錄的絕對路徑,所以這里可以直接構造已知文件的路徑,讓其包含,快速確認是否存在文件包含漏洞。
我們來通過包含一個已知的文件”/etc/passwd”文件來確認以上URL是否文件包含漏洞。
圖6
OK,通過上面返回的結果可以確定網站存在文件包含漏洞,下面我們來演示下如何利用該漏洞進行滲透測試。
3.2 漏洞利用
通過上面的測試,我們可以確定網站存在文件包含漏洞。那么這時問題來了,如何利用這個漏洞來達到我們的目的呢?其中一個思路就是將后門代碼插入網站的Web日志文件中,利用目標網站存在的文件包含漏洞包含此日志文件,這時Web日志中的后門代碼將會作為PHP代碼執行,這樣我們就可以獲取到一個WebShell進行后續的攻擊。但這時面臨一個問題,我們需要知道Web日志的存放路徑,否則無法實現目標。通常Web日志存放路徑通過Web服務器的配置文件指定。通過上面獲取的信息可以確定目標網站使用的是Nginx服務器,因此我們可以先通過包含Web服務器配置文件(Nigix.conf)來獲取到Web日志存放路徑。具體操作如下圖所示:
圖7
3.3 獲取到WebShell
上面我們通過Web服務器配置文件(Nginx.conf)獲取到了Web訪問日志的存在路徑(/opt/nginx/logs/access.log),但因為該網站的日志文件很大,這時訪問WebShell程序會卡死,所以我們選擇凌晨的時候進行再次攻擊。因為一般的網站都是每天生成一個訪問日志文件,在凌晨的時候日志文件較小,容易成功。下圖展示了如下向Web訪問日志中插入后門代碼:
圖8
最終,我們成功獲取到了目標網站的WebShell。
圖9
4. PHP文件包含漏洞防范
本部分主要從代碼層和Web服務器安全配置兩個方面來講解PHP文件包含漏洞的防范。首先來從代碼層來講,在開發過程中應該盡量避免動態的變量,尤其是用戶可以控制的變量。一種保險的做法是采用“白名單”的方式將允許包含的文件列出來,只允許包含白名單中的文件,這樣就可以避免任意文件包含的風險。可參考下面的代碼實現:
圖10
還有一種做法是將文件包含漏洞利用過程中的一些特殊字符定義在黑名單中,對傳入的參數進行過濾,但這樣有時會因為過濾不全,導致被有經驗的攻擊者繞過。
在Web服務器安全配置方面可以通過設定php.ini中open_basedir的值將允許包含的文件限定在某一特定目錄內,這樣可以有效的避免利用文件包含漏洞進行的攻擊。需要注意的是,open_basedir的值是目錄的前綴,因此假設設置如下值:open_basedir=/var/www/test,那么實際上以下目錄都是在允許范圍內的。
/var/www/test
/var/www/test123
/var/www/testabc
如果要限定一個指定的目錄,需要在最后加上”/“,這一點需要特別注意。
open_basedir=/var/www/test/
如果有多個目錄,在Windows下目錄間用分號隔開,在Linux下面則用冒號隔開。
5. 總結
上面我們通過文字和代碼對PHP文件包含漏洞的形成、利用技巧及防范都做了詳細的分析,
並結合一個真實案例講解了如何利用PHP文件包含漏洞對目標網站進行滲透測試,最終獲取到一個WebShell權限。通過這些內容,相信讀者對PHP文件包含漏洞有了一個深入的認識。其實只要明白了漏洞的原理,對漏洞有一個深入的認識,加上安全意識,徹底解決PHP文件包含漏洞並不是一件困難的事情。