• 中文
    • 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
  • 2.5k
  • 请登录之后再进行评论

    登录
    单栏布局 侧栏位置: