当前位置:首页 > 热点

什么是文件包含漏洞

一个网站的什文正常链接是 page.php?file=about,你把它改成 page.php?含漏file=../../etc/passwd,服务器就把系统用户文件的什文内容吐出来了。这就是含漏文件包含漏洞最直白的模样。

它的什文成因不复杂。程序员写代码时想让页面灵活一点,含漏比如根据 URL 参数动态加载不同的什文模块,于是含漏用了 include、require 这类函数,什文参数直接从用户输入里取。含漏问题就出在这里——用户输入没有被严格检查。什文本来只想让它包含 about.php,含漏结果攻击者塞进去一个路径,什文代码照样执行,含漏服务器照样听话。什文

文件包含分两种。本地文件包含(LFI)是读取服务器本地的文件,比如 /etc/passwd、日志文件、配置文件。远程文件包含(RFI)更危险,攻击者能把外部服务器上的恶意脚本包含进来直接执行。RFI 需要 PHP 的 allow_url_include 打开,默认是关的,所以 LFI 更常见。但 LFI 配合文件上传或者日志投毒,照样能拿到 shell。

我见过一个真实案例。某小型 CMS 的下载功能写成 download.php?file=files/report.pdf,没有过滤 ../。攻击者构造 file=../../../../var/log/apache2/access.log,然后往 User-Agent 里写一段 PHP 代码,再请求这个日志文件。代码被执行,服务器沦陷。整个过程不需要任何高级漏洞,就是路径没洗干净。

为什么这种漏洞反复出现?因为很多开发者觉得“只是读个文件而已”。他们没意识到,文件包含的本质是代码执行,不是文件读取。你包含一个 PHP 文件,里面的代码就会跑起来。你包含一个日志文件,如果日志里有 PHP 标签,也会跑起来。这个区别很关键,但容易被忽略。

防御手段其实不复杂。最直接的是白名单——只允许包含指定的几个文件名,其他一律拒绝。比如 $allowed = ['about', 'contact', 'help'];,然后检查参数是否在数组里。这比黑名单靠谱得多,因为绕过黑名单的手法太多了:....//、..%2f、绝对路径、PHP 流包装器……你堵不完的。

另一个办法是关掉 allow_url_include 和 allow_url_fopen,这能挡住 RFI。但 LFI 还在,所以还得配合 open_basedir 限制 PHP 能访问的目录范围。再狠一点,直接把用户输入拼进 include 语句的写法废掉,改用映射表或者 switch 分支。

有些开发者会用 basename() 来过滤,觉得取个文件名就安全了。但 basename() 在 Windows 和 Linux 下行为不一样,而且对某些编码绕过无效。我见过 basename() 被 %00 截断绕过的案例——虽然 PHP 5.3.4 之后修了空字节问题,但老系统还在跑。

文件包含漏洞的破坏力取决于上下文。如果包含点能执行代码,那就是远程代码执行,CVSS 评分直接拉满。如果只能读文件,那至少也是敏感信息泄露,配置文件里的数据库密码、API 密钥全暴露。更糟的是,很多 WAF 对文件包含的检测规则偏弱,因为正常请求里也可能出现 ../,误报和漏报都难平衡。

说个细节。PHP 的 include 和 require 在找不到文件时行为不同:include 只警告,require 直接 fatal error。攻击者有时候会利用这个差异来判断路径是否存在,像盲注一样一步步猜目录结构。这种技巧在 CTF 里很常见,真实渗透里也用。

最后提一句,文件包含漏洞不限于 PHP。JSP 的 <jsp:include>、ASP 的 <!--#include--> 都有类似风险,只是利用方式不同。核心逻辑永远一样:用户能控制被包含的路径,且没有足够的限制。修的时候别只盯着 PHP 函数,整个包含机制都得审一遍。

分享到: