[HCTF 2018]Warmup 详细题解

知识点:

目录穿越_文件包含

static静态方法

参数传递引用

mb_strpos函数 mb_substr函数

正文:

页面有一张 滑稽 的表情包,查看一下页面源代码,发现提示

那就访问/source.php 得到源码

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

可以看到有一个hint.php 访问一下

提示flag not here, and flag in ffffllllaaaagggg 得到了flag文件名

代码审计:

前面都是类中的代码,先看最后的代码

php 复制代码
    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\" />";
    }  

$_REQUEST 可以接收 GET POST COOKIE 传入的参数

需要存在file参数是字符串类型,并且经过emmm类中的checkFile方法返回true,才能执行include函数进行文件包含

这里没有创建emmm类的实例就可以引用其中的方法,是因为类中static表示是一个静态方法,可以通过类名直接调用,而不需要创建类的实例

目标明确之后开始看emmm类中的代码,类中也只有一个checkFile 方法,所以很简单,顺着往下看

给出了白名单,是source.php 和 hint.php 然后对参数page设置了条件

参数page就是传入的file数据,这里用了&$page,表示可以直接修改传入的变量,而不需要返回值来更新该变量

最终的目的是include $_REQUEST['file'] 包含其中有flag的文件,也就是ffffllllaaaagggg

目标就是让参数file也就是类中参数page包含ffffllllaaaagggg的同时满足checkFile方法返回true

首先page参数需要存在并且是字符串类型,然后if(in_array(page, whitelist)) 这个判断是无法满足的,因为得有flag文件名,但是没影响,只要不返回false就行,接着往下看

php 复制代码
$_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
php 复制代码
mb_strpos函数:  查找字符串在另一个字符串中首次出现的位置

mb_strpos ($haystack , $needle , $offset )
$haystack:被搜索的字符串
$needle:  要查找的字符串
$offset:  可选参数,指定从哪个字符开始搜索
//如果为正数,则从字符串的开头开始计算;如果是负数,则从字符串的末尾开始计算
//没有的话默认是0,即从开头开始搜索

mb_substr函数:  从一个字符串中提取子字符串

mb_substr ($str , $start , $length )
//substr() 函数只针对英文字符,而mb_substr()对于中文也适用
$str:    原始字符串
$start:  起始位置,如果为正数,则从字符串的开头开始计算;如果是负数,则从字符串的末尾开始计算
$length: 可选参数,表示要提取的子字符串的长度,如果没赋值,则提取从开始到字符串结束的所有字符

'.' 是 PHP 中的字符串连接运算符,它用于将两个字符串连接在一起,形成一个更长的字符串

在这里,它将 $page 变量的值和一个问号字符 '?' 连接在一起,形成一个新的字符串,在这个新的字符串中查找问号是否存在,那么很明显能找到

首先使用mb_strpos函数找到page中第一个问号的位置,然后使用mb_substr函数将问号之前的部分赋值作为_page进行处理
经过mb_strpos和mb_substr函数得到的$_page如果在白名单中,返回true

后面的代码对page 进行url解密之后赋值给_page,再次进行mb_substr函数得到新的$_page,再次判断是否在白名单中,不过如果传入的是正常的字符串,url解码之后还是本身,就没意义了

如果这一步进行完$page还不在白名单中,就会返回false

结合起来发现,只需要传入一个在白名单内的文件名(source.php或者hint.php)并在后面加上问号?

就可以保证在第二次if(in_array(_page, whitelist))匹配查找的内容在白名单,返回true,退出checkfile方法,后面的urldecode代码都是用不到的

不在文件名后面加?问号的话代码自动加的?会添加在参数末尾,这样截取的内容就不满足白名单

关于include函数

这样的话,参数的格式就是source.php? + 文件名

include()函数可以传入文件的绝对路径,也可以是相对路径

而参数是作为include()函数的参数执行文件包含的,绝对路径我们不知道,只能用相对路径

如果直接传入source.php?ffffllllaaaagggg,那么肯定会报错,因为没有这么一个文件名

实践出真知, 使用 include($_GET['file']); 这个简单的代码来简单说明一下

下图中的phpinfo.php是代码文件目录下面的一个php文件,abc是我随便输入的,没有这个目录,如果正常输入abc/phpinfo.php 是不行的,即使这个目录是存在的,也是会报错,因为格式不对

但是只要用../ 退回一级,就可以正常包含phpinfo.php

但是如果把abc 换成 abc? ,只要出现了? 那么就会报错

因为在windows文件名不能包含?

但是这里题目的环境是debian 不是windows系统 所以可以

那么这里搞清楚了,剩下的就是查找flag文件的具体路径了

从source.php?/ffffllllaaaagggg 开始,逐级用../进行目录穿越 经过四次目录穿越发现成功执行了命令,得到了flag

其实发现文件名也提示了我们要使用四层目录,文件名是4个f l a g

构造

php 复制代码
http://node4.anna.nssctf.cn:28698/source.php?file=source.php?/../../../../ffffllllaaaagggg

即可得到flag

相关推荐
0白露1 小时前
Apifox Helper 与 Swagger3 区别
开发语言
Tanecious.2 小时前
机器视觉--python基础语法
开发语言·python
叠叠乐2 小时前
rust Send Sync 以及对象安全和对象不安全
开发语言·安全·rust
ALe要立志成为web糕手2 小时前
SESSION_UPLOAD_PROGRESS 的利用
python·web安全·网络安全·ctf
zhu12893035563 小时前
网络安全的现状与防护措施
网络·安全·web安全
Tttian6223 小时前
Python办公自动化(3)对Excel的操作
开发语言·python·excel
独好紫罗兰4 小时前
洛谷题单2-P5713 【深基3.例5】洛谷团队系统-python-流程图重构
开发语言·python·算法
wirepuller_king5 小时前
创建Linux虚拟环境并远程连接,finalshell自定义壁纸
linux·运维·服务器
zhu12893035565 小时前
网络安全与防护策略
网络·安全·web安全
Yan-英杰5 小时前
【百日精通JAVA | SQL篇 | 第二篇】数据库操作
服务器·数据库·sql