简介
一些魔法函数与php反序列化漏洞
tips
反序列化和类的方法无关,不能把类的方法序列化
将php.exe所在目录放到环境变量中,就可以在终端里通过php.exe ./命令来执行php代码
魔术方法
__construct()
在实例化一个对象时会自动调用,可以用来初始化非public属性的值
php的构造方法不能重载
序列化与反序列化时,不会自动调用构造方法
__sleep() __wakeup()
会在序列化和反序列化时自动执行
serialize函数会检查类中是否存在魔术方法__sleep(),如果存在,该方法会被先调用,然后再执行反序列化,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组,如果该方法未返回任何内容,则NULL被序列化,比如
return ['username','password'];
如果被反序列化的变量是是一个对象,在成功重新构造对象之后,php会自动试图去调用wakeup()成员函数
__destruct()
销毁类的对象时自动执行
在程序最后一段写杀死相应的php进程的代码可以绕过析构方法,如果是在浏览器访问
system('taskkill /fi "imagename eq php-cgi.exe" /f');
__call() __callstatic()
对象执行类不存在的方法时,就会调用call方法
直接执行类不存在的静态方法时,会自动调用get方法
__get __set __isset __unset
对不可访问或不存在的属性访问或引用时,会自动调用__get方法
对不可访问或不存在的属性赋值时,会自动调用__set方法
将类不可访问的属性作为isset函数的参数时,会自动调用__isset
将类不可访问的属性作为unset函数的参数时,会自动调用__unset
__tostring()
类的实例和字符串进行拼接或作为字符串使用时,会自动调用__tostring()方法
__invoke()
将类的实例被作为函数名字执行的时候,会调用invoke方法
__set_state()
执行var_export()时自动调用
__debuginfo()
执行var_dump时自动调用
__clone()
当使用clone关键字,clone一个对象时会自动调用
反序列化漏洞的条件
有反序列化提交的入口
被反序列化的类的魔术方法有可能被利用
绕过__wakeup方法
条件:
php5至php 5. 6.25之间的版本可以绕过
php7至php7 .0.10之间的版本可以绕过
绕过方法
让反序列化字符串中表示属性数量的值大于大括号内实际属性的数量时,wakeup方法就不会被调用
应用
常见的时wakeup里面会给一个属性赋值,而destruct里面可以由我们给属性赋值,所以我们需要绕过wakeup方法,让我们自己给这个属性传恶意代码
本地建一个php文件,把题目给的类的代码复制过来,然后进行实例化,给可以控制的属性传一个后门,再对这个对象序列化并urlencode
绕过O:/d的限制
有时候对我们的参数有过滤,不让输入 O:数字 的形式,试图防止反序列化某个对象
我们只需要把O:数字改为O:+数字,就可以绕过
妙用&绕过相等
原理
使两个变量指向同一块内存地址
应用
比如题目把/flag的内容赋值给了secret,然后后面要求属性password的值等于secret
这个时候,我们依然按照上面说的方法写一个脚本,然后写一个构造函数
function __construct(){
$this->password = &$this->secret;
}
这样就能保证无论secret怎么改变,password都与secret的值相等
16进制绕过
反序列化后的字符串不能出现某个单词时,可以使用大写S绕过
即把s换成S,因为S支持ascll码
比如禁止使用name,我们就可以用n\97me代替
O:8:"backdoor":1:{s:4:"name";s:10:"phpinfo();";}
O:8:"backdoor":1:{S:4:"n\97me";s:10:"phpinfo();";}
php反序列化字符逃逸
- 可以控制某个类中的属性值
- 间接控制了某个类的反序列化字符串
- 由于存在无脑过滤,字符增减,造成 描述中字符串的长度 和实际的不一致
- 从而能够逃逸出若干个字符,实现字符可控,从而闭合前面的双引号
- 实现反序列化字符串的完全可控