首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >CTF笔记-1-PHP序列化与反序列化(__sleep与__wakeup)

CTF笔记-1-PHP序列化与反序列化(__sleep与__wakeup)

作者头像
Baige
发布于 2022-03-22 14:41:35
发布于 2022-03-22 14:41:35
2K0
举报
文章被收录于专栏:世荣的博客世荣的博客

1.前言:总结一下序列化和反序列化的入门知识

__sleep 与 __wakeup 序列化: 将一个对象转化成字符串 反序列化:将一个字符串转换成对象

2.魔术方法:

代码语言:javascript
复制
__construct: 在创建对象时候初始化对象,一般用于对变量赋初值。
__destruct: 和构造函数相反,当对象所在函数调用完毕后执行。
__toString:当对象被当做一个字符串使用时调用。
__sleep:序列化对象之前就调用此方法(其返回需要一个数组)
__wakeup:反序列化恢复对象之前调用该方法
__call:当调用对象中不存在的方法会自动调用该方法。
__get:在调用私有属性的时候会自动执行
__isset():在不可访问的属性上调用isset()或empty()触发
__unset():在不可访问的属性上使用unset()时触发

3.PHP序列化

PHP序列化的函数为:serialize()

代码语言:javascript
复制
<?php
class peak{
    public $name = "lishirong";
    protected $sex = "man";
    private $age = "18";
    }
$a = new peak;
echo serialize($a);
?>
代码语言:javascript
复制
序列化结果:
O:4:"peak":3:{s:4:"name";s:9:"lishirong";s:6:"*sex";s:3:"man";s:9:"peakage";s:2:"18";}
0:表示对象(object)
  4:对象名称长度
     peak:对象名称
           3:表示对象里属性的个数
              s:属性名类型
                4:属性名长度
                   name:属性的名称
                              lishirong:属性值

注:这个属性的值可有可无,没有赋值,那么序列化后就没有该值 这里可能不理解序列化后的sex和age,这个是由访问控制修饰符导致的(访问修饰符的不同,序列化后的属性名的长度和属性名会有所不同。 举个例子:

代码语言:javascript
复制
public(公有)
protected(受保护)
private(私有)
各访问修饰符序列化后的区别:
public:属性被序列化的时候属性名还是原来的属性名,没有任何改变
protected:属性被序列化的时候属性名会变成%00*%00属性名,长度跟随属性名长度而改变
private:属性被序列化的时候属性名会变成%00类名%00属性名,长度跟随属性名长度而改变

注:这里的%00也就是表示空字符,在url中用%00表示,在hex中表示\x00
Tip:%00和\x00也就是我们常说的00截断

4.serialize()函数:

serialize()函数有个规定,在序列化对象时,如果对象存在有__sleep魔术方法,那么,在序列化对象时__sleep魔术方法会优先调用,然后再继续执行序列化操作

代码语言:javascript
复制
<?php
class peak{
    public $name = "1stPeak";
    public $sex = "man";
    public $age = "18";
    public function __sleep(){
        return array('age');
    }
}
$a = new peak;
echo serialize($a);
?>

结果:O:4:"peak":1:{s:3:"age";s:2:"18";}

如上所示:只要序列化时执行了__sleep,就只会序列化__sleep中的属性

5.PHP反序列化

反序列化,顾名思义,就是将序列化后的字符串还原 unserialize()也有和serialize()相对应的魔术方法__wakeup,反序列化时,会优先检查是否存在__wakeup魔术方法,如果存在,就会优先调用__wakeup方法

代码语言:javascript
复制
<?php
class Demo
{
    public $flag = 'flag{aaaaaa}';
    public function __wakeup()
    {
        $this->flag = "bbbbbb";
        echo $this->flag;
    }
}
$a = new Demo();
$b = serialize($a);
echo $b."\n";
echo unserialize($b);
?>

输出:O:4:"Demo":1:{s:4:"flag";s:12:"flag{aaaaaa}";}
bbbbbb

一般做CTF题目时绕过的方法就是:先序列化字符串,然后使序列化后字符串中属性的个数大于真实对象中属性的个数,即可绕过。

6.例题(来源XCTF)

代码语言:javascript
复制
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
}
?code=

我们对其进行序列化:

代码语言:javascript
复制
<?php
class xctf{
public $flag = '111';
public function __wakeup(){
exit('bad requests');
    }
}
$a = new xctf;
echo serialize($a);
?>

结果为:O:4:"xctf":1:{s:4:"flag";s:3:"111";}

将序列化后字符串中属性的个数由1改为2,大于真实属性个数1,即可绕过__wakeup 注:修改s(属性类型)或属性名长度也可绕过执行__wakeup,因为你构造的属性和真实的属性不符; 但修改属性值是不会绕过__wakeup的,所以综述:只有改变属性个数、属性类型、属性名才可以绕过!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021 年 09 月,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 1.前言:总结一下序列化和反序列化的入门知识
  • 2.魔术方法:
  • 3.PHP序列化
  • 4.serialize()函数:
  • 5.PHP反序列化
  • 6.例题(来源XCTF)
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档