有关文件包含的一些问题辨析

$file这个变量到底被赋予了什么值

这是一道例题,首先我们知道文件包含的解题中,一些协议至关重要

由超全局变量$_GET或者$_POST得到的值,一般会赋予给一个变量,而这个变量的具体值,取决于这个协议的内容:

  1. file://协议

这个协议一般指定文件路径直接打开文件,比如?file=file:///etc/passwd,或者?file=file:///var/www/html/index.php,此时后者就会把index.php文件的值直接赋予给$file变量,

  1. php://协议

但是如果我输入的是?file=php://input,那么$php这个变量的值就是php://input

include函数的辨析

  • 其他几个也是一样的。

  • include函数会根据$file的值来处理内容。如果$file是普通文件路径,它会包含文件内容;如果$filePHP 流包装器,它会处理流中的内容。在 CTF 题目中,通过巧妙利用php://协议等流包装器,可以绕过一些限制来获取目标文件(如flag.php)的内容。

  • 关于文件内容的包含:
    在 PHP 里,当你使用include语句引入一个包含eval函数的 PHP 文件时,include所在的文件会执行被引入文件里的代码,这里面也包括我们经常使用的eval函数中的代码。

  • 比如:

    1
    2
    3
    4
    <?php
    $code = 'echo "这段代码由 eval 执行!";';
    eval($code);
    ?>

    引入上述文件的文件main.php

    1
    2
    3
    <?php
    include 'test_eval.php';
    ?>

    当你运行main.php时,它会引入test_eval.php,并且执行其中的代码,这就会触发eval函数去执行其内部的代码。

关于ctfshow web28的进一步详细理解

以下是这个题目的题干和大概解释

我来一个个说问题

  1. 首先,我们为了看flag.php这个文件是否存在,我们就直接利用file://协议读取这个文件,即DN/?file=flag.php直接读取,发现是一片空白,查源码也是一片空白,至少这步证实了flag.php这个php文件是存在的,根据我搜集资料所获得的信息,为什么flag.php在浏览器控制台源码都是空白的,解释是:因为php是服务器端语言,是运行在服务器里面的,在控制台源码里面呈现出来的都是php代码经过处理之后输出的html,css,js的语言,所以你看不到类似于$flag=xxxxxxx这种赋值语言。
  2. 那我们怎么搞呢,这时php://这种可以捕捉数据流的的协议就可以绕过这层障碍直接通过编码的方式获得服务器端源文件的内容,我们输入,/?file=php://filter/read=convert.base64/resource=flag.php这种编码就可以轻易读取到源文件内容,因为它直接捕捉服务器端给客户端的数据流,即可得到编码后的flag内容。
  3. 再说一句,我知道这时候$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
      <?php
      $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 web39

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <?php

    //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字符串.