什么是文件包含(漏洞)?
程序開發人員一般會把重復使用的函數寫到單個文件中,需要使用某個函數時直接調用此文件,而無需再次編寫,這種文件調用的過程一般被稱為文件包含。
而此時如果沒有對文件來源進行嚴格審查,就會導致任意文件讀取或者任意命令執行,php中與文件包含的有關的函數為 (include(),require()和include_once(),require_once())它們的區別如下
include():只有代碼執行到該函數時才會包含文件進來,發生錯誤時只給出一個警告並繼續向下執行。 include_once():和include()功能相同,區別在於當重復調用同一文件時,程序只調用一次。 require():只要程序執行就包含文件進來,發生錯誤時會輸出錯誤結果並終止運行。 require_once():和require()功能相同,區別在於當重復調用同一文件時,程序只調用一次。
文件包含(漏洞)分為本地包含和遠程包含,想要遠程包含時需要在php.ini配置文件中將allow_url_fopen設置為On(開啟狀態)。
文件包含(漏洞)讀文件
下面以DVWA文件包含模塊進行舉例,首先查看一下,low級別的源代碼
<?php // The page we wish to display $file = $_GET[ 'page' ]; ?>
我們發現代碼中沒有對接收的page參數做任何處理,所以參數page是不可控的,這樣就會造成任意文件讀取和任意命令執行。先看一下原始的URL
http://www.test.com/DVWA-master/vulnerabilities/fi/?page=include.php
我們將include.php替換成不存在的來看一下,我們發現報錯了,並且報出了絕對路徑。如下圖
接下來咱們構造如下URL,發現讀取到了配置文件php.ini
http://www.test.com/DVWA-master/vulnerabilities/fi/?page=D:\phpstudy_pro\WWW\www.test.com\DVWA-master\php.ini
如下圖
接下來咱們看一下中級別的源代碼
<?php // The page we wish to display $file = $_GET[ 'page' ]; // Input validation $file = str_replace( array( "http://", "https://" ), "", $file ); $file = str_replace( array( "../", "..\"" ), "", $file ); ?>
發現中級別的使用的str_replace函數,將http:// https:// ../ ..\ 都替換為空格,也就是相當於刪除了,但是這種安全措施,很容易繞過,你不是刪除嗎,那我雙寫,比如,可以將前面內容構造成htthttp://p://,這個函數將中間的http://刪除,剩下的內容重新構成http://,這樣就繞過了,執行了構造的惡意鏈接。
../和..\同樣的道理,這是用這樣的方式,如下圖,咱們依然讀取了php.ini配置文件。
下面咱們看一下高級別的源代碼
<?php // The page we wish to display $file = $_GET[ 'page' ]; // Input validation if( !fnmatch( "file*", $file ) && $file != "include.php" ) { // This isn't the page we want! echo "ERROR: File not found!"; exit; } ?>
發現高級別的源代碼用了fnmatch函數,對page參數進行檢查,如果包含的文件后綴,不是include.php,那就要求page參數的開頭必須是file,服務器才會去包含相應的文件。這樣咱們還是有方法繞過,可以使用file協議繞過。
再看一下最高級別的核心源代碼
<?php // The page we wish to display $file = $_GET[ 'page' ]; // Only allow include.php or file{1..3}.php if( $file != "include.php" && $file != "file1.php" && $file != "file2.php" && $file != "file3.php" ) { // This isn't the page we want! echo "ERROR: File not found!"; exit; } ?>
最高級別的只允許包含上面三個文件,杜絕了文件包含漏洞。
包含日志文件
而有些時候,當發現本地包含漏洞,普通方法咱們都試過了發現無法利用,這時候可以換一種思路,可以利用日志文件來進行入侵。這里以Apache舉例,Apache服務器運行后會生成兩個日志文件,這兩個文件是access.log(訪問日志)和error.log(錯誤日志),apache的日志文件記錄下我們的操作,並且寫到訪問日志文件access.log之中,這時候咱們直接在參數后加上咱們的惡意代碼,頁面報錯,這個錯誤信息就會記錄到access.log中,里面包含了惡意代碼,這時候只要知道日志的路徑,就可以使用菜刀鏈接,直接getwebshell。
PHP內置協議
PHP帶有很多內置URL風格的封裝協議,可用於類似fopen()、copy()、file_exists()和filesize()的文件系統函數。有想要了解的小伙伴可以去PHP官網,官網地址http://www.php.net/manual/zh/wrappers.php。這里列出了一些
File:// /*訪問本地文件系統*/ htt[p:// /*訪問HTTP(s)網址*/ ftp:// /*訪問FTP(s)URLS*/ php:// /*訪問各個輸入/輸出流(I/o streams) zlib:// /*壓縮流*/ data:// /*數據(RFC2397)*/ ssh2:// /*Secure Shell 2*/ expect:// /*處理交互式的流*/
實例
說明:通過本地包含直接getwebshell,直接控制整個網站權限。大體思路:構造錯誤頁面,里面包含惡意代碼,利用thinkphp的錯誤日志功能,直接菜刀連接。
實戰環境是,易酷cms2.5 源碼下載地址 https://dl.pconline.com.cn/download/1492133.html
我已經下載源碼,本地搭建好了,直接開始,搭建好的頁面顯示如圖
接下來構造錯誤頁面,如下圖
接下來,在url的后面結合thinkphp的模板語法構造一句話為:{~eval($_POST[-7])},結果如下圖,發現咱們的一句話木馬已經插入到錯誤日志中
可以找到/temp/logs/目錄下找到這個文件,咱們確定一下看看錯誤日志里到底有沒有咱們的木馬,發現確實存在
然后菜刀連接,成功getwebshell