[HCTF 2018]WarmUp

进去之后就是一个图 查看源码得到提示 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\" />";
    }  
?> 

主程序

一个if语句检查了如下内容:

1.非空

2.是否为字符串

3.能够通过emmm类的checkFile函数

同时满足上述条件则通过include函数包含对应文件,否则就是滑稽脸的图片

emmm类checkFIle函数分析

上来在白名单内得到提示 看hint.php

flag not here, and flag in ffffllllaaaagggg

那就猜测flag应该在ffffllllaaaagggg.php页面 回到源码 进行分析

首先定义了白名单 包含了 source.php 和 hint.php

接下来就是四个 if 语句的判断和部分对参数的处理语句

part1

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

先判断是否提交了$page变量以及是不是字符串 如果不是就返回false

part2

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

判断上传内容是否在白名单内 若没有返回false

part3

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

用到两个函数从内往外为mb_strpos()函数和mb_substr()函数

整个语句的作用是先查找$page变量中第一次出现 ‘ ? ’的位置,再将第一位开始到第一次出现问号的部分进行截断返回剩余串

mb_strpos()

mb_strpos (haystack ,needle )

haystack:要被检查的字符串。

needle:要搜索的字符串。

返回值为目标串在被检查串第一次出现的位置

mb_substr()

截取函数mb_substr ( string $str , int $start [, int $length = NULL [, string $encoding = mb_internal_encoding() ]] ) : string

str 必需。从该 string 中提取子字符串。

start 必需。规定在字符串的何处开始。

正数 - 在字符串的指定位置开始
负数 - 在从字符串结尾的指定位置开始
0 - 在字符串中的第一个字符处开始

length 可选。规定要返回的字符串长度。默认是直到字符串的结尾。

正数 - 从 start 参数所在的位置返回
负数 - 从字符串末端返回

encoding 可选。字符编码。如果省略,则使用内部字符编码。

part4

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

再次判断剩余串是否在白名单内

part5

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

对$page变量进行url解码再执行一次截断

part6

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

再次进行判断剩余串是否在白名单内

part7

echo "you can't see it";
            return false;

若以上判断都为false最终就返回false

构造payload绕过

符合函数要求的payload为?file=source.php

因为'?'在函数中进行了两次截取 所以第一个问号处不可利用,判断白名单也无法利用所以只能在第二次截断是绕过

用url编码 对 ' ? ' 进行两次编码 为%253f 则在页面提交时 解码为%3f在第二次截断时被解码为 ' ? ' 从而达到保留最后内容的目的。

payload 1.0:?file=source.php%253fffffllllaaaagggg

可是包含未成功,但是注意到没有了滑稽 说明有可能是文件路径不对 不在同一目录下 那就多返回几层目录试试

payload 2.0:?file=source.php%253f../../../../../ffffllllaaaagggg

成功绕过getflag

最后修改:2020 年 08 月 16 日 11 : 21 AM
请作者喝杯奶茶吧~