php序列化
- 解释:
- 序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。
- PHP中的序列化和反序列化分别通过函数serialize()和unserialize()即可实现。
- 序列化代表含义
-
php反序列化
- 解释:
- 就是把被序列化的字符串还原为对象,然后在接下来的代码中继续使用。
- 原理:
- 未对用户输入的序列化字符串进行检测,导致攻击者可以控制反序列化过程,从而导致代码执行,SQL注入,目录遍历等不可控后果。
- 序列化和反序列化本身没有问题,但是如果反序列化的内容是用户可以控制的,且后台不正当的使用了PHP中的魔法函数,就会导致安全问题
- 无类反序列化
- serialize() //将一个对象转换为一个字符串(序列化)
- unserialize() //将字符串还原成一个对象在反序列化的过程中自动触发了某些魔术方法。当进行反序列化的时候有可能触发对象中的一些魔术方法。(反序列化)
- 有类反序列化
- 魔术方法是一种特殊的方法,当对对象执行某些操作时会覆盖 PHP 的默认操作。
- 触发:unserialize函数的变量可控,文件中存在可利用的类,php常见的魔术方法:
-
知识补充
- == (允许类型转换)
- == 检查—>值相等 (值相等)
- ===检查—>值和类型相等(类型和值都要相等)
- js在比较的时候如果是 == 会先做类型转换,再判断值得大小,如果是===类型和值必须都相等。
案例演示
- 案例1:PHP反序列化热身题-无类问题-本地
- 案例2:CTF反序列化小真题-无类执行-实例
- 案例3:CTF反序列化练习题-有类魔术方法触发-本地
- 案例4:网鼎杯2020青龙大真题-有类魔术方法触发-实例
案例1:PHP反序列化热身题-无类问题-本地
- 案例演示1:认识序列化
- PHP在线执行:http://www.dooccn.com/php/
-
- 案例演示2:本地实例
- 1.源码:test.php
-
- 2.先将" xiaodi " 序列化
-
- 3.获取到 s:6:"xiaodi" ,将获取到的值输入到后面的get请求
-
- 4.成功得到falg值
- 1.源码:test.php
案例2:CTF反序列化小真题-无类执行-实例
- Bugku CTF题目:点login咋没反应 - Bugku CTF
- 1.题目如下,提示hint
-
- 2.打开场景后,是个登录框,但是登录框点击毫无反应
-
- 3.这个登录框没啥用,然后查看源代码,发现有一个 admin.css的点击链接
-
- 4.点进去,查看到
-
- 5.于是我们想到这个可能是个get请求,于是访问这个链接
-
- 6.查看到源码后,我们发现将"ctf.bugku.com"序列化后,利用cookie传即可flag
-
案例3:CTF反序列化练习题-有类魔术方法触发-本地
- 测试代码
-
- 在线执行结果
-
- 执行结果说明
- 创建对象时,会默认调用__construct()方法 < $a = new ABC >,
- 反序列化时,会默认调用__wakeup()函数 < $a_ser = serialize ($a ) >,
- 对象被销毁时,会默认调用__destruct()函数< 默认结束时候会自动销毁 >
案例4:网鼎杯2020青龙大真题-有类魔术方法触发-实例
- 案例:2020-网鼎杯-青龙组-Web-AreUSerialz
- 地址:https://www.ctfhub.com/#/challenge,题目如下
-
- 1.打开题目,进入后,直接出现网页代码
-
- 2.首先由ctf命名及代码函数unserialize判断本题考察反序列化知识点
- 第一:获取flag存储flag.php
- 第二:两个魔术方法__destruct __construct
- 第三:传输str参数数据后触发destruct,存在is_valid过滤
-
- 第四:__destruct中会调用process,其中op=1写入及op=2读取
-
- 第五:涉及对象FileHandler,变量op及filename,content,进行构造输出首先由ctf命名及代码函数unserialize判断本题考察反序列化知识点
- 3.涉及:反序列化魔术方法调用,弱类型绕过,ascii绕过
- 弱类型绕过
- 使用该类对flag进行读取,这里面能利用的只有__destruct函数(析构函数)。
- __destruct函数中
- if(
- this−>op==="2")代码,对op进行了===判断(强类型)并且op值为字符串2时会赋值为1,process函数中if(this−>op==="2")代码,
- 对op进行了===判断(强类型)并且op值为字符串2时会赋值为1,process函数中if(
- this->op == "2")代码,使用==判断(弱类型)(op值为2的情况下才能读取内容),
- 因此这里存在弱类型比较,可以使用数字2或字符串'空格2'绕过判断。
- ascii绕过
- is_valid函数还对序列化字符串进行了校验。
- 因为PHP序列化的时候,若成员被private和protected修饰,会引入不可见字符\x00,这些字符对应的ascii码为0,这是个ASCII不在32到125之间的字符,经过is_valid函数以后会返回false,导致无法执行到反序列函数。
经过测试,在PHP7.2+的环境中,使用public修饰成员并序列化,反序列化后成员也会被public覆盖修饰。因此可以改成public来绕过is_valid函数校验。
- 代码:
-
- 弱类型绕过
- 4.将上面的代码运行得到序列化的值
-
- 5.将得到的值写入到链接的后面
-
相关链接