060-WEB攻防-PHP反序列化&POP链构造&魔术方法流程&漏洞触发条件&属性修改
060-WEB攻防-PHP反序列化&POP链构造&魔术方法流程&漏洞触发条件&属性修改
知识点:
1、PHP-反序列化-应用&识别&函数
2、PHP-反序列化-魔术方法&触发规则
3、PHP-反序列化-联合漏洞&POP链构造
在实战情况下,是不需要知道这些具体分析的,都是利用工具去扫一些框架爆出的反序列话漏洞直接利用即可。
学这些具体分析就是为了以后往漏洞挖掘方向发展或者打CTF比赛及面试会被问
1、PHP-DEMO1-序列化和反序列化
为什么会产生序列化?
为了解决开发中数据传输和数据解析的一个情况(类似于要发送一个椅子快递,不可能整个椅子打包发送,这是非常不方便的,所以就要对椅子进行序列化处理,让椅子分成很多部分在一起打包发送,到目的后重新组装,也就是反序列化处理)
什么是反序列化操作? - 类型转换
- PHP & JavaEE & Python(见图)
序列化:对象转换为数组或字符串等格式
序列化(Serialization):
把“复杂的数据结构(如数组、对象)”转换成一个字符串,方便你:
- 存进文件
- 放进数据库
- 在网络上传输(如 Cookie、Session、API)
不能直接把“数组”或“对象”这样的复杂数据,塞进一个只支持字符串的地方(比如 Cookie)。
为什么不能直接把数组或对象塞进只支持字符串的地方?
- 本质问题:类型不兼容
PHP 的数组、对象是内存中的复杂结构,比如:
- 数组有键名、键值、可能还嵌套其他数组
- 对象有属性、方法、类名等元信息
而像 Cookie、数据库字段、URL 参数,这些地方只能存储字符串类型(即文本)。
所以你不能直接把这样的“结构”放进去,比如:
1 | setcookie("user", ['name' => 'Tom']); // ❌ 错误!数组不能直接当 cookie 值 |

反序列化(Unserialization):
是序列化的逆操作——把字符串还原成原来的数据结构

serialize() //将对象转换成一个字符串
unserialize() //将字符串还原成一个对象
2、PHP-DEMO2-魔术方法触发规则
常见的php魔术方法
__construct():
- //当对象new的时候会自动调用
- 当new Test实例化对象 触发魔术方法_construct() 输出__construct()初始化
unset()是 PHP 的一个语言结构,用于销毁变量,也就是说,它会让一个变量“消失”。

__destruct()
- //当对象被销毁时会被自动调用
__destruct()是对象销毁时自动触发的魔术方法。你没有主动销毁对象$test,但当脚本结束时 PHP 自动回收内存,系统帮你调用了__destruct(),所以会输出那一行。

__sleep()
- : //serialize()序列化执行时被自动调用


__wakeup()
//unserialize()反序列化时会被自动调用
这个和__sleep()截然相反


__invoke()
- : //把对象当作函数调用时触发

__toString()
- : //把对象当作字符串使用时触发
原因详解:为什么 __toString() 会被自动调用?
- \1.
echo/ 字符串上下文要求是字符串类型 - 在 PHP 中,
echo是一个语言结构,它只能输出字符串。所以当你:echo $a - 其中
$a是一个对象,PHP 必须把它转换成字符串,否则就会报错。

__call():
- //调用某个方法,若方法存在,则调用;若不存在,则会去调用__call函数。


__get()
- 读取一个对象的属性时,若属性存在,则直接返回属性值;若不存在,则会调用__get函数


__ set()
魔术方法 设置一个对象的属性时, 若属性存在,则直接赋值;若不存在,则会调用__set函数。
__set():设置对象不存在的属性或无法访问(私有)的属性时调用
__set($name, $value) * 用来为私有成员属性设置的值 * 第一个参数为你要为设置值的属性名,第二个参数是要给属性设置的值,没有返回值。return isset($this->$content);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27


### __isset()
* __检测对象的某个属性是否存在时执行此函数。当对不可访问属性调用 isset() 或 empty() 时,__isset() 会被调用
* name没被调用的原因是因为name是私有属性
<img src="/img/image-20250527204233957.png" alt="image-20250527204233957" style="zoom:50%;" />

* 这里因为name是私有属性所以不可访问 并且不可访问属性还使用了isset()所以调用了__isset()魔术方法显示123
* **为什么echo empty($person->sex) 为1**
原因是:**重写了 `__isset()` 魔术方法** PHP 做了下面这些步骤:
1. 检查 `$person->sex` 能不能访问;
2. `sex` 是公共属性,所以可以访问,不走 `__isset()`;
3. 但出于一致性,PHP 会**调用 `__isset()` 方法**来判断属性是否存在;
4. 你的 `__isset()` 方法返回:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 0xMouise!






