HCTF2018 Warmup 学习笔记



    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\" />";

    } 

?>

这里先来看第一段

 $_page = mb_substr(

                $page,

                0,

                mb_strpos($page . '?', '?')

            );

 if (in_array($_page, $whitelist)) {

                return true;

            }

很容易发现
只要$page里面没有?,mb_strpos()就会返回0,mb_substr()就不会截取字符串。
经过@Shana师傅的指正,是因为返回的是末尾的位置数,所以
$_page就是原来的字符串。

再来看第二段


$_page = urldecode($page);

            $_page = mb_substr(

                $_page,

                0,

                mb_strpos($_page . '?', '?')

            );

            if (in_array($_page, $whitelist)) {

                return true;

            }

这里 $page经过了urldecode()解码赋值给了 $_page,需要注意的是,这里和第一段是不一样的。mb_strpos()和mb_substr()都是处理的 $_page,而非第一段的 $page。

这里的思路就是让$page解码后出现?,然后就会返回true。因为下面一段就是返回false了,这里不返回true,就不会进入文件包含那个if里面了。


if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;

方法1

整体的思路就是第一段不出现?,第二段又要出现?。
所以进行二次urlencode编码, %253f
浏览器会自动解码一次变成%3f,再经过代码的urldecode()变成?。
接下来就是文件包含了。

HCTF2018 Warmup 学习笔记_第1张图片

update: 2018/11/3 22:33

这里的文件包含和题目部署环境有关,Windows由于目录命名规则不能带?。
所以只能使用方法1。

方法2

直接 source.php?/…/phpinfo.php 来包含
source.php?这个目录不存在, …/又目录穿越了(CSDN有猫病,两个点显示三个点),
所以就是当前目录的phpinfo.php。
因为我本地flag.php和phpinfo.php在同个目录,所以文件包含成功。

你可能感兴趣的:(学习)