[BUUOJ记录] [HCTF 2018]WarmUp

BUUOJ Web的第一道题,其实是很有质量的一道题,但是不知道为什么成了Solved最多的题目,也被师傅们笑称是“劝退题”,这道题的原型应该是来自于phpMyadmin的一个文件包含漏洞(CVE-2018-12613)

本文旨在分析这道题牵扯到的知识点以及解体思路,想直接看WriteUp拿Flag的师傅可以看看其他文章

解题过程

解题思路

进入题目查看源代码发现提示:

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

代码分为两部分来看,第一部分是定义了emmm类的一个checkFile函数,用来检查传入的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‘])    //用$_REQUEST来接收file参数,如果file参数的值不为空、为字符串、可以通过emmm类checkFile函数检测,则包含该文件
    ) {
        include $_REQUEST[‘file‘];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }

在emmm类的checkFile函数中我们可以看到白名单中有两个文件:

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

包含一下hint.php文件来试试 /source.php?file=hint.php :

提示我们Flag在ffffllllaaaagggg中,那么我们解题的关键就是如何包含这个在whitelist外的文件

从第二部分代码我们可以看出,重点是如何让ffffllllaaaagggg通过checkFile的检查,因此我们就需要从emmm类的checkFile函数入手

前置知识点

我们在读这个函数的代码前需要提前了解几个checkFile函数中出现的函数:

1. in_array() 函数搜索数组中是否存在指定的值

更多信息参考:https://www.w3school.com.cn/php/func_array_in_array.asp

2. mb_substr() 函数返回字符串的一部分,之前我们学过 substr() 函数,它只针对英文字符,如果要分割的中文文字则需要使用 mb_substr()

更多信息参考:https://www.runoob.com/php/func-string-mb_substr.html

3. mb_strpos() 查找字符串在另一个字符串中首次出现的位置

更多信息参考:https://www.php.net/manual/zh/function.mb-strpos.php

核心代码分析

在了解了上面的几个小点之后我们返回来看核心代码:

    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {  //page必须不为空或为字符串
                echo "you can‘t see it";
                return false;
            }

            if (in_array($page, $whitelist)) {  //in_array()检测page是否在whitelist中
                return true;
            }

            $_page = mb_substr(  //如果page含有?,则获取page第一个?前的值并赋给_page变量
                $page,
                0,
                mb_strpos($page . ‘?‘, ‘?‘)
            );
            if (in_array($_page, $whitelist)) {  //检测_page是否在whitelist中
                return true;
            }

            $_page = urldecode($page);  //给_page二次赋值,使其等于URL解码之后的page
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . ‘?‘, ‘?‘)  //如果_page有?,则截取_page(URL解码后的page)两个?中间的值
            );
            if (in_array($_page, $whitelist)) {  //检测_page是否在whitelist中
                return true;
            }
            echo "you can‘t see it";
            return false;
        }
    }

逻辑可能看着有点乱,所以我们梳理一下逻辑,这里引用王叹之师傅的分析:

可以看到函数代码中有四个if语句:

第一个if语句 对变量进行检验,要求$page为字符串,否则返回false  //因为返回False所以这里无用
第二个if语句 判断$page是否存在于$whitelist数组中,存在则返回true
第三个if语句 判断截取后的$page是否存在于$whitelist数组中,截取$page中‘?‘前部分,存在则返回true
第四个if语句 判断url解码并截取后的$page是否存在于$whitelist中,存在则返回true
若以上四个if语句均未返回值,则返回false

有三个if语句可以返回true,第二个语句直接判断$page,不可用

第三个语句截取‘?‘前部分,由于?被后部分被解析为get方式提交的参数,也不可利用

第四个if语句中,先进行url解码再截取,因此我们可以将?经过两次url编码,在服务器端提取参数时解码一次,checkFile函数中解码一次,仍会解码为‘?‘,仍可通过第四个if语句校验。

只要这四个if语句有一个为true即可包含file,关键点在_page 经过截断后返回true.

所以我们的突破点就在于第四个if语句中,只要满足他的条件,我们就可以包含文件:

$_page = urldecode($page);
$_page = mb_substr(
  $_page,
  0,
  mb_strpos($_page . ‘?‘, ‘?‘)
);if (in_array($_page, $whitelist)) {
  return true;
}

这里URL解码了一次$page值,这里需要注意的是,PHP中$_GET、$_POST、$_REQUEST这类函数在提取参数值时会URL解码一次

而这里在代码中又一次URL解码了一次,共计解码了两次,所以我们也需要对传入的值进行两次URL编码

其次我们的突破点就在于这段代码只会截取?之前的字符串拿去和whitelist比对,因此只要确保?前的值是source.php或hint.php即可返回true

等同于 /source.php?file=source.php%253f123456 便可以使用include()函数包含 source.php?123456 这个文件(%253f是?URL编码两次后的值)

所以可以构造Payload:

/index.php?file=source.php?/../../../../ffffllllaaaagggg

需要注意的是,这里之所以可以包含到ffffllllaaaagggg是因为PHP将 source.php?/ 视作了一个文件夹,然后 ../ 的用途是返回上级目录

ffffllllaaaagggg位于根目录下,一般Web服务的文件夹在/var/www/html目录中,再加上source.php?/这个“文件夹”,所以我们总共需要../四次来返回到根目录

(如果比赛中不知道flag具体位置的话可以一层一层来试)

原文地址:https://www.cnblogs.com/yesec/p/12635274.html

时间: 2024-11-08 06:29:37

[BUUOJ记录] [HCTF 2018]WarmUp的相关文章

[HCTF 2018]WarmUp

CTF-BUUCTF-[HCTF 2018]WarmUp题目: 知识点:根据提示,毫无疑问,PHP代码审计解题一.访问链接 /index.php?file=hint.php 是一个文件包含,source.php 是 index.php 的源代码.得到提示,flag 在 ffffllllaaaagggg 里二.代码审计: <?php    highlight_file(__FILE__);    class emmm    {        public static function check

[BUUOJ记录] [GYCTF]EasyThinking

主要考察ThinkPHP6.0的一个任意文件写入的CVE以及突破disable_function的方法. ThinkPHP6.0.0任意文件操作漏洞 理论分析 进入题目是一个简单的操作页面,dirmap扫出来www.zip源码泄露: 下载下来看一下源码目录: 很明显的ThinkPHP框架,让网页随便报个错看看版本: 发现版本为6.0.0,一般线上CTF题目中出现ThinkPHP这种框架时,多是考察近期该框架爆出的通用漏洞,像是XCTF外卡赛“高校战‘疫’”的PHP-UAF便是考察了一个PHP近期

Yandex Algorithm 2018 Warmup

A. Time Throught The Glass 题意:对于一个时钟,分针和秒针一定会在整数位置.下面告诉你这个时钟关于中垂线对称后的读数,让你输出它的真实读数. 观察:如果镜像读数是h,m的话,真实读数就是(12-h)%12, (60-m)%60. code: 1 /* 2 by skydog 3 */ 4 #include <iostream> 5 #include <cstdio> 6 #include <vector> 7 #include <util

[BUUOJ记录] [强网杯 2019]随便注(三种方法)

本题主要考察堆叠注入,算是比较经典的一道题,在i春秋GYCTF中也出现了本题的升级版 猜测这里的MySQL语句结构应该是: select * from words where id='$inject'; 构造Payload:用单引号+分号闭合前面的语句,插入SQL语句,再用注释符注释掉后面的语句即可 先列出所有数据库: 1';show databases;# 得到: array(1) { [0]=> string(11) "ctftraining" } array(1) { [0

[BUUOJ记录] [ACTF2020 新生赛]Upload

//简单的上传题,考察绕过前端Js验证,phtml拓展名的应用 打开题目点亮小灯泡后可以看到一个上传点 传一个php测试一下: 发现有文件拓展名检查,F12发现是Js前端验证: 审查元素直接删掉,继续上传PHP文件测试: 发现还是被过滤了,应该是后端还有一次验证,换成phtml文件测试,phtml文件代码如下: GIF89a //习惯在文件前加上GIF89a来绕过PHP getimagesize的检查,这道题中有无皆可 <script language='php'>@eval($_POST['

[BUUOJ记录] [CISCN 2019 初赛]Love Math

主要考察利用已有函数构造危险函数绕过,实现RCE. 进入题目给出源码: <?php error_reporting(0); //听说你很喜欢数学,不知道你是否爱它胜过爱flag if(!isset($_GET['c'])){ show_source(__FILE__); }else{ //例子 c=20-1 $content = $_GET['c']; if (strlen($content) >= 80) { //[NESTCTF 2019]Love Math2这里限制长度为60,用本题的异

软件工程——个人记录(gaopeng)

记录时间 2018.02.12 任务: 1.个人信息页面ui 2.数据库上传读取个人信息 3.整合密码修改到个人信息页面 实现程度: 个人页面UI基本实现: 密码修改: 待完成事项: 1.学号的格式限制,电话格式的正确性判断 2.用户头像的上传管理 3.服务器上传文件的地址问题 原文地址:https://www.cnblogs.com/penkgao/p/8468757.html

Hibernate3中重复引用hbm文件错误信息记录

Hibernate3中重复引用hbm文件错误信息记录. 2018 八月 12 11:17:09,778 ERROR - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'loginManager' defined in ServletContext resource [/WEB-INF/applicationCo

mysql修改数据存放路径(linux)

亲测可以的,记录下来  2018年2月5日 11:03:22 1. /etc/my.cnf [mysqld] 增加datadir = /data/nas 2. /etc/rc.d/init.d/mysql 从 "datadir=/data" 修改为 "datadir=/data/nas" 从 "datadir_set=" 修改为 "datadir_set=1" 3. 移动/data 目录下原来的数据库 到目录 /data/na