CTF Web PHP 反序列化漏洞完整学习笔记

发布时间:2026/6/25 19:03:58
CTF Web PHP 反序列化漏洞完整学习笔记 一、PHP 序列化与反序列化基础原理1. 通俗理解serialize () 序列化把数组、对象等复杂数据拆成标准化字符串用于存储、网络传输类似家具拆板打包快递。unserialize () 反序列化将序列化字符串还原为原始对象 / 数组类似收货后组装家具。2. 核心应用场景Session 会话存储、Redis/Memcached 缓存、跨服务 API 数据传输、数据库对象存储、消息队列异步任务。3. serialize () 序列化函数语法string serialize(mixed $value)仅不支持 resource 资源类型。基础类型序列化格式对照表 | 标识 | 类型 | 格式示例 | | ---- | ---- | ---- | |N|null|N;| |b | 布尔 | b:1;/b:0;| |i | 整型 | i:123;| |d | 浮点 | d:3.14;| |s | 普通字符串 | s:5:hello;| |S | 转义字符串 | S:5:he\6c\6co;| |a | 数组 | a: 元素数量:{键值对}| |O | 对象 | O: 类名字符长度:类名: 属性数量:{属性序列化内容}| |R/r | 引用 | R: 编号|对象序列化特殊规则序列化前优先执行__sleep()仅序列化该方法返回的属性属性访问修饰符会改变序列化字符串public直接写属性名s:4:nameprotected前缀\0*\0s:6:*proprivate前缀\0类名\0s:9:Testpri4. unserialize () 反序列化函数语法mixed unserialize(string $data, array $options [])PHP7 支持allowed_classes限制可反序列化类。失败场景序列化字符串格式错误、字符串长度不匹配、对应类未加载、语法缺失分号 / 括号。漏洞核心成因用户可控输入直接传入unserialize()可构造恶意字符串触发魔术方法执行危险操作。5. 入门靶场例题基础数组 / 对象序列化第一题直接反序列化 POST 数组构造指定 username、password 数组序列化串传入即可读取 flag第二题反序列化自定义 Person 对象实例化对象后序列化提交第三题包含 protected、private 私有属性序列化后必须 URL 编码提交否则空字符丢失导致解析失败。二、PHP 魔术方法反序列化漏洞核心利用点魔术方法以双下划线__开头满足特定条件自动调用是连接恶意输入与危险代码的桥梁。1. 生命周期类方法__construct()实例化 new 对象时触发反序列化不会调用__destruct()对象销毁、脚本执行结束自动触发反序列化后必触发最常用漏洞入口可执行文件删除、命令执行__sleep()序列化 serialize () 前执行筛选需要持久化的属性__wakeup()unserialize 反序列化完成后立刻触发常用来做安全校验存在经典绕过漏洞 CVE-2016-7124PHP7.4 新增__serialize()/__unserialize()优先级高于 sleep/wakeup。2. POP 链跳板常用魔术方法__toString()对象被当作字符串使用echo、字符串拼接、print触发多用于文件读取__invoke()对象像函数一样$obj()调用时触发可执行回调命令__call()调用对象不存在的实例方法触发__callStatic()调用不存在静态方法触发__get()读取私有 / 不存在属性触发__set()写入不可访问属性触发__isset()/__unset()对不可访问属性执行 isset、unset 操作触发。3. 魔术方法触发总表表格魔术方法反序列化时是否自动触发利用场景__construct否无__destruct是脚本结束漏洞入口命令 / 文件操作__wakeup是反序列化完成安全校验绕过__toString需主动字符串操作POP 链中间跳板__call/__get/__invoke需对应操作POP 链串联链路4. 魔术方法靶场例题第四题__destruct()动态调用函数private 属性 name 赋值 systemage 赋值命令对象销毁时执行system(命令)第五题同时存在__wakeup()重置 age、__toString()读取文件echo 输出对象触发文件读取第六题 CVE-2016-7124 __wakeup 绕过PHP5.6.25/7.0.10 以下版本修改序列化字符串中对象属性数量大于实际属性数即可跳过__wakeup 执行第七题 引用 绕过相等校验利用序列化 R 引用标记让两个私有属性指向同一内存绕过$name$age全等判断。三、Phar 反序列化无 unserialize 也能触发1. 原理Phar 是 PHP 归档文件文件元数据自动以序列化存储使用phar://协议访问文件时PHP 会自动解析元数据并执行反序列化无需代码中出现 unserialize 函数大幅扩大攻击面。2. Phar 文件四部分Stub存根必须以__HALT_COMPILER();结尾可伪装 GIF/JPG 图片 Manifest序列化元数据 文件内容 签名。3. 生成恶意 phar 文件条件php.ini 配置phar.readonly Off代码创建 Phar 对象设置恶意类实例为元数据至少添加一个文件内容可修改 Stub 伪装图片后缀绕过上传检测。4. 可触发 phar 反序列化的函数文件检测file_exists、文件读取file_get_contents、文件信息filesize、图像处理getimagesize、哈希函数md5_file、目录操作、复制重命名等绝大多数文件操作函数。5. phar:// 过滤绕过方案大小写混淆Phar://、URL 双重编码、协议嵌套php://filter/resourcephar://、文件后缀伪装图片、协议拼接绕过字符串匹配。四、反序列化漏洞形成三大必要条件入口可控用户可控数据直接传入 unserialize ()如 POST/GET 参数、Cookie、上传文件内容、数据库缓存存在利用 Gadget 类代码内包含魔术方法内部存在 system、file_get_contents、include 等危险操作类可加载反序列化时目标类已定义或自动加载可用。五、POP 链构造复杂反序列化核心考点1. POP 链概念单一类无法直达命令执行时串联多个类的魔术方法形成完整调用链路入口点__wakeup()/__destruct()反序列化最先触发跳板 Gadget__toString/__call/__get等中转魔术方法终点 Sink危险函数 system、eval、文件读取 / 包含2. 两种分析思路正向分析从反序列化入口出发顺着魔术方法调用链往下追踪至危险函数逆向分析先找到代码内危险函数反向寻找能触发该代码的魔术方法回溯到入口类。3. 常用 POP 链串联模式__destruct() - echo输出对象 - __toString() - 调用不存在方法 - __call() - 属性读取__get() - system/文件读取六、防御措施总结严格限制 unserialize 输入禁止用户可控数据直接反序列化PHP7 开启allowed_classes白名单只允许安全类反序列化类中__wakeup()做安全校验重置危险可控属性关闭 phar.readonly限制 phar 协议使用过滤文件操作函数中的 phar://、伪协议代码审计避免魔术方法内直接拼接、执行用户可控参数。