PHP反序列化漏洞学习-绕过_wakeup()函数
题目代码
代码如下,要求利用php反序列化漏洞去读取flag.php
文件中的内容
|
|
php反序列化简单介绍
根据php官方文档的介绍,php反序列化用于在开发中存储或传递php的值,同时又不丢失其类型和结构,php当中和反序列化有关的两个重要函数,分别为serialize
和unserialize
,这两个函数可以处理除resource
(资源类型)之外的任何php数据类型,对php值进行序列化和反序列化操作
php反序列化漏洞
php反序列化本身其实是没有危害的,但是当对一个php对象进行序列化或者反序列化操作时,由于对象里面的一些魔术方法会在一些情况下被触发,刚好这些魔术方法里面调用了一些危害的函数并且函数的参数是我们可以控制的,就会产生预料之外的危害,有关php对象的一些常见魔术方法如下:
|
|
具体看下面的例子
|
|
该程序的输出结果如下
需要注意的是private
、protected
、public
三个对象的属性经过序列化后的字符串格式是有区别的,这在构造POC的时候十分关键,通过抓包看到的序列化数据实际如下
|
|
其中常见的php数据类型对应的字母标识如下
a - array
b - boolean
d - double
i - integer
o - common object
r - reference
s - non-escaped binary string
S - escaped binary string
C - custom object
O - class
N - null
R - pointer reference
U - unicode string
接着看上面的那道题,代码很明显存在php反序列化漏洞,题目要求利用php反序列化漏洞去读取与index.php
同一目录下的flag.php
,代码流程很简单,就是将传入的$_GET['file']
参数经过base64解码后再进行反序列化,如果处理结果是该对象的一个序列化字符串,在进行反序列化的时候就会触发该对象的__wakeup
方法,并在代码结束时触发该对象的__destruct
方法,此时对象当中的$file
变量被传入show_source
,如果$file
是一个文件名,就会显示出对应文件的源代码,$file
变量又刚好是可控的,很容易构造出读取flag.php
的payload
构造序列化字符串,设置对象的protected
属性$file的值为flag.php
|
|
再经过base64编码
Tzo1OiJTb0Z1biI6MTp7czo3OiIAKgBmaWxlIjtzOjg6ImZsYWcucGhwIjt9
将得到的base64字符串传入$_GET['file']
,但是看到并没有显示出flag.php
的源码,这里依旧显示的是index.php
的源代码,原因就是传入的序列化字符串在反序列化的时候会触发对象的__wakeup
魔术方法,而在__wakeup
魔术方法中,将传入的$file
属性值设置成了index.php
,之后触发__destruct
方法时,$file
的值就变为了index.php
,所以这里需要绕过__wakeup
函数,这里需要利用__wakeup
函数的一个漏洞
wakeup()函数漏洞
当序列化字符串当中属性个数值大于实际的属性个数时,就会导致反序列化异常,从而跳过__wakeup
函数,具体的底层原理可以看下面的解释
那么就可以构造序列化字符串
|
|
将对象属性的个数设置为2,而实际的属性个数为1,使其反序列化产生异常,从而绕过__wakeup
函数,将序列化字符串进行base64编码后
Tzo1OiJTb0Z1biI6Mjp7Uzo3OiJcMDAqXDAwZmlsZSI7czo4OiJmbGFnLnBocCI7fQ==
成功读取到了flag.php
的源码