CakePHP反序列化POP链挖掘
字数 1729 2025-08-05 00:15:18

CakePHP反序列化POP链挖掘技术分析

前言

本文详细分析CakePHP框架中的反序列化POP(Property-Oriented Programming)链挖掘技术,涵盖3.x和4.x版本的利用方法。通过深入研究PHP函数调用特性和CakePHP框架内部机制,揭示多个可利用的反序列化漏洞点。

PHP函数调用特性

有参无参调用特性

PHP版本对函数参数调用的处理存在差异:

class a{
    public function aaa($a){
        echo 'aaa';
    }
    public function cccc(){
        echo 'cccc';
    }
}
$a = new a();
$a->aaa();    // 有参函数无参调用
$a->cccc(123,456);  // 无参函数有参调用

版本差异:

  • PHP ≤ 7.0.33:有参函数可以无参调用,仅产生Warning
  • PHP ≥ 7.1.0:有参函数无参调用会直接报Fatal error
  • 无参函数始终可以有参调用

反序列化入口点分析

第一潜在入口:SmtpTransport类

路径:vendor\cakephp\cakephp\src\Mailer\Transport\SmtpTransport.php

public function __destruct() {
    try {
        $this->disconnect();
    } catch (Throwable $e) {
    }
}

问题点:

  1. disconnect()方法检查$this->connected()
  2. connected()返回值可控
  3. __wakeup方法会重置$_socket为空,导致利用失败

该漏洞在3.7.7和4.x初始版本已修复(CVE-2019-11458)

第二潜在入口:Process类

路径:vendor\symfony\process\Process.php

public function __destruct() {
    if ($this->isRunning()) {
        $this->stop(0);
    }
}

版本限制:

  • __wakeup限制的版本:
    • 4.x: < 4.2.3
    • 3.x: < 3.9.6

老版本(4.x < 4.1.6, 3.x < 3.9.4)的__destruct直接调用stop()方法

利用链:

  1. 控制$this->status使isRunning()返回true
  2. stop()调用proc_get_status()函数
  3. 最终调用可控对象的readAndWrite()方法,触发__call

3.x版本利用链(以3.9.6为例)

__call方法利用

路径:vendor\cakephp\cakephp\src\ORM\Table.php

public function __call($method, $args) {
    if ($this->behaviors()->hasMethod($method)) {
        return $this->behaviors()->call($method, $args);
    }
}

进一步调用BehaviorRegistrycall()方法:

public function call($method, array $args = []) {
    $object = $this->get($behavior);
    return call_user_func_array([$object, $method], $args);
}

条件检查:

  1. hasMethod():检查方法是否存在(方法名转为小写)
  2. has():在父类ObjectRegistry中实现,可控

寻找可利用方法

路径:vendor\cakephp\cakephp\src\Shell\ServerShell.php

public function main() {
    $command = escapeshellcmd(PHP_BINARY) . ' -S ' . $this->host . ':' . $this->port;
    system($command);
}

命令注入点:

  • 通过分号(;)实现多命令执行(Linux)
  • 通过&实现多命令执行(Windows)
  • 需要确保out()方法正常执行

out()方法调用链:

  1. Shell -> ConsoleIo
  2. 最终输出可控

4.x版本利用链(以4.1.6为例)

ServerShell替代方案

4.x版本移除了ServerShell类,替代方案使用CallbackStatement类:

路径:vendor\cakephp\cakephp\src\Database\Statement\CallbackStatement.php

public function __call($method, $args) {
    $callback = [$this->callback, $method];
    return call_user_func_array($callback, $args);
}

结合BufferedStatementfetch()方法:

public function fetch($type = 'num') {
    if ($this->allFetched) {
        return false;
    }
    return $this->statement->fetch($type);
}

利用条件:

  1. $this->allFetched为false
  2. $this->statement可控
  3. fetch()参数为之前__call传入的bool值

总结

完整利用链

  1. 入口点Process类的__destruct
  2. 中间跳转:触发可控对象的__call方法
  3. 3.x最终利用ServerShellmain()方法实现命令执行
  4. 4.x最终利用CallbackStatement__call动态调用危险函数

版本影响

  • 3.x版本:影响< 3.9.6版本
  • 4.x版本:影响< 4.2.3版本

防御建议

  1. 及时升级到最新版本
  2. 避免反序列化不可信数据
  3. __wakeup__destruct方法进行安全审查
  4. 限制危险函数的使用

该技术展示了框架内部组件间复杂的交互关系如何被利用来构建攻击链,对PHP框架的安全设计具有重要参考价值。

CakePHP反序列化POP链挖掘技术分析 前言 本文详细分析CakePHP框架中的反序列化POP(Property-Oriented Programming)链挖掘技术,涵盖3.x和4.x版本的利用方法。通过深入研究PHP函数调用特性和CakePHP框架内部机制,揭示多个可利用的反序列化漏洞点。 PHP函数调用特性 有参无参调用特性 PHP版本对函数参数调用的处理存在差异: 版本差异: PHP ≤ 7.0.33 :有参函数可以无参调用,仅产生Warning PHP ≥ 7.1.0 :有参函数无参调用会直接报Fatal error 无参函数始终可以有参调用 反序列化入口点分析 第一潜在入口:SmtpTransport类 路径: vendor\cakephp\cakephp\src\Mailer\Transport\SmtpTransport.php 问题点: disconnect() 方法检查 $this->connected() connected() 返回值可控 但 __wakeup 方法会重置 $_socket 为空,导致利用失败 该漏洞在3.7.7和4.x初始版本已修复(CVE-2019-11458) 第二潜在入口:Process类 路径: vendor\symfony\process\Process.php 版本限制: 无 __wakeup 限制的版本: 4.x: < 4.2.3 3.x: < 3.9.6 老版本(4.x < 4.1.6, 3.x < 3.9.4)的 __destruct 直接调用 stop() 方法 利用链: 控制 $this->status 使 isRunning() 返回true stop() 调用 proc_get_status() 函数 最终调用可控对象的 readAndWrite() 方法,触发 __call 3.x版本利用链(以3.9.6为例) __ call方法利用 路径: vendor\cakephp\cakephp\src\ORM\Table.php 进一步调用 BehaviorRegistry 的 call() 方法: 条件检查: hasMethod() :检查方法是否存在(方法名转为小写) has() :在父类 ObjectRegistry 中实现,可控 寻找可利用方法 路径: vendor\cakephp\cakephp\src\Shell\ServerShell.php 命令注入点: 通过分号(;)实现多命令执行(Linux) 通过&实现多命令执行(Windows) 需要确保 out() 方法正常执行 out() 方法调用链: Shell -> ConsoleIo 最终输出可控 4.x版本利用链(以4.1.6为例) ServerShell替代方案 4.x版本移除了 ServerShell 类,替代方案使用 CallbackStatement 类: 路径: vendor\cakephp\cakephp\src\Database\Statement\CallbackStatement.php 结合 BufferedStatement 的 fetch() 方法: 利用条件: $this->allFetched 为false $this->statement 可控 fetch() 参数为之前 __call 传入的bool值 总结 完整利用链 入口点 : Process 类的 __destruct 中间跳转 :触发可控对象的 __call 方法 3.x最终利用 : ServerShell 的 main() 方法实现命令执行 4.x最终利用 : CallbackStatement 的 __call 动态调用危险函数 版本影响 3.x版本 :影响 < 3.9.6版本 4.x版本 :影响 < 4.2.3版本 防御建议 及时升级到最新版本 避免反序列化不可信数据 对 __wakeup 和 __destruct 方法进行安全审查 限制危险函数的使用 该技术展示了框架内部组件间复杂的交互关系如何被利用来构建攻击链,对PHP框架的安全设计具有重要参考价值。