PHP反序列化漏洞
·序列化与反序列化
类型 |
过程 |
序列化 |
对象—> 字符串 |
反序列化 |
字符串—>对象 |
字符串包括,属性名,属性值,属性类型和该对象对应的类名。
序列化函数serialize(),反序列化函数unserialize()。(O代表对象;A代表数组)
·_sleep()
serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,__sleep()方法会先被调用,然后才执行序列化操作
序列化的结果只有_sleep()中的两个属性
·_wakeup()
unserialize()会检查类中是否存在一个__wakeup魔术方法。如果存在则会先调用__wakeup()方法,再进行序列化
当序列化字符串中表示对象属性个数的数字值大于真实类中属性的个数时就会跳过__wakeup的执行,
·访问控制修饰符
根据访问控制修饰符的不同序列化后的属性长度和属性值会有所不同
public(公有)
protected(受保护) //被序列化的时候属性值会变成 %00*%00属性名
private(私有的) //被序列化的时候属性值会变成%00类名%00属性名
注意protected属性和private属性的长度,%00为空白符,空字符也有长度,一个空字符长度为 1
·反序列化POP链
pop又称之为面向属性编程(Property-Oriented Programing),常用于上层语言构造特定调用链的方法。
构造思想
既然是连续调用链就会有头有尾,头当然是入口,也就是能传入参数的地方,一般都是GET或POST传参再unserialzie,尾巴毋庸置疑是可以达到攻击或获取数据的口子,比如eval、include等可以执行或者包含读取甚至是直接拿flag,如果有这些那肯定是尾巴了。有了头有又了尾,怎么通过这些连起来的成为一个问题,这时想到了序列化与反序列化最重要的一个点还没用上==>魔术方法。
__construct() 当对象创建(new)时会自动调用。但在 unserialize() 时是不会自动调用的。
__destruct() 当一个对象销毁(反序列化)时被调用
__toString() 当一个对象被当作一个字符串使用时被调用
__sleep() 在对象在被序列化之前立即运行
__wakeup() 将在序列化之后立即被调用
PHP中Session反序列化
在php.ini中存在三项配置项:
session.save_path=”” —设置session的存储路径
session.save_handler=”” –设定用户自定义session存储函数,如果想使用PHP内置会话存储机制之外的可以使用本函数(数据库等方式)
session.auto_start boolen —指定会话模块是否在请求开始时启动一个会话,默认为0不启动
session.serialize_handler string –定义用来序列化/反序列化的处理器名字。默认使用php (php<5.5.4)
以上的选项就是与PHP中的Session 存储 和 序列化存储 有关的选项。
在使用xampp组件安装中,上述的配置项的设置如下:
session.save_path=”D:\xampp\tmp” 表明所有的session文件都是存储在xampp/tmp下
session.save_handler=files 表明session是以文件的方式来进行存储的
session.auto_start=0 表明默认不启动session
session.serialize_handler=php 表明session的默认序列化引擎使用的是php序列话引擎
在上述的配置中,session.serialize_handler是用来设置session的序列化引擎的,除了默认的PHP引擎之外,还存在其他引擎,不同的引擎所对应的session的存储方式不相同。
引擎 session存储方式
php(php<5.5.4) 存储方式是,键名+竖线|+经过serialize()函数序列处理的值(只序列化值)
php_serialize(php>5.5.4) 存储方式是,经过serialize()函数序列化处理的键和值(将session中的key和value都会进行序列化)
php_binary 存储方式是,键名的长度对应的ASCII字符+键名+经过serialize()函数序列化处理的值
在PHP (php<5.5.4) 中默认使用的是PHP引擎,如果要修改为其他的引擎,只需要添加代码ini_set(‘session.serialize_handler’, ‘需要设置的引擎名‘);进行设置。
上文参考链接:
https://blog.csdn.net/qq_51295677/article/details/123425199
https://blog.csdn.net/qq_45521281/article/details/105891381
WP:
1)攻防世界unserialize3
审计代码,只需要绕过wakeup魔术方法,传递code的值
在php编译器中进行如图编译,对类xctf序列化(序列化的结果中,要把xctf后的1改为2,达到绕过wakeup()效果, 当序列化字符串中表示对象属性个数的数字值大于真实类中属性的个数时就会跳过__wakeup的执行,)
将序列化的结果赋值给code,用get方式传递,得到flag
2) 攻防世界Web_php_unserialize
代码审计
在php在线工具中编译运行
传参
3)BUUCTFWarmUp1
查看源码,在url后加source.php
代码审计,应该传?file=source.php%253../(未知个数个../)flag
url后加/hint.php
多次添加../后传?file=source.php%253F../../../../../ffffllllaaaagggg得到flag