[极客大挑战2019]PHP
[极客大挑战2019]PHP
ZhEYuAN提示自己有备份网站,直接dirsearch扫,有个flag.php
这个flag.php没内容,一看就是假的.
可以看到这个网站的文件
打开flag.php,内容如下
一眼假,我们再看index.php和class.php
进行一个代码审计!
index文件
1 | include 'class.php'; |
会将 class.php
文件的内容包含进来,并在当前文件中执行。,相当于两个文件中的代码属于一体的.
class文件
Name
类,包含私有属性 $username
和 $password
,以及三个方法:
__construct()
: 构造函数__wakeup()
: 反序列化时调用__destruct()
: 析构函数
明显是反序列化的问题,解决此问题需要满足几个条件
- 有unserialize()
- 反序列化函数参数可控
- 存在可利用的魔术方法,尤其注意wakeup.destruct
- 一层一层地研究该类在魔法方法中使用的属性和属性调用的方法,看看是否有可控的属性能实现在当前调用的过程中触发的
- 找到我们要控制的属性了以后我们就将要用到的代码部分复制下来,然后构造序列化,发起攻击
解题思路
首先找可利用的魔术方法,看到__destruct(),在对象销毁时自动调用.并且这个魔术方法中出现了关键判断语句,通过判断username和password来给出flag.
但是在调用destruct之前发现了__wakeup函数,执行unserialize()时,先会调用这个函数,而它会把我们的username更改.自然的,尝试绕过wakeup
网上可以搜到很多绕过wakeup的方法,我们这里尝试PHP 5.6.30 之前的版本中存在一个漏洞,通过修改序列化字符串中的对象属性数量来绕过 __wakeup。
构造payload
①正常构造,选取我们需要的类和属性,并用var_dump输出
1 | <?php |
错误示例:更改默认值没意义,因为构造函数会把默认值覆盖
1 | class Name{ |
②更改属性个数来绕过wakeup
1 | O:4:"Name":3:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;} |
③注意变量的声明是public private protect,这三种声明序列化会产生不同的字符串
注意到声明是private,所以应该更改参数,私有字段的字段名在序列化时,类名和字段名前面都会加上\0的前缀。字符串长度也包括所加前缀的长度
1 | O:4:"Name":3:{s:14:"%00Name%00username";s:5:"admin";s:14:"%00Name%00password";i:100;} |
得到flag
参考博客