[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

相关推荐
luoganttcc5 分钟前
Ubuntu24 上安装搜狗输入法
linux·运维·服务器
恃宠而骄的佩奇19 分钟前
i春秋-登陆(sql盲注爆字段,.git缓存利用)
web安全·网络安全·蓝桥杯
工业通讯探索者21 分钟前
信捷PLC转以太网连接电脑方法
linux·服务器·网络
小吉在努力敲代码中22 分钟前
c++实现B树(下)
开发语言·数据结构·c++·b树·算法
嚯——哈哈23 分钟前
DDoS高防服务器:保障业务安全和稳定的抗攻击利器
服务器·安全·ddos
活老鬼28 分钟前
Ceph分布式存储
linux·运维·服务器·分布式·ceph
一只小松许️31 分钟前
现代C++HTTP框架cinatra
开发语言·c++·http
ac-er888837 分钟前
ThinkPHP 模型如何更新数据
数据库·oracle·php
不爱学英文的码字机器38 分钟前
[C++] 智能指针
开发语言·c++·算法
♡喜欢做梦38 分钟前
【数据结构】栈和队列详解!!!--Java
java·开发语言·数据结构·链表