PHP反序列化的原理

发布时间:2021-09-03 23:27:04 作者:chen
来源:亿速云 阅读:253
# PHP反序列化的原理

## 1. 序列化与反序列化基础概念

### 1.1 什么是序列化

序列化(Serialization)是将数据结构或对象状态转换为可存储或可传输格式的过程。在PHP中,序列化后的数据是一个包含字节流的字符串,它可以保存对象的属性、类型和结构信息。

```php
class User {
    public $username = 'admin';
    protected $password = '123456';
    private $salt = 'abc';
}

$user = new User();
echo serialize($user);
// 输出:O:4:"User":3:{s:8:"username";s:5:"admin";s:11:"*password";s:6:"123456";s:10:"Usersalt";s:3:"abc";}

1.2 什么是反序列化

反序列化(Unserialization)是将序列化后的字符串还原为原始数据结构或对象的过程。这是序列化的逆操作。

$serialized = 'O:4:"User":3:{...}';
$unserialized = unserialize($serialized);
var_dump($unserialized);

2. PHP序列化格式详解

PHP序列化字符串包含以下关键部分:

3. PHP反序列化执行流程

3.1 基本处理过程

  1. 词法分析:将序列化字符串分解为token
  2. 语法分析:根据token构建语法树
  3. 对象创建:根据类名实例化对象
  4. 属性赋值:按照顺序为对象属性赋值

3.2 关键函数分析

unserialize()函数内部实现主要步骤:

  1. 调用php_var_unserialize()开始解析
  2. 根据第一个字符判断数据类型
  3. 对于对象类型:
    • 调用unserialize_obj()处理
    • 通过zend_lookup_class()查找类定义
    • 调用object_common1()初始化对象
    • 处理魔术方法__wakeup()

4. 反序列化中的魔术方法

PHP提供了一些在反序列化过程中自动调用的魔术方法:

4.1 __wakeup()

在对象反序列化完成后立即调用:

class User {
    public function __wakeup() {
        echo "Wake up called!\n";
    }
}

4.2 __destruct()

当对象被销毁时调用:

class User {
    public function __destruct() {
        echo "Destructor called!\n";
    }
}

4.3 __sleep()

在序列化时调用,可指定需要序列化的属性:

class User {
    public function __sleep() {
        return ['username']; // 只序列化username属性
    }
}

5. 反序列化漏洞原理

5.1 漏洞产生条件

  1. 存在可被控制的序列化数据输入
  2. 类中实现了有危险操作的魔术方法
  3. 存在可被利用的类方法(POP链)

5.2 典型攻击场景

class VulnerableClass {
    public $file;
    
    public function __destruct() {
        if(file_exists($this->file)) {
            unlink($this->file);
        }
    }
}

// 攻击者可构造恶意序列化数据
$payload = 'O:15:"VulnerableClass":1:{s:4:"file";s:9:"important.txt";}';
unserialize($payload);

5.3 属性注入攻击

通过修改序列化字符串中的属性数量,可以绕过__wakeup()的执行:

// 原始序列化数据
O:4:"User":1:{s:8:"username";s:5:"admin";}

// 修改属性数量后的payload
O:4:"User":100:{s:8:"username";s:5:"admin";}

6. 反序列化利用技术(POP链)

6.1 什么是POP链

Property-Oriented Programming(面向属性编程)通过组合不同类的魔术方法和普通方法,形成可执行任意代码的调用链。

6.2 构建POP链示例

class Gadget1 {
    public $handle;
    public function __destruct() {
        $this->handle->close();
    }
}

class Gadget2 {
    public $filename;
    public function close() {
        eval(file_get_contents($this->filename));
    }
}

// 构造恶意序列化数据
$payload = serialize([
    new Gadget1(),
    new Gadget2()
]);

7. 防御措施

7.1 输入验证

7.2 安全配置

unserialize($data, ['allowed_classes' => ['SafeClass']]);

7.3 代码层面防护

  1. 避免在魔术方法中执行危险操作
  2. 对反序列化后的对象进行严格验证
  3. 使用__sleep()限制序列化的属性

8. 实际案例分析

8.1 Typecho反序列化漏洞(CVE-2018-18753)

漏洞位于install.php中,通过反序列化Referer头实现RCE:

$config = unserialize(base64_decode(Typecho_Cookie::get('__typecho_config')));

8.2 Laravel反序列化RCE(CVE-2021-3129)

利用Ignition组件的反序列化漏洞,通过精心构造的日志文件实现远程代码执行。

9. 检测与审计方法

9.1 代码审计要点

  1. 查找项目中所有的unserialize()调用
  2. 检查是否对输入数据进行了过滤
  3. 分析可用的魔术方法和普通方法

9.2 自动化工具

10. 总结

PHP反序列化是一个强大的功能,但也带来了严重的安全风险。理解其底层原理对于开发安全的应用程序至关重要。开发者应当:

  1. 尽量避免反序列化用户输入
  2. 及时更新框架和依赖库
  3. 实施最小权限原则
  4. 定期进行安全审计

通过正确理解和使用反序列化机制,可以在享受其便利性的同时有效降低安全风险。 “`

这篇文章共计约2300字,详细介绍了PHP反序列化的核心原理、安全风险及防御措施,采用Markdown格式编写,包含代码示例和结构化标题。内容涵盖从基础概念到高级利用技术的完整知识体系。

推荐阅读:
  1. java反序列化原理-Demo(二)
  2. java反序列化原理-Demo(一)

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

php

上一篇:如何编译安装以及使用msgpack-php

下一篇:MySQL中的隐藏列的具体查看方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》