• 中文
    • English
  • 注册
  • 查看作者
    • [HCTF 2018]WarmUp 1

      题目简介

        • 本地文件包含漏洞

      解题步骤

      1. 启动并访问靶机,前端只有一个滑稽的表情

      [HCTF 2018]WarmUp 1

      2. 右击或F12审计一下代码,可以看到source.php,我们访问一下该页面

      [HCTF 2018]WarmUp 1

      3. source.php内容如下。

      <?php
          highlight_file(__FILE__);
          class emmm
          {
              public static function checkFile(&$page)
              {
                  $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
                  if (! isset($page) || !is_string($page)) {
                      echo "you can't see it";
                      return false;
                  }
      
                  if (in_array($page, $whitelist)) {
                      return true;
                  }
      
                  $_page = mb_substr(
                      $page,
                      0,
                      mb_strpos($page . '?', '?')
                  );
                  if (in_array($_page, $whitelist)) {
                      return true;
                  }
      
                  $_page = urldecode($page);
                  $_page = mb_substr(
                      $_page,
                      0,
                      mb_strpos($_page . '?', '?')
                  );
                  if (in_array($_page, $whitelist)) {
                      return true;
                  }
                  echo "you can't see it";
                  return false;
              }
          }
      
          if (! empty($_REQUEST['file'])
              && is_string($_REQUEST['file'])
              && emmm::checkFile($_REQUEST['file'])
          ) {
              include $_REQUEST['file'];
              exit;
          } else {
              echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
          }  
      ?>

      4. 可以看到include函数没有任何过滤措施,那么我们可以利用本地文件包含漏洞来访问任意文件,以获取flag,但是想要执行include函数,我们需要满足三个条件:

        1. file不为空

        2. file的值是字符串

        3. file通过emmm类的checkFile方法校验

      5. 第一和第二个条件都很简单,主要是第三个条件checkFile方法的校验规则非常麻烦,我们先来逐行解释一emmm类每一行代码的作用:

      <?php
      highlight_file(__FILE__);
      class emmm
      {
          //$page前面加&代表引用,这里是引用传递
          public static function checkFile(&$page)
          {
              //定义whitelist数组
              $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
      
              //如果page变量未声明或为null,或者不是字符串,则进入if
              if (! isset($page) || !is_string($page)) {
                  echo "you can't see it";
                  return false;
              }
              //如果page的值在$whitelist数组里则进入if
              if (in_array($page, $whitelist)) {
                  return true;
              }
      
              //截取从0到?首次出现的位置的字符串
              $_page = mb_substr(
                  $page,
                  0,
                  mb_strpos($page . '?', '?') //点在php中用来连接两个字符串或变量,此代码意思为拼接page和?的值,并返回?字符首次出现的位置
              );
      
              //如果_page的值在$whitelist数组里则进入if
              if (in_array($_page, $whitelist)) {
                  return true;
              }
              //对page解码
              $_page = urldecode($page);
      
              //截取从0到?首次出现的位置的字符串
              $_page = mb_substr(
                  $_page,
                  0,
                  mb_strpos($_page . '?', '?')
              );
              //如果_page的值在$whitelist数组里则进入if
              if (in_array($_page, $whitelist)) {
                  return true;
              }
              echo "you can't see it";
              return false;
          }
      }
      //如果file变量为空 且 是字符串  且 通过checkFile 校验,则进入if
      
      if (! empty($_REQUEST['file'])
          && is_string($_REQUEST['file'])
          && emmm::checkFile($_REQUEST['file'])
      ) {
          include $_REQUEST['file'];
          exit;
      } else {
          echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
      }
      ?>

      6. 读懂了emmm类的代码后,我们需要构造file的值。本地文件包含漏洞的格式一般是file=../../../.../xxx,其中../的个数不固定,xxx为flag文件名,那么这个xxx具体是什么呢?我们尝试访问一下hint.php,发现提示:flag not here, and flag in ffffllllaaaagggg,可以猜测到服务器存放flag的文件名可能为ffffllllaaaagggg,我们可以构造的file=../ffffllllaaaagggg,将其带入checkFile中看一下是否可以返回true。

      7. 步骤一:因为我们定义了file的值且是string类型,所以第一个if 的return false 顺利绕过

      if (! isset($page) || !is_string($page)) {
          echo "第一个if未通过";
          eturn false;
       }

      8. 步骤二:因为我们的file的值既不是souce.php也不是hint.php,所以是无法通过该if的,直接放弃这个return true的机会,继续往下看。

      if (in_array($page, $whitelist)) {
        return true;
      }

      9. 步骤三:mb_substr会将file的值通过一定的规则截取后,再次放入if判断,那么我们可以在file的值前面主动拼接一个souce.php?或者hint.php?,也就是file=source.php?../ffffllllaaaagggg,通过mb_substr截取后的值是souce.php,此时checkFile返回true

      //截取从0到?首次出现的位置的字符串
      $_page = mb_substr(
          $page,
          0,
          mb_strpos($page . '?', '?') //点在php中用来连接两个字符串或变量,此代码意思为拼接page和?的值,并返回?字符首次出现的位置
      );
      
      
      //如果_page的值在$whitelist数组里则进入if
      if (in_array($_page, $whitelist)) {
          return true;
      }

      10. 我们逐个添加../的个数,最终发现当file=source.php?../../../../../ffffllllaaaagggg的时候,输出flag:flag{784155f9-68a0-4772-ac02-3eaa0105f3ac}

      知识详解

      一:php常见函数

      • isset:检测变量是否已声明并且其值不为 null

      • in_array:检查数组中是否存在某个值,第一个参数为待搜索的值,第二个参数为要搜索的数组

      • is_string:检测变量是否是字符串

      • empty:检查一个变量是否为空

      • $_REQUEST:$_REQUEST可以获取以POST方法和GET方法提交的数据

      • mb_strcut() :根据 start 和 length 参数返回 str 的一部分

      • mb_strpos():查找字符串在另一个字符串中首次出现的位置

      • urldecode(): 解码已编码的 URL 字符串

      • include():包含并运行指定文件

      • include_once() :include_once 表达式和 include 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含

      • require() :require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时脚本会中止,而include会继续运行。

      • require_once():require_once 表达式和 require 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

      二:文件包含漏洞

      文件包含漏洞

      漏洞原因:

      • php代码中使用了文件包含函数

      • 文件包含函数参数可以自定义且没有经过过滤

      漏洞分类:

      • 本地文件包含漏洞(LFI):指包含本地服务器中的文件

        • 格式:?file=../../../xxxx

      • 远程文件包含漏洞(RFI):指包含远程服务器中的文件

        • php.ini中的allow_url_fopen = On和 allow_url_include = On 时,才可以利用该漏洞

        • 格式:?file=http://xxxx.xxx/xxxx

      • php中引发文件包含漏洞的通常是以下四个函数:

        • include():包含并运行指定文件

        • include_once() :include_once 表达式和 include 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含

        • require() :require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时脚本会中止,而include会继续运行。

        • require_once():require_once 表达式和 require 表达式完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

        • 当利用这四个函数来包含文件时,不管文件是什么类型(图片、txt等等),都会直接作为php文件进行解析。[1]

      参考资料

      未知
    • 0
    • 0
    • 0
    • 280
    • 请登录之后再进行评论

      登录

      赞助本站

      • 支付宝
      • 微信
      • QQ

      感谢一直支持本站的所有人!

      单栏布局 侧栏位置: