HCTF-2018-Web-warmup WriteUp

0x01 题目环境

题目环境在CTFhub上,在下方链接搜索warmup即可。

https://www.ctfhub.com/#/challenge

打开环境,只发现了一张滑稽图。如下
HCTF-2018-Web-warmup WriteUp_第1张图片
我们看一眼源码,并没有发现什么有用的信息,但是这一行有点问题。
HCTF-2018-Web-warmup WriteUp_第2张图片

0x02 代码审计

我们尝试访问一下这个东西,然后发现这是一道代码审计题。

http://challenge-73ef6a42b59996b3.sandbox.ctfhub.com:10080/?file=source.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()函数,看下面的判断。

    if (! empty($_REQUEST['file'])     
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "
"
; }
1.$_REQUEST['file']不为空,!empty($_REQUEST['file']返回true2.$_REQUEST['file']是字符串,is_string($_REQUEST['file']返回true;
3.emmm::checkFile($_REQUEST['file']返回true.
4.上述三个条件都满足时,会执行include()函数,这是一个文件包含漏洞,具体后面再说。
有一个条件不满足时,则显示一张图片,就是上文中的滑稽图。而对于第一第二个条件十分容易满足,因此我们重点分析放在第三个条件上。

在这个checkFile()函数中,将传入的参数'file'赋值给了$page

$whitelist = ["source"=>"source.php","hint"=>"hint.php"];

这行是定义了一个白名单,含有"source.php""hint.php"两个元素。
source.php上文中已经访问过,我们再访问一下hint.php

这里有一个关键信息就是flag存储在ffffllllaaaagggg中,因为这道题涉及到文件包含,我们不妨假设这是一个文件名,需要利用文件包含漏洞打开。

if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

这一段也好理解,当 $page不存在或者$page不是字符串时,打印"you can't see it"并返回false。由于我们需要返回true,因此这个条件容易满足。

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

这一段是白名单验证,检查$whitelist中是否含有$page。而验证十分容易,我们访问这两个文件时已经利用过了。

$_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );

这一段代码中牵扯到两个函数mb_substrmb_strpos。不熟悉的话可以查看下方链接。

https://www.php.net/manual/zh/function.mb-substr.php
https://www.php.net/manual/zh/function.mb-strpos.php

经过分析,我们可以发现这段代码的作用是截取$page中到第一个?之前的内容。
而下面一段代码上文出现过一次,是对截取之后的内容进行白名单验证。

 $_page = urldecode($page);

这一行是对$page进行URL decode,然后再经过一次截取,截取之后进行白名单验证。
到此我们分析完了checkFile()函数,其中有多处可以返回true值,而如何构造payload我们还要看include()函数。

0x03 构造payload

如果flag包含ffffllllaaaagggg中的话,我们并不能确定这个文件的具体位置,但是我们可以通过找到它的相对位置来访问它。即构造../来完成。
因此我们的payload可以是这种形式:

$page=source.php../ffffllllaaaagggg

我们先不考虑这样是否能够找到ffffllllaaaagggg,我们先看这样的payload能否经过checkFile()函数的验证。
第一个if成功绕过,第二个返回false,截取不变,第三个if返回false,URL解码不变,截取不变,第四个if返回false,最终返回false。因此这样并不行。
那么我们就考虑截取的那一段代码,它会返回?前的内容,如果我们构造一个这样的payload

$page=source.php?../ffffllllaaaagggg

第一个if成功绕过,第二个返回false,截取后变成

$_page=source.php

第三个if返回true,跳出函数。因此这样的payload是可以满足checkFile()函数的验证的。
然后我们再考虑文件包含的问题,而这个我们只要通过不断尝试就能发现这样是可行的。

$page=source.php?../../../../../ffffllllaaaagggg

在这里插入图片描述
当然payload的形式有很多种,比如将source.php换成hint.php。此外,还有关于代码种URL解码那一段,可能有人会有疑问为什么没有用到。当然这段代码不是没有用的,当我们构造这样的payload时,就会用到。

$page=source.php%3f../../../../../ffffllllaaaagggg

因为%3f经过一次解码就是?。不过考虑到可能环境的不同,有上传经过服务器时服务器会自动进行一次解码,因此构造这样的payload也是有的。

$page=source.php%253f../../../../../ffffllllaaaagggg

%253f经过一次解码是%3f。这可能会因为不同的操作系统而不同,具体通过尝试就可以知道。

你可能感兴趣的:(Web,php,web)