一.类与对象
类是定义了一件事的抽象特点,它将数据的形式以及这些数据上的操作封装在一起。
对象是具有类类型的变量,是对类的实例。
比如说:你在打游戏,你和你队友说:“你要选一个英雄。”这里英雄就是一个类,你必须把要选的英雄说出来,具体到哪一个英雄,妲己,亚瑟,捷风,盖伦等等,这些都是对象。这里妲己就是对类的实例化。
类的内部构成:成员变量(属性)+成员函数(方法)+成员常量
用class a,创建一个类a
用function 某某,创建一个方法,例如function_construct。
$a=new b(),把类实例化成一个对象,
权限修饰符:public 公有 ,所有都能够调用
private 私有, 只有自己的方法能调用
protect 受保护的 ,自己和子类能够调用
格式:
二.序列化
序列化是将对象的状态信息(属性)转换为可以存储或传输的形式的过程。
三.反序列化
反序列化是将序列化后的参数还原成实例化的对象。
(1)反序列化后的内容为一个对象
(2)反序列化生成的对象里的值,由反序列化里的值提供;与原有类预定义的值无关。
四.魔术方法
什么是魔术方法?
魔术方法是一个预订好的,在特定情况下自动触发的行为方法。可以举个例子,当你想打电脑游戏的时候,是不是要先打开电脑,就是说在你要打游戏的情况触发了打开电脑这个行为动作。
反序列化漏洞的成因:反序列化过程中,unserialize()接受的值(字符串)可控;通过更改这个值(字符串),得到所需要的代码,即生成的对象的属性值,通过调用方法,触发代码执行。
魔术方法在特定条件下自动调用相关方法,最终导致触发代码。
那么我们就需要知道有那些魔术方法,以及它们的触发时机。
如下图所示:
_construct():构造函数,在实例化一个对象的时候,首先会去自动执行的一个方法。
实例化对象就是你去$a=new a(),
触发时机:实例化对象
功能:提前清理不必要的内容
参数:非必要
_destruct():析构函数,在对象的所有引用被删除或者当对象被显示销毁时执行的魔术方法。
在你实例化一个对象结束后呢会触发destruct函数。$a=new a(),在这之后会触发destruct,而construct是在这时会触发,要分清这两个相对的函数。serialize序列化不会触发destruct,而反序列化后会触发destruct,因为反序列化得到的是对象,用完后会销毁。
_sleep:在序列化的时候会检查当前类里面是否有这个函数,如果有则会先触发这个函数,再来进行序列化。
触发时机:序列化之前
功能:用于清除对象,并返回一个包含对象中所有应该被序列化的变量名称的数组,简单来说就是执行sleep后删除不必要的属性,返回要序列化的成员属性。
参数:成员属性
_wakeup():在反序列化之前会检查是否含有该函数,如果有则会触发该函数,和sleep触发条件相反。
_toString():表达方式错误导致魔术方法触发,把对象当成字符串调用,
例如:
$a=new b();
print_r($a);
echo $a;
a里面就是一个对象,可以用print_r输出对象,不会触发toString,反而echo会把a当作字符串输出,会触发toString.
_invoke():格式表达错误导致魔术方法触发,把对象当成函数调用。
例如:
$a=new b();
echo $a->c;
echo $a()->c;
假设a里面的值是c,当你执行echo $a->c;时会输出a里面的值c;但是在$a后面加上一个()就会把a当成一个函数来调用,就会触发invoke。
魔术方法触发前提:魔术方法所在类或对象被调用。
_call():调用一个不存在的方法是会触发,输出为不存在的方法的名称和参数。
$a=new b();
$a->callxxxx('d');
如果不存在callxxxx方法就会触发call方法。
_callstatic():静态调用或调用成员常量时使用的方法不存在,和call方法的区别就是静态调用,其实静态调用就是把->变为::
如
$a::callxxxx('c')
_get:调用的成员属性不存在 。
五.pop链
在反序列化中,我们能控制的数据就是对象中的属性值(成员变量),所有在PHP反序列化中有一种漏洞利用方法叫“面向属性编程”,即pop.
pop链就是利用魔术方法在里面进行多次跳转然后获取敏感数据的一种payload.
wakeup漏洞:
如果存在wakeup魔术方法,在序列化字符串中表示对象属性个数的值比真实的属性个数值大的时候,就会绕过wakeup魔术方法。