php反序列化
序列化初识
序列化是将对象或者数组转化为可储存/传输的字符串。在php中使用serialize()来将对象或者数组进行序列化,并返回一个包含字节流的字符串来表示。进行序列化的时候需要注意的是:
1 | 1.类名不区分大小写 |
基础参考b站橙子科技。
PHP原生类
当我们不知道flag所在的位置,没有pop链的思路和可利用反序列化的函数的时候,一般就是需要用原生类了。例如:
1 | echo new $_POST['a']($_POST['b']); |
类似于这样的,我们可以使用原生类进行遍历读取。详情可参考php原生类
Directorylterator类
DirectoryIterator类会创建一个指定目录的迭代器。当执行到echo函数时,会触发DirectoryIterator类中的 __toString() 方法,输出指定目录里面经过排序之后的第一个文件名。
利用Globlterator类测文件路径
GlobIterator类也可以遍历一个文件目录,行为类似于 glob()函数,可以通过模式匹配来寻找文件路径。
确定文件目录后,用SplFileObject类进行文件读取
用new创建后形参为flag或者伪协议。
魔术方法
魔术方法在特定条件下自动调用相关方法,最终导致触发代码。是我们pop链利用的关键。
__construct()
构造函数,在实例化一个对象的时候,首先会去自动执行的一个方法。触发条件(以下例子对象中默认存在该魔法方法):
1 | $a = new CTF(); |
__destruct()
析构函数,在对象的所以引用被删除或者当对象被显示销毁时执行的魔术方法。触发条件:
1 | unserialize($a); |
__sleep()
用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。触发条件:
1 | echo serialize($a); //序列化之前执行 |
__wakeup()
预先准备对象资源,返回void,常用于反序列化操作中重新建立数据库连接或执行其他初始化操作。触发条件:
1 | unserialize($a); //反序列化之前执行 |
当属性个数的值大于真实属性个数时,会跳过该方法的执行。
__toString()
把对象当成字符串调用。触发条件:
1 | $a = new CTF(); |
__invoke()
把对象当成函数调用。触发条件:
1 | $a = new CTF(); |
__call()
调用一个不存在的方法。触发条件:
1 | $a = new CTF(); |
__get()
调用的成员属性不存在。触发条件:
1 | $a = new CTF(); |
__set()
给不存在的成员属性赋值。触发条件:
1 | $a = new CTF(); |
__isset()
对不可访问属性使用isset()或者empty()时,__isset()会被调用。触发条件:
1 | $a = new CTF(); |
总结
直接放图,自己看。ヾ(❀╹◡╹)ノ゙❀~
然后根据方法构造pop链即可,方法:倒推法
字符串逃逸
反序列化以:}
结束,后面的字符串不影响正常的反序列化,因此,当数据先经过一次serialize再经过unserialize的时候,序列化的字符串变多或者变少有可能导致反序列化属性逃逸。这种漏洞往往出在字符替换函数身上。例如:
1 | class A |
由此可见,aaa缺少了,会导致后面的正常语句被吞掉,从而导致序列化错误,此时$a的序列定位到了s:的中间,这属于减少,增多也是同理,这一部分要结合题目来理解。(先放着doge)。