以迷宫类比PHP反序列化链
字数 1648 2025-08-11 08:36:00

PHP反序列化漏洞分析与利用:迷宫类比法

一、核心概念

PHP反序列化漏洞可以类比为一个迷宫:

  • 入口__destruct()__toString()方法
  • 路径__call、同名类、call_user_func_arraycall_user_func等方法
  • 出口call_user_func_arraycall_user_funceval$a($b,$c)等命令执行与文件写入点

二、反序列化漏洞基础

1. 成因

  • 反序列化时将字符串还原成类对象
  • 类被销毁时默认触发__destruct()析构方法
  • 类被当作字符串使用时执行__toString方法

2. 利用条件

  • 存在完全可控的反序列化点:unserialize(可控变量)
  • 存在文件操作函数且文件名可控:file_exists('phar://恶意文件')
  • 注意:PHP8中Phar的元信息不再自动反序列化

三、迷宫入口分析

1. 主要入口方法

  • __destruct():最佳入口,对象销毁时自动调用

    • 示例:Laravel中的PendingBroadcast
    class PendingBroadcast {
        protected $events;
        protected $event;
    
        public function __destruct() {
            $this->events->dispatch($this->event);
        }
    }
    
  • __toString():类被当作字符串时调用

    • 在WordPress的Guzzle、PHPExcel中有应用
  • __wakeup():执行unserialize()时首先调用

四、路径探索

1. 路径前提

  • 类之间存在包含关系
  • 框架中更容易实现(遵循composer规则)

2. 关键路径模式

  • 模式1$this->a->b()$temp = $this->a; $temp->b()

    • 要求:a可控,参数部分或全部可控
    • b不可控时:定义a为有__call的类
      public __call(string $name, array $arguments): mixed
      
    • b可控时:可定义a为任意类,b为该类方法
  • 模式2:使用call_user_func()call_user_func_array()

    • 适合二次或多次跳转

3. 方向控制

  • __construct():控制跳转方向

    • 初始化时可设置参数绕过中间关卡(如if判断)
  • 注意事项

    • 只能控制类或父类已定义的变量
    • 注意继承和访问修饰符(public/protected/private)
    • 父类private变量使用时需在构造时包含父类
    • __construct__destruct是类默认存在的

五、出口点

1. 常见出口

  • 命令执行

    • call_user_func()call_user_func_array()参数可控时
    • 形如$a($b,$c)$a$b可控
      system('id', $c);
      
    • eval($a)
  • 文件操作

    • 文件写入函数
    • 文件包含函数

六、实例分析

1. 简单示例代码

class lemon {
    protected $ClassObj;
    function __construct() {
        $this->ClassObj = new normal();
    }
    function __destruct() {
        $this->ClassObj->action();
    }
}

class normal {
    function action() {
        echo "hello";
    }
}

class evil {
    private $data;
    function action() {
        eval($this->data);
    }
}

unserialize($_GET['d']);

2. 漏洞分析

  1. 入口lemon::__destruct()
  2. 路径$this->ClassObj->action()
    • 原指向normal::action()
    • 通过控制ClassObj指向evil::action()
  3. 出口eval($this->data)

3. 利用构造

class lemon {
    protected $ClassObj;
    function __construct() {
        $this->ClassObj = new evil(); // 控制跳转方向
    }
}

class evil {
    private $data = "phpinfo();"; // 控制执行代码
}

echo urlencode(serialize(new lemon())); // 编码防止乱码

七、高级技巧

1. 绕过__wakeup

  • 通过修改序列化字符串的对象计数
  • 示例:O:4:"test":1:{s:1:"a";s:3:"aaa";}改为O:4:"test":2:{s:1:"a";s:3:"aaa";}

2. 特殊反序列化方式

  • phar反序列化:通过phar://协议触发
  • session反序列化:控制session数据

3. 访问修饰符处理

  • private和protected属性序列化时包含%00
  • 需要正确编码处理

八、防御建议

  1. 避免反序列化用户可控数据
  2. 使用__wakeup()进行安全检查
  3. 对敏感操作添加权限验证
  4. 及时更新PHP版本(特别是PHP8对Phar的改进)

通过这种迷宫类比法,可以系统性地分析PHP反序列化漏洞,明确寻找入口、路径和出口的策略,提高漏洞挖掘和利用的效率。

PHP反序列化漏洞分析与利用:迷宫类比法 一、核心概念 PHP反序列化漏洞可以类比为一个迷宫: 入口 : __destruct() 与 __toString() 方法 路径 : __call 、同名类、 call_user_func_array 、 call_user_func 等方法 出口 : call_user_func_array 、 call_user_func 、 eval 、 $a($b,$c) 等命令执行与文件写入点 二、反序列化漏洞基础 1. 成因 反序列化时将字符串还原成类对象 类被销毁时默认触发 __destruct() 析构方法 类被当作字符串使用时执行 __toString 方法 2. 利用条件 存在完全可控的反序列化点: unserialize(可控变量) 存在文件操作函数且文件名可控: file_exists('phar://恶意文件') 注意 :PHP8中Phar的元信息不再自动反序列化 三、迷宫入口分析 1. 主要入口方法 __destruct() :最佳入口,对象销毁时自动调用 示例:Laravel中的 PendingBroadcast 类 __toString() :类被当作字符串时调用 在WordPress的Guzzle、PHPExcel中有应用 __wakeup() :执行 unserialize() 时首先调用 四、路径探索 1. 路径前提 类之间存在包含关系 框架中更容易实现(遵循composer规则) 2. 关键路径模式 模式1 : $this->a->b() 或 $temp = $this->a; $temp->b() 要求: a 可控,参数部分或全部可控 b 不可控时:定义 a 为有 __call 的类 b 可控时:可定义 a 为任意类, b 为该类方法 模式2 :使用 call_user_func() 或 call_user_func_array() 适合二次或多次跳转 3. 方向控制 __construct() :控制跳转方向 初始化时可设置参数绕过中间关卡(如if判断) 注意事项 : 只能控制类或父类已定义的变量 注意继承和访问修饰符(public/protected/private) 父类private变量使用时需在构造时包含父类 __construct 和 __destruct 是类默认存在的 五、出口点 1. 常见出口 命令执行 : call_user_func() 和 call_user_func_array() 参数可控时 形如 $a($b,$c) 且 $a 、 $b 可控 eval($a) 文件操作 : 文件写入函数 文件包含函数 六、实例分析 1. 简单示例代码 2. 漏洞分析 入口 : lemon::__destruct() 路径 : $this->ClassObj->action() 原指向 normal::action() 通过控制 ClassObj 指向 evil::action() 出口 : eval($this->data) 3. 利用构造 七、高级技巧 1. 绕过 __wakeup 通过修改序列化字符串的对象计数 示例: O:4:"test":1:{s:1:"a";s:3:"aaa";} 改为 O:4:"test":2:{s:1:"a";s:3:"aaa";} 2. 特殊反序列化方式 phar反序列化 :通过 phar:// 协议触发 session反序列化 :控制session数据 3. 访问修饰符处理 private和protected属性序列化时包含 %00 需要正确编码处理 八、防御建议 避免反序列化用户可控数据 使用 __wakeup() 进行安全检查 对敏感操作添加权限验证 及时更新PHP版本(特别是PHP8对Phar的改进) 通过这种迷宫类比法,可以系统性地分析PHP反序列化漏洞,明确寻找入口、路径和出口的策略,提高漏洞挖掘和利用的效率。