关于文件包含的一些问题辨析
有关文件包含的一些问题辨析
$file这个变量到底被赋予了什么值

这是一道例题,首先我们知道文件包含的解题中,一些协议至关重要
由超全局变量$_GET
或者$_POST
得到的值,一般会赋予给一个变量,而这个变量的具体值,取决于这个协议的内容:
file://
协议
这个协议一般指定文件路径直接打开文件,比如?file=file:///etc/passwd
,或者?file=file:///var/www/html/index.php
,此时后者就会把index.php
文件的值直接赋予给$file变量,
php://
协议
但是如果我输入的是?file=php://input
,那么$php
这个变量的值就是php://input
。
include函数的辨析
其他几个也是一样的。
include
函数会根据$file
的值来处理内容。如果$file
是普通文件路径,它会包含文件内容;如果$file
是PHP
流包装器,它会处理流中的内容。在 CTF 题目中,通过巧妙利用php://
协议等流包装器,可以绕过一些限制来获取目标文件(如flag.php)的内容。关于文件内容的包含:
在 PHP 里,当你使用include
语句引入一个包含eval
函数的 PHP 文件时,include
所在的文件会执行被引入文件里的代码,这里面也包括我们经常使用的eval
函数中的代码。比如:
1
2
3
4
$code = 'echo "这段代码由 eval 执行!";';
eval($code);引入上述文件的文件
main.php
1
2
3
include 'test_eval.php';当你运行
main.php
时,它会引入test_eval.php
,并且执行其中的代码,这就会触发eval
函数去执行其内部的代码。
关于ctfshow web28的进一步详细理解
以下是这个题目的题干和大概解释

我来一个个说问题
- 首先,我们为了看
flag.php
这个文件是否存在,我们就直接利用file://
协议读取这个文件,即DN/?file=flag.php
直接读取,发现是一片空白,查源码也是一片空白,至少这步证实了flag.php
这个php文件是存在的,根据我搜集资料所获得的信息,为什么flag.php
在浏览器控制台源码都是空白的,解释是:因为php是服务器端语言,是运行在服务器里面的,在控制台源码里面呈现出来的都是php代码经过处理之后输出的html,css,js的语言,所以你看不到类似于$flag=xxxxxxx
这种赋值语言。 - 那我们怎么搞呢,这时php://这种可以捕捉数据流的的协议就可以绕过这层障碍直接通过编码的方式获得服务器端源文件的内容,我们输入,
/?file=php://filter/read=convert.base64/resource=flag.php
这种编码就可以轻易读取到源文件内容,因为它直接捕捉服务器端给客户端的数据流,即可得到编码后的flag内容。 - 再说一句,我知道这时候$file这个变量被赋予的值是
php;//
这一大堆协议,为什么include
可以读取它呢?因为这是php的强大之处,include除了可以包含文件之外,还可以对这种协议进行读取,它通过知晓后面的resource=flag.php
文件,知道了对象,然后使用php;//filter/convert.base64-encode
对其服务器端源码进行处理,就可以把源码呈现。
关于include
以及$_GET
的格式辨析
在web命令执行题目中,有如下
payloads
:/?c=include$_GET[mmk]?>&mmk=data://text/plain,<?php system("ls");?>
这里补充:
1.
include
一般格式:对于具体的字符串:
example.php
,这种形式的包含对象是需要引号的,毕竟别人为字符串。对于已经被赋值的变量,比如:
1
2
3
4
$a = "example.php";
include $a;
/*后面代码略*/后面直接跟变量,就不用加引号了,加了引号反而变成字符串了。
2.
$_GET
等超全局变量的格式- 对于
$_GET[]
超全局变量括号中的参数,可以使用双引号、单引号,也可以不用任何引号。 - 比如我的
payloads
:/?c=include$_GET[mmk]?>&mmk=data://text/plain,<?php system("ls");?>
关于伪协议辨析
引用自
@Traveler2000
的博客:
data伪协议以及文件包含与php伪协议有关
data
伪协议的解析:
如例题:ctfshow web391
2
3
4
5
6
7
8
9
10
11
12
13
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}这里传入的payloads就是
?c=data://text/plain,%20<?php%20eval(system("cat%20fl*g.php"));%20?>
为什么include
中的"php"
这个字符串没有干扰payloads
的传入,因为data://
伪协议相当于在data://
后写入数据,data://
及其后的数据会被当作文件处理。也就是说,
data
伪协议只会把其后面的可被解析为php
代码的字符解析为php
代码,其他字符都会被返回到前端比如下图:
可以看到,payloads里面有一个多余的
php
,该php字符就被include
解析后返回到前端去了
这里有两个php
是因为题目源码里面的include
里本来就有一个php
字符串.