PHP反序列化入门手把手详解
前言:文章内容大致可分为原理详解-漏洞练习-
防御方法。文章内容偏向于刚接触PHP反序列化的师傅,是一篇对PHP反序列化入门的手把手教学文章。文章特色在于对PHP反序列化原理的详细分析以及一系列由简入深的PHP反序列化习题练习和分析讲解。文章写作初衷是想借助REEBUF平台与入门安全的师傅分享自己入门期间的学习成果。最后特别感谢何君师傅的教导。
问题咨询和282G网络安全资料的领取点击此处即可
序列化与反序列化
名词解释
序列化:将变量转换为可保存或传输的字符串的过程;
反序列化:在适当的时候把这个字符串再转化成原来的变量使用。
优点:这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。
例子1
例子:将一大段对象序列化压缩成字符串.然后根据要求反序列化重新构造对象.(②是序列化的格式,下文详解)
例子-对象压缩成字符串
例子-字符串还原成对象
例子2
再例如:网购家具,店家把家具拆分打包邮寄过来的过程就是序列化,反序列化就是买家根据说明书自定义将商品还原过程。
例子2-桌子拆分
例子2-桌子组装还原
字符解释
字符详解
O:6:"Person":3:{s:4:"name";s:3:"tom"; s:11:"Personage"; i:18; s:6:"*sex"; s:3:"boy";}
O : 自定义对象 object
6 : 类名的长度
:3 : 3个成员属性
S:4 : 你的成员属性名 长度为4 ,并且是一个字符串 string
S:3 : 刚刚那个成员属性对应的值 是string类型,并且长度是3位
s:11:"Personage" : 因为该属性是私有属性,所以需要在属性名前加上类名,方便我们进行反序列化的时候的识别.
i:18 : 18是age的属性值 , i是代表 integer类型
s:6:"*sex"; sex这个属性是一个受保护的属性,特征就是 * 号
s:3:"boy : 代表 string类型,属性值长度为3位 boy对应是 sex的属性值
字符解释
private和 protected详解
PHP 序列化的时候 private和 protected 变量会引入不可见字符%00,%00类名%00属性名 为private,%00*%00属性名 为protected,注意这两个 %00就是 ascii 码为0 的字符。这个字符显示和输出可能看不到,甚至导致截断,但是url编码后就可以看得清楚.我们可以将序列化的字符用urlencode编码之后,打印出来查看.
字符解释
PHP常见魔术方法
__construct
__construct:构造函数,会在每次创建新对象时先调用此方法
__construct
__destruct
__destruct:析构函数,会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行
__destruct
__toString
__toString:返回一个类被当做字符串时要输出的内容,此方法必须返回字符串并且不能在此方法中抛出异常,否则会产生致命错误。
__tostring
__invoke
__invoke:PHP5.3起,当尝试以函数的方式调用对象时,会调用此方法。
__invoke
__call
__call : 在对象中调用一个不可访问方法时调用。
__call
__sleep
__sleep:返回一个包含对象中所有应被序列化的变量名称的数组。serialize函数在序列化类时首先会检查类中是否存在__sleep方法。如果存在,会先调用此方法然后再执行序列化操作。并且只对__sleep返回的数组中的属性进行序列化。如果
__sleep不返回任何内容,则null会被序列化,并产生E_NOTICE级别的错误。__sleep不能返回父类的私有成员,否则会产生E_NOTICE级别的错误。对于一些很大但不需要保存全部数据的对象此方法很有用。
即序列化serialize时会调用__sleep.
__sleep
__wakeup
__wakeup:与__sleep相反,是在unserialize函数反序列化时首先会检查类中是否存在__wakeup方法,如果存在会先调用次方法然后再执行反序列化操作。用于在反序列化之前准备一些对象需要的资源,或其他初始化操作。
即反序列化unserialize时会自动调用__wakeup
__wakeup
PHP反序列化练习
一.初步认识
任务:通过传参让页面出现phpinfo界面
1.构建环境
习题代码
<?php
class one
{
var $b = 'phpinfo();';
function action()
{
eval($this->b);
}
}
$a = unserialize($_GET[1]);
$a->action();
2,分析
payload O:3:"one":1:{s:1:"b";s:10:"phpinfo();";}
①新建新文件用于存放预构造的代码
②实例化一个对象,将其序列化的内容打印出来
③得到其序列化