Exception,Error 类绕过md5、sha1—— [极客大挑战 2020]greatphp
1 |
|
看到两个强比较,以为是强碰撞,但是看到后面有过滤,还需要执行命令,不对,去原生类里面找。
PHP原生类在安全方面的利用总结-安全KER - 安全资讯平台
Error 和 Exception 因为有 tostring 魔术方法,将他们反序列化后只显 message 不显示错误代码,所以在同一行反序列化,md5 和 sha1 就可以绕过。
Error 类是所有 PHP 内部错误类的基类,
源码含有以下两行:
1 | Error implements Throwable { |
message 是错误消息,code 是错误代码。
1 | public __toString ( ) : string |
Exception 是所有异常的基类,关键部分同上。
当我们 new 了 error 类,并 echo 了这个对象,触发类的 tostring 方法:
1 |
|
输出如下:
1 | Error: payload in /usercode/file.php:2 |
会打印 message,file 和Stack trace,并不会打印 code。也就是说只要在同一个文件里 message 相同,那么打印出来的字符串就会完全相同,自然而然 md5 值就相同。
回到题目,因为 md5($a)=md5(string($a)),可以触发类的 tosring 方法,所以我们可以让 code 不同,其他部分相同,来绕过这里的本身不同但是 md5 和 sha1 相同。
了解了以上知识点,我们会写出以下脚本:
1 | class SYCLOVER |
但是拿到输出结果,会发现并没有回显,因为 tostring 的结果是包含行号的,这里我们需要把两个赋值属性放在同一行。
由于我们需要保证两个属性的 message 始终一致,还需要对 message 中的命令不断进行修改,所以较好的办法是提前赋值变量。
1 | class SYCLOVER |
关于 payload 中$a = '?><?= include $_GET[_]; ?>';
的原因,在看了 wp 和追问了 ai 后,我的解释是:
由于题目中的正则表达式过滤了()
括号,而 PHP 中的函数调用需要括号,在不能写一句话木马之后,很自然的就想起 include。
这里我将$a 换成 echo 123;
无回显,百思不得其解,其实一看就明白了。eval 里的是这样一个字符串:
1 | Error: echo 123; in /usercode/file.php:2 |
eval 里面必须是合法的 php 代码,这样的显然是不合法的,只会报错,而题目里已经设置不显示报错信息了。
因此我们要在字符串里面塞入一个自成一体的 php 脚本。这样 eval 里面就是:
1 | Error: include $_GET[_]; in /usercode/file.php:2 |
这样我们就可以用 include 来召唤 flag 了。
此处?>
是用来闭合的,经测试不写这个会报错unexpected ‘<’.S