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) {
}
}
问题点:
disconnect()方法检查$this->connected()connected()返回值可控- 但
__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()方法
利用链:
- 控制
$this->status使isRunning()返回true stop()调用proc_get_status()函数- 最终调用可控对象的
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);
}
}
进一步调用BehaviorRegistry的call()方法:
public function call($method, array $args = []) {
$object = $this->get($behavior);
return call_user_func_array([$object, $method], $args);
}
条件检查:
hasMethod():检查方法是否存在(方法名转为小写)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()方法调用链:
Shell->ConsoleIo- 最终输出可控
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);
}
结合BufferedStatement的fetch()方法:
public function fetch($type = 'num') {
if ($this->allFetched) {
return false;
}
return $this->statement->fetch($type);
}
利用条件:
$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框架的安全设计具有重要参考价值。